About the Project
The problem that inspired us
Today's AI coding assistants are incredibly good at generating code. That is also part of the problem.
When an assistant immediately produces a complete solution, developers can skip the difficult reasoning that actually builds expertise: understanding memory boundaries, tracing runtime behavior, handling edge cases, and debugging failures. We call this copy-paste amnesia. The code works, but the developer may not be able to explain why.
There is a second problem: context amnesia. A developer might spend hours struggling with recursion today, only for a new chat tomorrow to treat them like a complete beginner again. Most coding assistants optimize for solving the immediate task, not for tracking what the developer has learned over time.
We built SocraticPair to explore a different relationship between developers and AI: an AI pair-programming partner that guides you toward the solution instead of immediately writing it for you.
What SocraticPair does
SocraticPair adapts its behavior to the situation.
In Apprentice Mode, the AI acts as a Socratic teacher. Instead of dumping a solution into the editor, it uses an adaptive three-level hint ladder:
- Observation: identifies where to look without revealing the solution.
- Skeleton: provides structured ghost-text with targeted
TODOs. - Full explanation: reveals the implementation and analyzes its complexity when the developer explicitly escalates or gives up.
The hints are integrated directly into the Monaco editor using view zones, ghost text, and a side-by-side diff editor. The system avoids destructively replacing the developer's code, preserving their editing and undo history.
In Pair Mode, SocraticPair becomes a more traditional collaborative programming partner that can discuss tradeoffs and answer direct questions.
In Firefighting Mode, learning friction disappears. During an outage or deadline, the system provides a direct patch so the developer can ship the fix. However, the shortcut is recorded as Learning Debt, allowing SocraticPair to revisit the underlying concept later.
How we built it
Our architecture separates the interactive experience from long-running learning and memory work.
The frontend is built with Next.js and deployed on Vercel. It communicates with a backend gateway running on Google Cloud Run using Server-Sent Events (SSE). The streaming path allows SocraticPair to return hints incrementally without blocking on memory processing.
We designed the system around three main contracts:
- Frontend → Gateway: sends the active code context, cursor location, mode, code changes, and test results.
- Gateway → Memory Worker: completed turns are pushed into a background task queue.
- Memory Worker → Firestore: the worker updates a persistent Concept DAG representing the developer's knowledge.
For code execution, SocraticPair uses a dual-tier strategy. Simple Python code runs locally through Pyodide WebAssembly, giving near-instant test execution without server latency. Code requiring native dependencies or network-capable libraries is routed to a more isolated server-side sandbox design.
The learning system models concepts as a directed acyclic graph. For example, understanding recursion base cases can be a prerequisite for BST insertion and tree traversal. When a developer struggles with a higher-level concept, SocraticPair can trace backward through prerequisites instead of repeatedly explaining the same symptom.
Each concept maintains a probabilistic mastery estimate using a Beta-distribution-based knowledge model. Evidence decays over time so old successes gradually become less influential, reflecting the fact that people forget concepts they do not practice. The model also accounts for slip and guess probabilities so a single typo does not dramatically change a developer's estimated understanding.
The most interesting technical challenge
One of the biggest challenges was preventing the AI from accidentally defeating the purpose of the product.
Even when prompted to provide a small hint, a language model may decide that the "helpful" response is to generate the entire solution. During testing, this happened with our own Level 1 and Level 2 hints.
That led us to build a solution leak guard designed to prevent lower-level hints from exposing a complete implementation. This also exposed a fundamental tension with token streaming: if tokens are streamed immediately, the system may not know a response contains too much solution detail until part of that response has already reached the user.
This became one of our biggest lessons from building the project: streaming speed and pedagogical safety can be competing requirements. A fast system is not automatically a safe teaching system.
We also encountered real-world infrastructure challenges. Our original streaming approach using the agent framework encountered telemetry and context-variable failures, so we changed the fast path to stream directly from the model client while preserving the rest of the agent architecture.
Another challenge was latency. Our initial design targets were ambitious, but real model time-to-first-token was significantly slower than our ideal specification. Rather than treating the architecture diagram as reality, we learned to distinguish between design targets and measured production behavior.
Some planned background memory infrastructure also remained incomplete at submission time. The Concept DAG and knowledge-tracing logic exist as tested code, but not every intended model integration was deployed. We chose to document that honestly rather than present design assumptions as production measurements.
What we learned
The project taught us that building an AI product is not just about connecting a model to an interface.
We learned about:
- Designing asynchronous architectures where memory writes never block interactive responses.
- Streaming AI responses safely using SSE.
- Sandboxing untrusted code and thinking about infrastructure-level threats such as metadata access and SSRF.
- Building idempotent background processing so task retries do not corrupt user knowledge scores.
- Modeling learning as a graph instead of a collection of isolated chat histories.
- The practical difference between a promising architecture specification and a system that has actually been measured under real conditions.
Most importantly, we learned that the behavior of the AI itself must be treated as a system design problem. A model naturally optimized to provide answers can conflict with a product designed to help users learn.
Why this matters
We believe AI coding tools should not force a choice between productivity and learning.
Sometimes developers need guidance. Sometimes they need a collaborator. Sometimes production is broken and they simply need the patch.
SocraticPair tries to recognize those different contexts and adapt accordingly. It can teach when learning matters, collaborate when reasoning matters, and remove friction when shipping matters.
The long-term goal is simple: turn AI from an answer generator into a partner that helps developers build knowledge that remains after the chat window closes.
Built With
- bayesian-knowledge-tracing
- docker
- firestore
- gemini
- gemini-api
- github
- google-adk
- google-cloud
- google-cloud-run
- google-cloud-tasks
- gvisor
- language-server-protocol
- monaco-editor
- next.js
- pyodide
- pyright
- python
- react
- redis
- server-sent-events
- typescript
- vercel
- vertex-ai
- webassembly
Log in or sign up for Devpost to join the conversation.