← All posts

April 22, 2026

Building the level switcher: one click, three readings of the same chapter

One of the requests we kept hearing from beta users was: "I want to read this thing, but it's too hard. Can the AI rewrite it at my level?" Sounds simple. The interesting part was wiring it in without making the schema ugly.

The problem

A reader document has a body, a title, optionally a source URL, optionally a parent book it belongs to. We wanted three difficulty levels per document, each generated on demand, each cached on disk so the second click is instant.

The decision

Variants are siblings, not embedded fields. Each variant is its own reader_documents row, with a parent_id pointing at the original and a level column. That gave us:

  • Free reuse of the existing CRUD, listing, and search endpoints — variants are reader documents.
  • An obvious cache: SELECT * FROM reader_documents WHERE parent_id = ? AND level = ?.
  • Click-to-define popovers, the chapter pager, and the level switcher itself all read from the same shape.

The cost

We had to make listReaderDocs filter by parent_id IS NULL so the sidebar wouldn't show 4× the entries. One WHERE clause; cheap. We also had to propagate library_item_id and chapter_position from parent to variants so that switching to a beginner reading inside a book chapter still has a chapter pager — also one line.

The prompt

The simplifier passes the user's known vocab (mastered + review) into the system prompt, plus their computed level. It explicitly says "don't translate" and "preserve paragraph structure". The output is the rewritten text and only the rewritten text — we don't ask for explanations, because we have separate UI for that.

Three weeks in: people use it. The "Beginner" pill on a chapter that originally felt unreadable does what people hoped. Boring engineering, working feature.