Most "AI tutor" products are just a chatbot wearing a graduation cap — you ask a question, it answers, nothing persists, nothing is ever verified. You can feel like you learned something without ever being tested on whether you did. claratto starts from a different premise: you don't know something until you've proven it, and the app's whole architecture is built to enforce that honestly instead of just claiming it.
The product pitch, distilled: "Come in empty. Leave full." The user is a brain — literally, a visual 3D graph that starts blank and grows one node at a time, but only when a topic is actually proven, not just discussed.
The core loop
A user asks about any topic, and the AI teaches it — real depth, chunked, checked for understanding as it goes. Then comes a quick test, not a "got it" button but an actual quiz. The score gates storage, decided server-side and never by the client: 75% or above adds a bright "solid" node with connections to related topics, 45–74% adds a faint "needs review" node, and anything below 45% stores nothing at all. On a pass, the user watches their brain light up live.
That score-gate is the single most important design decision in the whole product. It's tempting, and common in this space, to just mark something "learned" the moment a chat ends. claratto refuses to do that — the brain only grows by testing, which means the visualization on screen is never a vanity metric, it's an honest record.
Architecture
Five layers, with a strict one-way trust boundary — the browser is untrusted, full stop. The client (Next.js, in the browser) renders screens and reads its own brain data in real time via Firestore listeners, but never calls the AI directly and never writes memory. API routes are the actual trust boundary: every route verifies the Firebase ID token first, rate-limits, validates input with Zod, then calls into the service layer — the server decides score-to-strength and writes via the Firebase Admin SDK, so a client can't forge a passing score even if it tries.
Below that sits the tutor service — the actual product logic: the teaching engine, the syllabus parser, the credit/plan policy layer, the teacher-brain memory writer, all server-only. Models are Gemini via the Vercel AI SDK for teaching, parsing, and structured generation, and Sarvam for the voice-interview feature, behind a thin, provider-agnostic adapter — { model, prompt, schema? } → text | validated object — that knows nothing about teachers, plans, or the brain. That separation is what let me add the interview feature on a completely different provider without touching the teaching code at all. Data lives in Firestore, with no separate vector DB — Firestore's native vector index (findNearest) does semantic retrieval directly on the brain nodes, so there's no separate infrastructure to run just for "find topics related to this one."
The two memories that never mix
This is the part I'd point to as the actual engineering idea, not just plumbing. The brain (memories/*) is what the user has proven — grown only by a passed test, uncapped, queried selectively (only the current topic plus its direct connections via vector search), and never touched by anything except the scoring route. App memory, or the teacher-brain (teacherBrain/*), is what's been taught, independent of whether it was tested — it updates after every single exchange in a session, when a small background LLM call extracts zero to three "covered points" and, more recently, specific misconceptions the student showed, so that coming back to a topic three weeks later means the tutor picks up where it left off instead of re-teaching from zero, without ever touching the brain.
Keeping these separate is a deliberate constraint I never bend: a chat teaching you something and a test proving you know it are epistemically different events, and conflating them is exactly how most "AI learning" products end up being trust-me-bro software.
The teaching protocol — the part I iterated on the most
The system prompt driving the tutor went through several real redesigns while building this. The first version was a rigid, one-step-per-message Socratic protocol — hook analogy, wait, probe, wait, core idea, wait. Good in theory, but it defaulted to childish toy-box analogies even for advanced professional topics, and it paced everything the same way regardless of what was actually asked. The next pass made it audience-aware and uncapped in depth: it stopped assuming every student is a child needing a fable, so a technical topic gets real terminology and real code instead of a metaphor standing in for the real thing.
The final shape is chunked, interactive delivery. Working memory holds roughly 4±1 new chunks before comprehension degrades, so instead of one giant wall of text or one shallow teaser, the tutor delivers the topic in genuine, complete sub-parts — each one deep, none of them childish — with a real comprehension check between them. Only once the topic's core content is fully covered does it move into a reinforcement loop: confidence-calibrated recall checkpoints, Feynman teach-back, a worked-example-gated struggle problem (novices get a worked example first — desirable difficulty only helps once you have a basic schema), interleaving, and a spaced-repetition flashcard kit. An invisible completion marker the model emits only when it reaches the true end of that loop is used server-side to fire a "ready to test?" nudge at the right moment, instead of guessing from a message count.
I mention this in this much detail because I think it's the most defensible technical decision in the project: the prompt isn't a one-shot instruction, it's a state machine the model re-derives from the conversation transcript every single turn, with no external flag telling it what phase it's in.
Brain visualization
Proven topics render as glowing nodes on a Three.js 3D brain model. Node placement isn't random — an AI classification call buckets each topic into one of five domain types (mechanism, conceptual, factual, skill, emotional — the same taxonomy the teaching protocol itself reasons with, so there's exactly one classification system in the app, not two that can drift apart), and each bucket gets its own angular wedge on the sphere. Classifications are cached client-side and never re-fetched for a topic once resolved.
Monetization
Live and monetized: Razorpay subscriptions with currency-aware checkout, a credit-based usage system where every AI call is token-costed and debited transactionally, and a free/paid model-tier split so heavier reasoning models are gated by plan rather than exposed unconditionally.
Tech stack
Next.js 16 App Router with server components by default and "use client" pushed down to the smallest interactive leaf. Firebase — Firestore with its native vector index, Firebase Auth for identity, Admin SDK for all writes. Gemini via the Vercel AI SDK for teaching, syllabus parsing, and structured generation, with Sarvam handling the voice models for the mock-interview feature. Three.js and React Three Fiber for the 3D brain. Razorpay for subscriptions and credit packs. Zod validating every route input and every AI output before it's trusted.
What I'd flag as the real challenges
Prompt-as-state-machine reliability is the sharpest edge. The teaching protocol has no explicit state stored anywhere — the model infers which phase it's in by re-reading the transcript every turn. That's elegant when it works and silently wrong when it doesn't, and the only way I trusted it was by scripting direct calls against the live model rather than trusting it by inspection.
The moat is a discipline, not a lock. Nothing technically stops a future version of me from writing a code path that upserts a brain node outside /api/score. The separation between "taught" and "proven" only holds because it's enforced as a standing rule across every change, not because the schema makes it impossible.
Cost is structural, not incidental. The teacher-brain's per-round summarization means every single teaching exchange triggers two model calls, not one. That's a deliberate trade for the cross-session memory it buys — but it's real money, tracked in the credit system from day one rather than bolted on later.
— Saurabh