Problem Statement

I revise by explaining things out loud to nobody. It works, because explaining forces you to find the holes. The problem is nobody is listening, so nothing tells you where the holes were.

Every AI study tool I have used has the same flaw. It already knows the material. So when my explanation is vague, it fills the gap for me and I never find out I was vague. I finish the session feeling like I understood it, with no evidence either way.

Solution Overview

Star Pupil gives you a student instead. Pip knows nothing about your topic and believes exactly what you tell him, including the things you explain badly.

When you enroll, before you type anything, an examiner writes a map of the subject and a six question exam sealed against it. You teach by typing. Every sentence becomes a belief in Pip's head, right or wrong. Then he sits that sealed paper alone and answers only from what you taught him.

He fails, usually. The report card shows you why, and every lost mark points at a sentence you wrote.

Key Features

Everything is a view onto one structure. After each message, an extraction pass writes down what a real student would now believe. Not what is true. What your wording licenses.

interface Belief {
  statement: string;     // what Pip now believes
  status: "correct" | "wrong" | "fuzzy";
  quote: string;         // your exact words that produced it
  derivedFrom: number[]; // beliefs this was reasoned from
  correction?: string;   // what you could have said instead
}
Feature What it does
Live misconceptions Say something sloppy and the concept turns red while you watch, quoting your sentence as the source
Sealed paper Syllabus, questions and mark scheme fingerprinted with SHA-256 in your browser at enrollment, recomputed on the report card
Frontier map You only see what you could teach next. Show the full syllabus and the lesson becomes a checklist
Dispute Tell Pip he never heard you say that. He reads your sentence back and keeps his note unless the quote really does not support it
Blank enforcement If Pip says the lesson never covered something, the mark is zero even when his guess is right
Root tracing A lost mark walks the derivation chain back to the first wrong belief, not the nearest one
Two scores Coverage and accuracy separately. A confident 6/6 on half the topic is a different problem from a shaky 6/6 on all of it

Technologies Used

Next.js 16, TypeScript, Tailwind, shadcn/ui. The map is React Flow over a dagre layout. The exam streams as NDJSON so the stages tick live. Web Crypto computes the seal in the browser. Canvas draws the downloadable report card, with no image export library.

The model layer is a ladder ordered by free tier quota rather than model quality, because the project runs on $0:

Rung Free quota Why here
Gemini 3.1 Flash Lite 500/day Leads. Enforces a response schema
Groq gpt-oss-120b 1,000/day Separate bucket, real depth
Groq llama-3.3-70b 1,000/day Separate bucket again
Gemini 3 Flash 20/day Best model here, so it goes last

Putting the best model first would be wrong. On a free key it is almost always the rung that is already spent. Every (model, key) pair is its own step, so a 429 rotates keys before dropping to a weaker model. Calls are bounded twice, 8 seconds per attempt and 45 seconds per ladder, because Vercel kills the function at 60 and returns an HTML page that the frontend cannot parse.

No accounts, no server state, no database. The lesson lives in your browser.

Target Users

Students who already revise by explaining out loud and want to know where the holes are. Anyone rehearsing a presentation against a listener who cannot fill in their gaps. Tutors who want to show a student the difference between a confident explanation and a correct one.

Challenges I ran into

The exam used to be written after the lesson, and it was fed the concepts that came out shaky. It demoed beautifully. The exam always found the trap I planted.

Then I watched someone else use it and they said, out loud, "well of course it caught that, it read what I taught."

They were right. An exam written after the lesson, aimed at the lesson's weak spots, is a mirror. Every wrong answer I had been proud of was unfalsifiable.

So I moved the paper to enrollment and sealed it so you can check it did not move. This cost me the good demo. The exam now asks about things you never touched, and it does that often. It turned out to be the better product, because those questions produce Pip's confessions, and that is where coverage as a separate score came from.

What I learned

A prompt is not a guarantee.

I asked the grader to mark confessed gaps as blank, and it mostly did. Then I ran the same exam across different models. One of them confessed the gap, then guessed the right answer out of its own knowledge, and the grader handed it the mark. The score had stopped measuring my teaching and started measuring what the model already knew.

The fix is four lines and it runs after the model has spoken:

const confessed = answers[i]?.confessed && !answers[i]?.usedBeliefIds?.length;
if (confessed && g.verdict !== "blank") {
  return { verdict: "blank", graderVerdict: g.verdict, culpritBeliefId: null };
}

The guess still prints on the report card, greyed out, worth nothing. Rules you actually need get enforced in code, after the model has spoken, or they are not rules.

Built With

Share this project:

Updates