← Blog

Why we built Discito on FSRS-6

Spaced repetition is one of those rare ideas in cognitive science where the math actually pays off in your real life. Show a fact at the right moment — not too soon, not too late — and you can remember it for years instead of weeks. Get that timing wrong, and you spend hours reviewing material your brain had already filed away.

Every flashcard app that's ever mattered has been a bet on which scheduling algorithm gets that timing closest to right. Discito's bet is FSRS-6. Here's why.

The shortest possible history of "when should I see this card?"

The original answer was Leitner boxes, proposed by Sebastian Leitner in 1972 — physical index cards, five boxes, move a card forward when you get it right and back to box one when you get it wrong. Simple, mechanical, and roughly correct: harder cards come back sooner, easier cards drift toward the bottom of the stack.

In 1985, Piotr Wozniak published SM-2 as part of the original SuperMemo. SM-2 was a closed-form formula: given a card's previous interval, your last rating (Again / Hard / Good / Easy), and a per-card "ease factor," compute the next due date. SM-2 is the algorithm that made Anki famous. Almost every spaced-repetition app you've used in the last fifteen years runs some variant of it.

SM-2 has a problem, though. The ease factor is hand-tuned, the formula is fixed, and the model has no real concept of how memory actually works — just a heuristic that's been roughly right for a generation of learners. If you've ever felt like Anki was over-burying easy cards or surfacing hard ones too late, you weren't imagining it. SM-2 was a 1980s approximation of a 2020s problem.

Wozniak kept iterating — SM-15, SM-17, SM-18 — but each successor stayed closed-source, locked inside SuperMemo. Meanwhile, the Anki community had millions of users generating billions of reviews, and nobody could touch that data to build something better.

Enter FSRS

The Free Spaced Repetition Scheduler — FSRS — is the answer that the open-source community built. It's based on a three-component memory model:

Instead of a hand-tuned formula, FSRS uses a small neural model trained on millions of real Anki reviews from the Open Spaced Repetition project. The model has 21 weights; those weights define how difficulty, stability, and retrievability evolve with every Again / Hard / Good / Easy you tap. Schedule the next review based on the retention probability you've asked for (default 90%), and you get scheduling that's measurably better than SM-2 on the same review history.

FSRS-6 is the latest version, released in 2024. It adds short-term memory handling for cards reviewed within the same day, better forgetting-curve behavior for very long intervals, and a cleaner separation between the "first review of a brand-new card" case and everything that comes after.

FSRS-6 isn't "better than Anki." It is the algorithm that Anki itself now ships as the modern default. The community converged.

Why this matters for Discito

When we started building Discito, the FSRS-6 spec was already public. The reference implementation — py-fsrs — was already shipping. The challenge wasn't inventing better scheduling; it was making sure that what we shipped on iOS produced the exact same review times that Anki desktop would produce for the same review history.

That "exact same" matters more than it sounds. Two devices that disagree by a single ULP — one unit in the last place of a floating-point number — produce slightly different intervals, which over thousands of reviews diverge into noticeably different decks. Sync becomes a lie. Cross-device parity becomes impossible.

So Discito's FSRS port has one non-negotiable invariant: bit-exact with py-fsrs on every supported review path. Every test in FSRSKit runs against parity fixtures generated by the reference Python implementation. If we change the algorithm, the fixtures change. If we don't change the fixtures, we cannot have introduced a divergence.

The one gotcha worth telling you about

Swift's standard library has both exp(x) and pow(M_E, x). They should produce identical results. They do not — they diverge by one ULP at scattered inputs because exp(x) uses a lookup table while pow(M_E, x) uses the general power function. That occasional 1-ULP gap is enough to fail a parity test against py-fsrs, which uses Python's math.e ** x — and Python's ** operator routes through the C library's pow, not exp.

So Discito's FSRS implementation uses Foundation.pow(M_E, x) everywhere, never exp. It's a one-line discipline that took an embarrassingly long time to figure out, and it's the kind of thing that distinguishes "we shipped FSRS" from "we shipped FSRS that actually matches the reference." Discito's parity tests don't pass unless every floating-point output matches py-fsrs to the bit.

The optimizer that lives on your phone

The 21 default weights work well as a starting point — they're trained on a huge cross-section of Anki review data, so they generalize. But your memory isn't an average. The interval at which you forget pharmacology vocabulary is not the interval at which someone else forgets verb conjugations. Eventually, you want weights tuned to your own review history.

That's what FSRS's per-user optimizer does. After about 1,200 reviews — the rough threshold below which you don't have enough data for stable training — the optimizer runs a small gradient-descent pass over your actual review history and produces a personalized weight vector. From that point on, your scheduling is tuned to your memory.

Most apps that support FSRS optimization run it on a server. You upload your review history, a server crunches the numbers, you download new weights. That's fine, but it means your study data leaves your device, and it means the feature breaks the moment you're offline.

Discito does it differently. We vendored fsrs-rs, the Rust reference optimizer, and bridged it to Swift via swift-bridge. The optimizer runs on your iPhone, on your review history, and produces weights that persist in NSUbiquitousKeyValueStore — Apple's key-value sync. Your weights follow you across devices via iCloud, like everything else in Discito. Nothing leaves your device for any of this to work.

On an iPhone 17 Pro, the optimizer chews through a 1,200-review fixture in about 55 milliseconds. On older hardware it's slower, but it still finishes in well under a second. You tap "Optimize FSRS Parameters" in Settings → Review & Scheduling, the spinner appears, the spinner disappears, your weights are now yours. (This feature is part of Discito Pro.)

Why we don't ship "FSRS Lite" or "FSRS Light"

Some apps brand FSRS support as a premium feature, then ship a subset of the algorithm on the free tier. We're not going to do that. Free users on Discito get the full FSRS-6 algorithm, including all 21 default weights, full scheduling, full retention math. The only piece behind the Pro paywall is the per-user optimizer, because that's the piece with non-trivial ongoing compute cost and storage requirements.

If you're paying $0 for Discito Lite, you're getting the same scheduling quality that paying $25 for AnkiMobile gives you — modulo the per-user weight tuning, which most users won't notice without first banking the 1,200 reviews the optimizer needs anyway. That's the bar.

Credit where it's due

None of this would exist without the work of the Open Spaced Repetition project — particularly Jarrett Ye (LMSherlock) and the contributors who built the FSRS family, published the spec, maintained the Python and Rust reference implementations, and validated the model against the largest spaced-repetition dataset in existence. Discito's FSRS implementation is a port. The science is theirs.

And, obviously, Damien Elmes — Anki's creator — built the open-source app that made spaced repetition mainstream in the first place. Every FSRS app, including Discito, stands on that foundation. We credit both in the App Store listing for the same reason: this category exists because of open-source work, and we don't get to pretend otherwise.

What Discito adds is the iOS-native experience — sync that just works, a 30-second onboarding, widgets, Live Activities, on-device AI for card generation, and a price tag that says "$14.99 once" instead of "$X.XX per month forever." The algorithm is the same one that's already won. We're just shipping it the way iOS users have been waiting for.

Try Discito

Discito Lite is free forever. Pro is $14.99 once, lifetime, Family Sharing included.

Read other posts