Skip to content
М

Boston, MA

Matt Serdukoff

Lociros

Graded readers where A2 is actually A2. Ask a model for beginner text and it reaches for grammar a beginner has not met yet, so Lociros treats the CEFR level as a constraint it can check.

Write A1 Japanese about a morning at the market.

  1. Draft

    毎朝、市場に行って、魚を買っています。

    ja:te_form (て)ja:te_iru (て)Fails A1

  2. Rewrite

    毎朝、市場に行きます。そして、魚を買います。

    Every morning I go to the market. Then I buy fish.

    Passes A1, shelved

Checked, not asked

The model writes. It does not get to decide what level it wrote. The draft and rewrite above are real validator output: て-form and ている are both off the table at A1, and the polite present passes.

  1. 01ConstrainThe prompt carries the level's grammar rules and every word allowed at or below it.
  2. 02AnalyzeThe draft is tokenized by a real analyzer for its language: lemma, part of speech, inflection, reading.
  3. 03ValidateRules in JSON score over-level words and forbidden constructions. Nothing is taken on the model's word.
  4. 04RewriteA failing draft goes back with its flags, at a lower temperature. The less severe attempt is kept.
  5. 05QuarantineA draft that still fails is stored for review and never reaches the shelf.

One analyzer per language

Each language drifts upward in its own way, so each gets its own analyzer and its own rules. CEFR levels live in hand-edited JSON per language, with allowed cases, tenses, and constructions and a cap on over-level words.

  • JapaneseSudachiて-form, ている, relative clauses, keigo
  • ArabicCAMeL Toolspast tense, إنّ, derived Forms II–X, the passive
  • ItalianspaCycongiuntivo, gerundio, passato remoto
  • Russianrazdel + pymorphy3extra cases, participles, бы, который-clauses

Every word arrives analyzed

The reader is built on the same analysis the validator used. Tap a word for its lemma, level, grammar, and gloss. Japanese words break into kanji, with each reading aligned to its character, and Arabic words show their root and verb form.

市場しじょうmarketnoun / A2
  • 市し, market, city, town5 strokes / JLPT N3
  • 場じょう, location, place12 strokes / JLPT N4

Kanji details come from a bundled KANJIDIC2 lexicon of about 13,100 characters. Stroke order animates from KanjiVG when the gloss opens.

A level that follows the reader

  • Placement by reading

    One short passage per band from A1, four questions each, climbing while the reader gets three of four right. After 30 days away, the shelf offers the ladder again from the old band.

  • Ratings that move slowly

    Three too-easy or too-hard ratings in a row move placement one CEFR step. Just right clears the streak, so one bad day does not reshuffle the shelf.

  • New versus known

    Every card on the shelf counts content words you have already met against new ones, by token, so a recycled word that shows up three times counts three times.

  • What to read next

    Unread, calibration-passed passages at your level first, then one up, then one down. Texts that reuse words you tapped for a gloss rank higher.

Slow on purpose, safe to run

Writing, analyzing, maybe rewriting, and translating a passage takes 20 to 40 seconds, so generation runs as a background job the client polls instead of a request that holds a connection open.

  • The pytest suites never call the LLM. Validators are tested on fixed sentences: て-form fails A1 and passes A2, congiuntivo fails B1 and passes B2.
  • Guests get a device id, a placement read, and one passage. Signing up moves that progress onto a Supabase account.
  • FastAPI runs as two replicas behind nginx, deployed with a rolling restart and a one-command rollback. The Next.js frontend and admin app are on Vercel.
  • Generation is capped per account each month and rate limited per caller and per IP.