Inspiration

There's a Brookings stat that stuck with us: 78% of parents think their kid learns a lot in school. Only 60% of kids say the same about themselves. Parents mostly find out how their kid is doing from report cards and "how was school today," and both of those are pretty bad signals.

We didn't want to build another quiz bot. Kids already know when they're being tested, and they get good at giving the answer that ends the test, not the honest one.

So we went looking at research on "teachable agents" instead — kids who think they're teaching a character actually try harder and learn more than kids doing the same work for a grade. If the character gets confused, that's not the kid's fault. It just makes them want to explain better.

That's where Pip came from. A character who's never been to school, who wants the kid to explain stuff to it. We're still scoring the explanation underneath — checking if it actually holds up, not just if it sounded confident — but the kid never sees that part.

What it does

Two things happen each day.

Morning is Morning Ripple — short, four steps, no AI needed. Arrival, a feeling check, pick an activity, set a small intention. Tap-based, under a couple minutes. This is the easy one on purpose.

Evening is where the real thing happens. The kid tells Pip something they learned. Pip asks a follow-up like it's actually curious, not like it's grading anything. Every message a kid types gets checked by a safety filter in plain code before it goes near the AI at all — if there's a match, the session stops and a parent gets alerted immediately.

Parents get their own dashboard, and we spent a lot of time making sure it doesn't read like a report card. No letter grades. Topic trends use language like "may overestimate" instead of a number. There's a review queue for stuff that's probably fading, and a section that just flags effort worth noticing. There's also an "Ask Pip" tab where a parent can ask a question and get a summary answer — it never changes what the kid experiences.

How we built it

React + Vite, Node/Fastify, Postgres through Drizzle, Redis for rate limiting. Voice runs on the browser's built-in speech APIs, so there's no extra infra for that — it also just falls back to typing if voice doesn't work on a device, which it doesn't always.

The AI side is split into three separate calls instead of one prompt doing everything:

  • a companion call that stays in character as Pip
  • an assessor call, private, that scores what the kid actually understood
  • a composer call that takes the assessor's output and turns it into something the kid can hear — no scores, no "correct/incorrect," just process language

Splitting the assessor from the composer was on purpose. If it's all one prompt, a grading-sounding line can slip through eventually. With it split, the score literally never reaches the same output the kid sees.

Before any of that runs, there's a keyword/pattern safety check that's just JavaScript — no model involved. We wrote it as a pure function so it's easy to unit test in isolation, and tests/unit/learningSafety.test.js and tests/unit/sessionsModule.test.js cover the detection logic and the safety-first turn behavior at the route level — confirming the safety check runs and short-circuits before the session ever reaches the AI/encryption step.

We used Codex to build most of this in stages rather than asking for the whole thing at once — scaffold a module, get it running, write a test, review, then move to the next piece. That mattered most on the agent layer: instead of one big prompt for "the AI part," we had Codex build the companion, assessor, and composer as separate, separately-testable calls with their own structured output schemas — which is what made the "score never reaches the kid" guarantee something we could actually verify instead of just hope for.

Challenges we ran into

Getting the "not a test" framing to actually be true was harder than writing "be encouraging" into a prompt. That alone doesn't stop grading language from leaking through eventually. The assessor/composer split was our fix for that.

Voice was flaky in the way browser speech APIs always are — SpeechRecognition support isn't consistent across browsers, and mic permission can get denied or ignored. We ended up building the typed/tap path first and treating voice as an enhancement on top of it, not the other way around, so a session never actually depends on voice working.

We had to be careful the companion didn't start acting like it has feelings about the kid — no "I missed you," nothing that reads as dependency. That's a UNICEF guidance point for AI companions aimed at kids, and it changed some of the actual prompt language, not just a disclaimer somewhere.

Five days isn't much time, so we skipped requiring parents to paste in lesson content every day — the kid's own explanation is the input. That means we can't always catch a wrong answer that sounds internally consistent. We're just saying that outright instead of pretending it's solved.

Accomplishments that we're proud of

The safety check runs before the AI ever sees anything, and it's backed by a real test, not just a claim in a doc.

The scoring and the kid-facing response are two separate calls, not one prompt trying to do both jobs — so a score literally has no code path into what the kid hears.

We got the full loop working end to end in five days: device approval and PIN handoff, the morning ritual, the evening teaching loop, encrypted storage, and a parent dashboard pulling from real data instead of mock UI.

Six unit test suites plus a dedicated architecture-boundary test layer, covering safety detection, session/idempotency handling, student/consent logic, and the HTTP layer — for a five-day build, that's more test coverage on the safety-critical path than we expected to land.

What we learned

Most of the hard part wasn't the AI. It was everything around it — the safety gate, consent handling, what happens when the AI call fails, how data gets stored. None of that is a GPT-5.6 prompt. It's just regular backend work, and it's most of what makes this trustworthy at all.

What's next for Undercurrent

This is a demo, not something we'd hand to real families yet. Before that: actual verified parental consent instead of an email checkbox, real account email delivery, key rotation, a retention policy that's enforced instead of just documented, more adversarial testing on the safety patterns, and legal review for whatever region it'd launch in.

We also scoped but didn't build a "prediction accuracy" feature — showing a kid over time whether they're getting better at knowing what they actually understand, not just measuring the gap once and moving on. That's the next real feature, not just a settings screen.

Built With

Share this project:

Updates