Themed clusters

DRAFT — will change

A cluster is just related words kept side by side — food, travel, feelings — a reference the agent can lean on, never a checklist it has to clear. When the FSRS backbone marks an item due, the agent resurfaces it where the chat opens a door, and the cluster is just the nearby words it may also reach for if the moment allows. This is V1's teaching loop, riding on the Anki backbone.

6 min
Versioning. V0 = the sticky first conversation (design · plan). V1 = the teaching layer = the Anki backbonefull FSRS scheduling, the real tracking-and-timing spine — plus this doc, the reference layer of themed clusters over it. Post-V1: skill rating, anti-annoying cadence tuned by data, other languages.
  1. Why not one queue
  2. The cluster
  3. The themed open
  4. A session, end to end
  5. How clusters form
  6. Picking the moment
  7. The session objective
  8. Data & the web page
  9. V1 vs later
  10. Open questions

Why not one queue

A plain SRS queue hands you whatever's due, in scheduler order: 久しぶり (long time no see), then 醤油 (soy sauce), then 締め切り (deadline). No single conversation can carry all three — they have nothing to do with each other — so there's no natural way to resurface them in a real chat. You're forced back to flashcards.

Cluster by meaning and the problem dissolves. Group the food words together, and when one of them comes due, one ordinary conversation — "what's for lunch?" — has room for it, plus any neighbors that happen to fit. The theme is what makes conversation-native review possible: a thread can hold a topic, so a due word has somewhere natural to land — and related words sit right there as reference, not as a list to get through.

The cluster

A cluster is a handful of tracked items that hang together by topic — drawn from the user's own life, the same words the backbone already logged. Examples after a few weeks of chatting:

🍜 Food & eating

お腹すいたonaka suitalearning
醤油しょうゆlearning
注文ちゅうもんnew
おすすめosusumeshaky
辛いからいknown

✈️ Travel & moving

引っ越しひっこしnew
片道かたみちlearning
久しぶりひさしぶりshaky
荷物にもつlearning

Each item still lives in the backbone with its own status and its own FSRS due date — the cluster owns neither. It's just a theme tag grouping related words so the agent has them on hand as reference. A word can carry more than one theme; the cluster is a lens for review, not a folder that owns the word, and never a set the agent has to use in full.

The themed open

FSRS is what says an item is due. When a due item belongs to a theme the user actually talks about, the agent can open a proactive message on that theme — and the job is simply: resurface the due item where the conversation gives it a natural home. The cluster around it is reference — related words the agent may reach for if a door opens, never a list it has to clear.

1
Open on the theme, not the words. "お腹すいた、what're you eating today?" — a normal hungry-friend text. The user can't tell it's a review session; it just feels like anna's thinking about lunch.
2
Resurface the due item first; lean on neighbors only if they fit. The due word (say 醤油) is the point — soy vs miso gives it a natural opening. Cluster neighbors like 注文 or おすすめ are reference: if the thread happens to open a door, reach for one; if not, leave it. Gloss only if they'd be lost.
3
Grade from the replies — that grade feeds FSRS. They use 醤油 cleanly → it grades well and FSRS pushes its next review out; they blank on おすすめ → it grades down and comes back sooner. Same inferred grading as always — the conversation is the grade button.
Coverage was never the goal. The cluster is reference, not a quota. If a neighbor like 注文 gets no natural opening, it simply isn't used — the agent does not shoehorn it in, and nothing is owed. Even the due item waits if the thread won't carry it; FSRS will surface it again. This is the backbone-advises, agent-decides rule: FSRS sets the table, the agent still reads the room.

A session, end to end

Anna opens unprompted. The due item is 醤油; the rest — 注文 · おすすめ · 辛い — are food-cluster neighbors she reaches for only because the thread opens a door to each.

anna · proactive open
お腹すいた〜
what're you eating today?
idk maybe ramen
anna
いいね 🍜
醤油 or 味噌?
shoyu always
anna
醤油 ramen, classic
are you the type to 注文 the same thing every time, or do you go for the おすすめ?
usually the same thing lol. whats osusume mean
anna
the おすすめ = what they recommend, the house pick
next time 注文 the 辛い one, live a little 🌶️
haha maybe. 辛いの注文してみる

One due word resurfaced, three neighbors riding along because the chat happened to make room — the user produced 注文 and 辛い unprompted by the end (both grade well, FSRS pushes them out), got a quick gloss on おすすめ (graded down, comes back sooner), and never once felt reviewed. Had the chat gone elsewhere, only 醤油 would've surfaced — and that'd be fine. That's the whole loop.

How clusters form

Cheap and emergent, not a hand-built taxonomy. As the backbone captures each item, the agent also tags it with a theme — a short semantic label (food, travel, work, feelings). Items sharing a theme are a cluster.

Picking the moment

In V1, FSRS already answers what's due — per item, with real timing. What's left to the agent's judgment is which theme to open on and when:

One theme per session. Mixing clusters re-creates the random-queue problem inside a single chat.

The session objective

Mechanically this reuses what onboarding already does. V0 gives the agent a live objective block for the current stage (currentObjective() in core/agent.mjs). A themed open is just another objective: a transient block naming the FSRS-due item(s) to resurface, with the cluster's other words listed underneath as reference — use the due ones where the conversation allows, lean on the neighbors only if they fit, force nothing.

# Right now → themed open: Food & eating
Open naturally on food (they often grab ramen).

DUE (FSRS) — resurface where it fits, don't force:
  醤油 (learning)

REFERENCE — related words; reach for one only if a door opens:
  注文 · おすすめ · 辛い

Gloss only if they'd be lost. Grade from how they reply
(remember → FSRS). Nothing here is owed — if the thread won't
carry the due item, leave it; it'll come due again.

No new machinery — same objective-injection pattern, same remember tool writing grades back to FSRS. FSRS picks what's due; the cluster just supplies the related words sitting next to it.

Data & the web page

A small extension to the backbone's item store: each item gains a theme (or a list of themes).

"醤油": {
  surface: "醤油", reading: "しょうゆ", gloss: "soy sauce",
  status: "learning",
  fsrs: { due: "2026-06-25", stability: 4.2 }, // from the backbone
  theme: "food",            // the cluster's only addition
  lastSession: "2026-06-23" // when it last got a themed pass
}

On the read-only web page, themes become the natural grouping — vocab shown in clusters (Food, Travel, Work…) instead of one long list. Same read-only rule: view, don't edit; you grow a cluster by talking about it, not by filing words into it.

V1 vs later

V1 — now

  • Full FSRS scheduling in the backbone — real per-item timing & decay drives what's due.
  • Theme tag per item; clusters emerge as a reference layer.
  • Proactive themed opens on a due item's theme.
  • Objective = resurface the FSRS-due item; cluster words are reference, never forced.
  • Web page grouped by theme.

Later (post-V1)

  • Anti-annoying cadence tuned by data, not feel.
  • Cross-cluster sequencing over weeks.
  • Skill rating (ELO) to set session difficulty.
  • Other languages.

Open questions