Flashcards Srs
Spaced-repetition scheduling engine for flashcards, study decks and memory apps: a pure, deterministic SM-2 (SuperMemo 2) implementation plus Leitner boxes and deck analytics. schedule takes one...
flashcards-srs
Spaced-repetition scheduling engine for flashcards, study decks and memory apps — a pure, deterministic SM-2 (SuperMemo 2) implementation plus the classic Leitner box system and deck analytics. Packaged as a Leumas "intelligent microservice" adapter pack.
Every tool has a deterministic algorithmic core that works fully offline with no model. A couple of tools (schedule, difficulty) can optionally enrich their study tip with an LLM when one is reachable (via ../_shared/llm.js), and silently fall back to a templated tip otherwise. Results carry a mode: 'heuristic' | 'llm' tag when the LLM path is enabled.
Tools
| Tool | Input | Returns |
|---|---|---|
schedule | { card, grade, date?, options? } | One SM-2 step: next intervalDays, updated ease, repetitions, lapses, phase, due date. Grade <3 lapses the card (reset to 1 day). |
review | { cards, date?, options? } | Batch SM-2 — advances an array of { ...cardState, grade } cards; returns per-card next state + deck accuracy/avg interval. |
leitner | { card?, box?, correct, date?, options? } | Moves a card up one Leitner box on correct recall, resets to box 1 on incorrect; returns new box, interval and due date. |
dueToday | { cards, date?, options? } | Buckets a deck into overdue, dueNow, upcoming (within horizonDays) and new cards; returns the flat due id list. |
deckStats | { cards, date?, options? } | Deck aggregate: state distribution (new/learning/review/mature), avg ease, maturity %, difficulty mix, and a day-by-day due forecast. |
difficulty | { card, options? } | Classifies a card easy/medium/hard/leech with a 0-100 difficulty index and a remediation tip. |
retentionEstimate | { card, date?, options? } | Forgetting-curve R(t)=exp(-t/S) recall probability now + the optimal next review for a targetRetention. |
Card shape
All tools accept a defensive card object (all keys optional, sensible defaults applied):
{ "id": "capital-of-france", "ease": 2.5, "interval": 6, "repetitions": 2, "lapses": 0,
"box": 3, "due": "2026-07-20", "lastReviewed": "2026-07-14" }
Usage
import srs from './index.js';
// SM-2: a card recalled perfectly (grade 5) after 2 prior reps
srs.adapters.schedule({ card: { ease: 2.5, interval: 6, repetitions: 2 }, grade: 5 });
// -> { mode:'heuristic', ease:2.6, intervalDays:16, repetitions:3, phase:'review', due:'2026-07-30', ... }
// Leitner: a wrong answer drops the card to box 1
srs.adapters.leitner({ card: { id: 'x', box: 4 }, correct: false });
// -> { fromBox:4, box:1, intervalDays:1, due:'2026-07-15', note:'Incorrect — reset to box 1...' }
// What's due
srs.adapters.dueToday({ cards: deck, date: '2026-07-14' });
SM-2 algorithm (implemented exactly)
grade q ∈ 0..5.q < 3⇒ lapse: repetitions → 0, interval → 1 day, lapse counter +1.EF' = EF + (0.1 - (5-q)·(0.08 + (5-q)·0.02)), floored at 1.3.- Interval: rep 1 → 1 day, rep 2 → 6 days, rep n>2 →
round(prevInterval × EF').
DRY boundary
New capability — a memory/learning scheduler. It deliberately does not overlap:
datetime/ical— generic date math and calendar-file generation (this owns study scheduling logic).numbers/statistics— generic numeric/series math (this owns the SM-2, Leitner and forgetting-curve models).cron— interval-string parsing (5m); unrelated to review scheduling.
Self-contained: Node built-ins only, zero npm deps. The only cross-pack import is ../_shared/llm.js for the optional study-tip enrichment.