Skip to content

09 · How it works

Scheduling (FSRS)

FSRS decides when a card returns. No state is kept — the schedule is replayed from the review log every time.

On this page

Review intervals are set by FSRS (Free Spaced Repetition Scheduler). Cards you know well come back later; shaky ones come back sooner.

No state, replayed from the log

data/reviews/*.jsonl is the only truth. A card’s schedule is derived by replaying that card’s log every time.

Keeping state separately creates a second truth and they always drift apart. In the system this replaced, 23 days of study had left only 5 commits — 18 days of history had vanished.

Two consequences follow from the design.

  • No fuzz on intervals. Randomness would change the result on every replay
  • New cards are treated as “can be shown right now”

Each log line carries at least card_id, review_time (Unix ms) and review_rating (1–4). One file per day, append-only.

Do not hand-edit, sort or delete anything under data/. Log lines for deleted cards stay (they are the only copy of the history).

The defaults

Value
AlgorithmFSRS-6 (21 parameters)
Desired retention0.9
Short-term steps1 min / 10 min (10 min for relearning)
New cards per day20 (Anchor Pro lifts the cap)

On the defaults, all three platforms produce the same intervals from the same log. A brand-new card reads “Again 1 min / Hard 6 min / Good 10 min / Easy 8 days”.

Changing the parameters (data/fsrs.json)

There is no input field in settings. Having said that the repository is the source of truth, a per-device setting would be a second truth. Put data/fsrs.json in the repository and it is read on every sync.

{
  "w": [ 21 numbers ],
  "desired_retention": 0.9,
  "learning_steps": ["1m", "25m"],
  "relearning_steps": ["10m"],
  "maximum_interval": 36500
}
  • Keys are snake_case, so output from the usual optimisers or Anki pastes in directly (camelCase is also accepted)
  • Every field is optional, and a broken file never stops the app. It falls back to the defaults and says in settings what it declined and why
  • w is accepted at lengths 17 / 19 / 21 only. Anything else falls back, with a note in settings
  • Each sync diffs it; if it disappears remotely, it is removed from the device too

Specifying a 19-element w drops iOS to FSRS-5, where it stops reading learning_steps (short-term becomes a fixed 1/5/10 minutes). Mac and Android honour the steps even at 19. Settings surfaces the discrepancy. Write no w at all and all three run FSRS-6.

Settings showing “FSRS-5” is therefore correct reporting that you passed a 19-element w.

Optimising from your own log (Mac)

Settings → “Optimise from your log” on the Mac build learns parameters from your own review history.

  • It shows you how the intervals would change before you accept (changing the parameters recomputes every card’s due date at once)
  • Accepting rewrites data/fsrs.json and sends it on the next sync. The same settings then land on your iPhone
  • Only reviews whose previous grade was on a different day are used as input. Same-day repeats have zero elapsed time and carry no information about forgetting
  • Roughly 400 reviews to try it, 1,000 to be stable. You can run it below that and throw the result away
  • Optimising works in the packaged app only (about once a month is plenty)

iOS and Android only read the file.

This page is the public specification for Anchor Cards. Found something that disagrees with the app? Tell us onGitHub or viacontact.