Final version. The prototype stopped after review round 11, at the owner's call: the councils stayed at 7-8 of 10, short of the 9/10 bar, and the next step is a structural change (below), not another fix round.

Prototype · ONC2-8580 · staging data and staging QA accounts only · not shipped · api 9804566b (api#1438), app c1c844b4c (#2659), both draft PRs, not for merge

The tutor invites you in, on Home

When a learner opens Home, their course's tutor (Rezzy for the medical courses, Savvy for CFA and CPA, Casey for LSAT and the Bar) opens with one short message about what the learner did last, and one or two things it can do about it right now: a quiz on the exact questions they missed, their due cards, the lesson they should read next, or a question they can answer with a tap. Each tap lands where it says: a quiz already built, a screen, or a chat that starts from the card.

Code decides what is possible and true; one model call decides what is worth saying today and says it in the tutor's voice; code checks the result before the learner sees it.

How it works, end to end

SnapshotSQL, one course Offersreal ids, one count Composeone model call Validateretry once, fallback Cachelearner, course, scope Card on Homecatalog components Actresolves the tap Quiz on exact questions Lesson, cards, game Chat seeded with the card
  1. Snapshot. SQL reads only the active course (and its selected exams): recent sets and their misses, lessons read, due and forgotten cards, readiness trends, exam date, rhythm, onboarding and the tutor's memory notes.
  2. Offers. Code turns the snapshot into things the app can run today, each with real ids and one count used by its label, its facts and its target.
  3. Compose. One structured call (Gemini 3.5 Flash Lite) picks one or two offers and writes the message, buttons, chips and at most one block.
  4. Validate. Every id is an offer; every number belongs to an offer the card uses; no other course's exam or tutor; the rules the model breaks most. A failure retries once with fixes, then falls back to a card built from the rules.
  5. Cache. Stored per learner, course and exam scope with a fingerprint of the data; an unchanged learner gets the stored card in ~0.1 s.
  6. Act. A tap goes to the server, which resolves the offer on the stored card (a quiz template from the exact question ids, a route, or a chat whose first bubble is the stored message and whose first turn follows the offer's plan).

Component catalog

The model picks components by reference; the app draws them from design-system parts. It can't put a number or an id in one.

ComponentWhat it shows
question_setThe set an offer is about: topics, "4 missed of 10", source, when. From the offer's facts, never model text.
flashcard_peekHow many cards, the topic, and the front of the shortest card (a cloze is blanked).
lesson_peekThe lesson's title, subject and minutes.
subject_barsReadiness bars for the subjects the message names, with their trend.
ButtonsOne or two actions, the first primary. Each is an offer id.
ChipsReplies: a check-in's answers, or "Something else" to answer in their own words.

Action registry

Offer kindOpensResolved as
quiz_setA quiz on the exact questions they misseda test template made at tap time, one per card and offer
quiz_topicNew questions on a subject or topics (PYQs where the course has them; five easier ones as a small win)picked at tap time
flashcards_dueReview of their due cards in this courseroute
flashcards_idsReview of exact cards (forgotten 3+ times, never reviewed)route
lessonA lesson by idroute
gameA game on a subject where the course has itroute
open_chatThe walkthrough chat they left, at the question they reached ("Pick up at Q3")route to that chat
chatThe tutor's chat, seeded: explain misses, cards from misses or a lesson, review cards, mini lesson, summary, plan the exam, check-inschat with a server-side plan

Latency and cost

Eval v11b at api 4762e561 (the commits after it change prompt copy and add checks): the full set of 162 synthetic learners across the nine courses, in the situations each course meets (misses, a lesson read, due cards, an exam passed, a walkthrough left part way, a new learner, back after a break, big piles, one-topic sets). The rules write the card for the 9 with a walkthrough to pick up, with no model call; the other 153 get one Gemini 3.5 Flash Lite compose each through the api's provider setup, one retry with the validator's errors, then the rules' card. A second model (Gemini 3.6 Flash) judges each valid card.

ModelRunsValid first tryValid after retryFallbacksFirst call p50 / p95 / maxWhole compose p50 / p95 / maxMean cost
gemini-3.5-flash-lite153118143101187 / 1504 / 4905 ms1258 / 2709 / 5450 ms$0.00137
ModelJudgedPass all four (person, times, claims, fit)Mean voice (1-5)
gemini-3.5-flash-lite1431394.42

At one fresh card per active learner per day, 10,000 learners cost about $14 a day. The walkthrough chat uses the existing chat model; its first turn takes about 8 s on staging.

Which model should write the card? A benchmark

Recommendation: GPT-6 Luna at low reasoning effort, through the AI Gateway. In a blinded read it wrote the best cards (step 4.73 of 5, no factual errors in 15), with no fallbacks and 13 of 15 valid on the first call. It costs about a quarter of today's model at list price ($0.00054 against $0.00233 per Home render, about $5 against $23 a day for 10,000 learners). The price is about half a second: a full card's p50 is 2.6 s against 2.1 s, and 1 card in 15 took 7.0 s, past the 6 s inline budget, so the rules card stays as the backstop. Run the full 162-learner eval on it before switching. GPT-6 Luna at none is the faster runner-up (worst 5.2 s, step 4.13).

Medium and high effort don't suit an inline card: 7 and 15 of 15 cards went past 6 s, and they wrote no better cards. DeepSeek V4.1 Flash with thinking off is the fastest to a first card (p50 1.3 s), but it fell back 3 times in 15. With thinking on it is slow (full card p50 8.5-8.7 s, worst 43 s) and costs 2-3 times today's model.

Model, effortFirst card p50 / p95Full card p50 / p95 / maxOver 6 sCost per renderValid first / after retry / fallbackJudge passVoiceMain = top offerList price, uncachedBlind step / voice (1-5)Factual errors (blind)
Gemini 3.5 Flash Lite, thinking low (today)1.7 / 2.1 s2.1 / 3.4 / 3.5 s0 of 15$0.001368 / 14 / 1 of 1514 of 144.8614 of 14$0.002333.13 / 3.200 of 15
GPT-6 Luna, none2.3 / 2.5 s2.4 / 5.2 / 5.2 s0 of 15$0.0002010 / 15 / 0 of 1515 of 154.8015 of 15$0.000634.13 / 3.270 of 15
GPT-6 Luna, low2.4 / 2.9 s2.6 / 5.4 / 7.0 s1 of 15$0.0001913 / 15 / 0 of 1515 of 154.8015 of 15$0.000544.73 / 3.600 of 15
GPT-6 Luna, medium5.9 / 8.1 s5.9 / 13.2 / 18.7 s7 of 15$0.0004913 / 15 / 0 of 1514 of 154.9315 of 15$0.000844.13 / 3.274 of 15
GPT-6 Luna, high10.4 / 16.2 s10.4 / 16.2 / 21.6 s15 of 15$0.0005815 / 15 / 0 of 1515 of 154.8715 of 15$0.000954.47 / 3.202 of 15
DeepSeek V4.1 Flash, none1.3 / 2.7 s2.2 / 2.9 / 3.4 s0 of 15$0.0012410 / 12 / 3 of 1512 of 125.0012 of 12$0.001813.93 / 3.671 of 15
DeepSeek V4.1 Flash, low4.7 / 11.8 s8.5 / 18.3 / 21.5 s8 of 15$0.003519 / 14 / 1 of 1514 of 144.5014 of 14$0.004104.40 / 3.071 of 15
DeepSeek V4.1 Flash, high8.3 / 12.0 s8.7 / 18.6 / 42.8 s9 of 15$0.0043910 / 13 / 2 of 1512 of 134.6913 of 13$0.004994.13 / 3.134 of 15

Gallery: tutors, courses and states

Indian Medical PG (NEET-PG) Rezzy

Learner state: a PYQ set yesterday, 9 misses across two subjects

You missed 9 in yesterday's PYQ set, 7 of them in Internal Medicine. Let's walk through those misses together.

Walk me throughTry the 9 again
Something else

block: question_set · source: composed

Indian Medical PG (NEET-PG), Home, on Web
Web: Home
Indian Medical PG (NEET-PG), after the first tap, on Web
Web: after the first tap
Indian Medical PG (NEET-PG), Home again after the tap, on Web
Web: Home again after the tap
Indian Medical PG (NEET-PG), Home offering to pick the walkthrough up, on Web
Web: Home offering to pick the walkthrough up
Indian Medical PG (NEET-PG), the walkthrough reopened, on Web
Web: the walkthrough reopened
Indian Medical PG (NEET-PG), walkthrough after one answer, on Web
Web: walkthrough after one answer
Indian Medical PG (NEET-PG), Home after that answer, on Web
Web: Home after that answer
Indian Medical PG (NEET-PG), Home, on iPhone
iPhone: Home
Indian Medical PG (NEET-PG), after the first tap, on iPhone
iPhone: after the first tap
Indian Medical PG (NEET-PG), Home again after the tap, on iPhone
iPhone: Home again after the tap

US Medical PG (USMLE) Rezzy

Learner state: read a lesson today, no questions on it since

You read Antiparasitic drugs (antiprotozoals) today. I can turn it into 10 flashcards so it sticks.

Make 10 cardsTry 3 on it
Something else

block: none · source: composed

US Medical PG (USMLE), Home, on Web
Web: Home
US Medical PG (USMLE), after the first tap, on Web
Web: after the first tap
US Medical PG (USMLE), Home again after the tap, on Web
Web: Home again after the tap
US Medical PG (USMLE), Home, on iPhone
iPhone: Home
US Medical PG (USMLE), after the first tap, on iPhone
iPhone: after the first tap
US Medical PG (USMLE), Home again after the tap, on iPhone
iPhone: Home again after the tap

UK Medical PG (UKMLA) Rezzy

Learner state: exam month set months ago, back after a break

Still aiming for December? Either way, 10 Medicine (Core Systems) questions are ready.

Try 10 questions
Same planNew exam date

block: question_set · source: composed

UK Medical PG (UKMLA), Home, on Web
Web: Home
UK Medical PG (UKMLA), after the first tap, on Web
Web: after the first tap
UK Medical PG (UKMLA), Home again after the tap, on Web
Web: Home again after the tap
UK Medical PG (UKMLA), Home, on iPhone
iPhone: Home
UK Medical PG (UKMLA), after the first tap, on iPhone
iPhone: after the first tap
UK Medical PG (UKMLA), Home again after the tap, on iPhone
iPhone: Home again after the tap

NCLEX-RN Rezzy

Learner state: a quiz four days ago, 3 misses; prefers flashcards

You have 12 flashcards due. Since you like flashcards, let's clear them out.

Review all 12
Something else

block: flashcard_peek · source: composed

NCLEX-RN, Home, on Web
Web: Home
NCLEX-RN, after the first tap, on Web
Web: after the first tap
NCLEX-RN, Home again after the tap, on Web
Web: Home again after the tap
NCLEX-RN, Home, on iPhone
iPhone: Home
NCLEX-RN, after the first tap, on iPhone
iPhone: after the first tap
NCLEX-RN, Home again after the tap, on iPhone
iPhone: Home again after the tap

MCAT Rezzy

Learner state: exam date has just passed

How did your MCAT go on October 26?

Went wellNot sureNot greatDidn't take it

block: none · source: composed

MCAT, Home, on Web
Web: Home
MCAT, after the first tap, on Web
Web: after the first tap
MCAT, Home again after the tap, on Web
Web: Home again after the tap
MCAT, Home, on iPhone
iPhone: Home
MCAT, after the first tap, on iPhone
iPhone: after the first tap
MCAT, Home again after the tap, on iPhone
iPhone: Home again after the tap

CFA Savvy

Learner state: a quiz three days ago, misses in Fixed Income

You missed 5 in your quiz 3 days ago, each in a different topic. I can walk you through them so you catch what slipped.

Walk me throughTry the 5 again
Something else

block: question_set · source: composed

CFA, Home, on Web
Web: Home
CFA, after the first tap, on Web
Web: after the first tap
CFA, Home again after the tap, on Web
Web: Home again after the tap
CFA, Home offering to pick the walkthrough up, on Web
Web: Home offering to pick the walkthrough up
CFA, the walkthrough reopened, on Web
Web: the walkthrough reopened
CFA, walkthrough after one answer, on Web
Web: walkthrough after one answer
CFA, Home after that answer, on Web
Web: Home after that answer
CFA, Home, on iPhone
iPhone: Home
CFA, after the first tap, on iPhone
iPhone: after the first tap
CFA, Home again after the tap, on iPhone
iPhone: Home again after the tap

CPA Savvy

Learner state: a weak set yesterday, 7 misses

You missed 7 questions in yesterday's quiz, spread across 4 topics. Let's work through them together.

Walk me throughTry the 7 again
Something else

block: question_set · source: composed

CPA, Home, on Web
Web: Home
CPA, after the first tap, on Web
Web: after the first tap
CPA, Home again after the tap, on Web
Web: Home again after the tap
CPA, Home offering to pick the walkthrough up, on Web
Web: Home offering to pick the walkthrough up
CPA, the walkthrough reopened, on Web
Web: the walkthrough reopened
CPA, walkthrough after one answer, on Web
Web: walkthrough after one answer
CPA, Home after that answer, on Web
Web: Home after that answer
CPA, Home, on iPhone
iPhone: Home
CPA, after the first tap, on iPhone
iPhone: after the first tap
CPA, Home again after the tap, on iPhone
iPhone: Home again after the tap

LSAT Casey

Learner state: new, told the tutor about a worry (pacing)

You mentioned running out of time on timed sections, so let's start with 5 easier questions to get the reasoning sure before speed. Start there, or talk it through first?

Try 5 to start
Talk it throughNot sure yet

block: question_set · source: composed

LSAT, Home, on Web
Web: Home
LSAT, after the first tap, on Web
Web: after the first tap
LSAT, Home again after the tap, on Web
Web: Home again after the tap
LSAT, Home, on iPhone
iPhone: Home
LSAT, after the first tap, on iPhone
iPhone: after the first tap
LSAT, Home again after the tap, on iPhone
iPhone: Home again after the tap

Bar Exam Casey

Learner state: retaker, misses in Contracts two days ago

You missed 4 in your Contracts quiz 2 days ago, each in a different topic. Let's walk through them.

Walk me throughTry the 4 again
Something else

block: question_set · source: composed

Bar Exam, Home, on Web
Web: Home
Bar Exam, after the first tap, on Web
Web: after the first tap
Bar Exam, Home again after the tap, on Web
Web: Home again after the tap
Bar Exam, Home offering to pick the walkthrough up, on Web
Web: Home offering to pick the walkthrough up
Bar Exam, the walkthrough reopened, on Web
Web: the walkthrough reopened
Bar Exam, walkthrough after one answer, on Web
Web: walkthrough after one answer
Bar Exam, Home after that answer, on Web
Web: Home after that answer
Bar Exam, Home, on iPhone
iPhone: Home
Bar Exam, after the first tap, on iPhone
iPhone: after the first tap
Bar Exam, Home again after the tap, on iPhone
iPhone: Home again after the tap

Tap-throughs

None this round.

No screen recordings for this final round. The Mac mini that runs the simulators ran out of memory three times on 31 October, and device work there was stopped, so the recordings were skipped. The card, tap and after shots for each course in the gallery above show where every tap lands, on web (api 9804566b) and the iPhone (api 388e38cb).

Real and mocked

Real: snapshot from staging data, offers with real ids, the model call through the api's provider setup, validation, fallback, caching, the act endpoint (test templates, flashcard ids, routes), the seeded chat with server-side turn instructions, analytics events. Seeded: the staging QA learners' history (wrong answers, lessons read, due cards, exam dates, memories) written by a staging-only script; flashcards are the course's own cards or built from the course's own plain MCQs, never another learner's. Not built: the Trigger.dev precompute (designed, not deployed), a persisted events table (Redis + PostHog only), games filtered by topic (games open on a subject where they can).

Known, outside this prototype

Open questions

Council score history

Two councils (Claude Opus 5.5 and GPT-6.1-Sol), each with learner reviewers for a Rezzy, a Savvy and a Casey course and an engineering reviewer, fresh every round. The bar was 9/10 on both axes from both councils; the loop stopped after round 11 short of it.

RoundOpus learnerOpus engineerSol learnerSol engineerTop finding
12026-10-306 (7/7/6)66 (7/8/6)5api 21ee70af, app d62e23e82, web capturesNumbers on cards weren't all grounded in the data, and a late model could show a different fallback on every open.
22026-10-306 (6/7/7)77 (7/8/7)6api 94b8087a, app bc38da8ba, web captures (all 9 re-seeded, one run)A tap didn't always open what the button promised (quiz fills short of the count, due-card counts that drifted).
32026-10-306 (6/7/7)77 (7/7/8)7api 2393ae51, app e69fdddaa, web + iPhone captures (iPhone composes after an api restart)A quiz "on a lesson" opened loosely tagged questions; counts on buttons weren't exact against the bank.
42026-10-307 (7/7/8)78 (8/8/9)6api 6e39192d, app 90d4750dc, web + iPhone captures, output judge on the 68-learner evalA tap on a card replaced while it was on screen could fail; quiz resizing rewrote unrelated facts.
52026-10-307 (7/7/7)78 (8.5/8/8)7api d1fef14b, web + iPhone captures, eval run8Check-in chips and timing ("results out yet?" five days after the MCAT); flashcard learners offered the wrong step.
62026-10-307 (7/7/7)78 (8/8/8)7web + iPhone captures, dealt records per set and lessonOpening a walkthrough marked the whole set done, so Home moved on before the learner finished.
72026-10-306 (6/7/8)67 (8/7/9)6api ac1f2700, web + iPhone captures, NEET PG and Bar answer shotsAfter "Went well" Home pushed pre-exam misses; the walkthrough's state lived in the model's memory of the first turn.
82026-10-306 (6/7/7)77 (7/8/8)7api 2266d7eb, app 042e715fe, walkthrough state in Postgres, rules resume card; web + iPhone + answer shotsThe walkthrough's try line read as a calculation on recall questions; one-miss topics were named as where the misses gathered.
92026-10-307 (7/7/8)78 (8/8.5/8.5)7.5api 6ab52076, app 042e715fe, walk commits on delivery, no card after "went well", no-verdict reveal; web + iPhone + answer shotsCounts the validator didn't tie to a topic or deck ("15 on Enzyme Kinetics" when 2 were); Home pushed practice right after "Went well".
102026-10-317 (7/7/7)77 (7/7/8)7api bdbc5f53, app c1c844b4c, full 162-learner eval, quiet Home after the exam, lesson in the check's turn, stricter validator; web + iPhone + 4 answer runsThe walkthrough's last step never saved (it ended on a tool call); copy the regex validator let through; first-try validity falling as checks grew.
112026-10-317 (7/8/7)78 (8/8/8)7.5api 9804566b (iPhone run on 388e38cb), app c1c844b4c, walkthrough end saved, narrower walkthrough routing, more validator checks, rules card one idea; web + iPhone + 4 answer runs. Last round: the owner stopped the loop here (option B)The validator is a growing list of regex checks over free text: move the model to structured slots the server words.