Algernon Review
by @antoniovfranco
FSRS-4.5 flashcard review session for OpenAlgernon. Use when the user runs `/algernon review`, says "revisar flashcards", "quero revisar", "cards em atraso",...
clawhub install algernon-reviewπ About This Skill
name: algernon-review version: "1.0.0" description: > FSRS-4.5 flashcard review session for OpenAlgernon. Use when the user runs
/algernon review, says "revisar flashcards", "quero revisar", "cards em atraso",
"modo revisao", "review session", or asks to practice due cards. Handles all card
types (flashcard, dissertative, argumentative), AI evaluation of open-ended
answers, automatic FSRS scheduling, N1/N2/N3 promotion, and correction card
generation.
algernon-review
You run the interactive flashcard review session with FSRS-4.5 spaced repetition. You handle flashcards (binary reveal), dissertative cards (AI-graded), and argumentative cards (AI-graded). At the end, you check promotion eligibility and save the session.
Constants
ALGERNON_HOME="${ALGERNON_HOME:-$HOME/.openalgernon}"
DB="${ALGERNON_HOME}/data/study.db"
FSRS-4.5 Parameters
Step 1 β Fetch Due Cards
sqlite3 "$DB" \
"SELECT c.id, c.type, c.front, c.back, c.tags, c.source_title, c.deck_id,
cs.stability, cs.reps, cs.state
FROM cards c
JOIN card_state cs ON cs.card_id = c.id
JOIN decks d ON d.id = c.deck_id
JOIN materials m ON m.id = d.material_id
WHERE cs.due_date <= date('now')
[AND m.slug = 'SLUG']
ORDER BY cs.due_date ASC
LIMIT 50;"
(Include AND m.slug = 'SLUG' only if a specific slug was provided.)
If no cards due: "No cards due for review. Great job staying on top of it." and stop.
Display: "Starting review: N cards due."
Step 2 β Review Loop
Flashcards (type = 'flashcard')
1. Show front. AskUserQuestion options: ["Show answer"] 2. Show back. AskUserQuestion options: ["Again", "Good"] 3. Run FSRS update (see Step 3).
Dissertative and Argumentative Cards
1. Show front. AskUserQuestion options: ["Ready to answer"] 2. AskUserQuestion: "Type your answer:" (free text) 3. Evaluate the response against the reference answer (card back): - Dissertative: check accuracy of key points, completeness - Argumentative: check that both sides are represented, trade-offs identified - Output: brief feedback + suggested grade (1 or 3) + optional MISCONCEPTION note 4. Show evaluator feedback + reference answer. AskUserQuestion options: ["Again", "Good"] (Use the user's button choice, not the AI suggestion.) 5. Run FSRS update using the user's chosen grade. 6. If a MISCONCEPTION was detected, create a correction card:
sqlite3 "$DB" \
"INSERT INTO cards (deck_id, type, front, back, tags)
VALUES (DECK_ID, 'flashcard',
'CORRECTION: MISCONCEPTION_QUESTION',
'CORRECT_EXPLANATION',
'[\"[correction]\",\"[N1]\"]');
INSERT INTO card_state (card_id, due_date)
VALUES (last_insert_rowid(), date('now'));"
Step 3 β FSRS Scheduling
For each graded card, compute new values and update card_state.
Read current state:
sqlite3 "$DB" \
"SELECT stability, difficulty, reps, lapses, state, last_review
FROM card_state WHERE card_id = CARD_ID;"
Compute elapsed days (if last_review is not NULL):
sqlite3 "$DB" \
"SELECT ROUND(julianday('now') - julianday('LAST_REVIEW'), 2) AS elapsed;"
State transitions:
| State | Grade | New stability | New difficulty | New state | Interval | |------------|-------|---------------------------|-----------------------------|------------|------------------| | new | Good | 0.4 | 0.3 | review | 1 day | | new | Again | 0.1 | 0.4 | learning | 1 day | | learning | Good | stability * 1.5 | MAX(0.1, difficulty - 0.05) | review | MAX(1, ROUND(S)) | | learning | Again | stability (unchanged) | MIN(1.0, difficulty + 0.1) | learning | 1 day | | relearning | Good | stability * 1.5 | MAX(0.1, difficulty - 0.05) | review | MAX(1, ROUND(S)) | | relearning | Again | stability (unchanged) | MIN(1.0, difficulty + 0.1) | relearning | 1 day | | review | Good | S * EXP(0.9*(1-R)) | MAX(0.1, difficulty - 0.05) | review | MAX(1, ROUND(S)) | | review | Again | MAX(0.1, stability * 0.2) | MIN(1.0, difficulty + 0.1) | relearning | 1 day, lapses+1 |
For review+Good, compute retrievability first:
sqlite3 "$DB" \
"SELECT EXP(LN(0.9) * ELAPSED / STABILITY) AS R;"
Update:
sqlite3 "$DB" \
"UPDATE card_state SET
stability = NEW_S,
difficulty = NEW_D,
due_date = date('now', '+' || INTERVAL || ' days'),
last_review = datetime('now'),
reps = reps + 1,
lapses = NEW_LAPSES,
state = 'NEW_STATE'
WHERE card_id = CARD_ID;
INSERT INTO reviews (card_id, grade, scheduled_days, elapsed_days)
VALUES (CARD_ID, GRADE, INTERVAL, ELAPSED);"
Step 4 β Promotion Check (after all cards)
For each card reviewed with grade = Good where reps >= 5:
sqlite3 "$DB" \
"SELECT c.id, c.tags, c.deck_id, cs.reps
FROM cards c JOIN card_state cs ON cs.card_id = c.id
WHERE c.id = CARD_ID AND cs.reps >= 5;"
If reps >= 5 and tags contain [N1], check deck retention over last 7 days:
sqlite3 "$DB" \
"SELECT CAST(SUM(CASE WHEN grade=3 THEN 1 ELSE 0 END) AS REAL) / COUNT(id) AS retention
FROM reviews r JOIN cards c ON c.id = r.card_id
WHERE c.deck_id = DECK_ID AND r.reviewed_at >= datetime('now', '-7 days');"
If retention >= 0.9:
[N2], due today.[N2] cards: promote to N3 (full technical depth, productionStep 5 β Session Summary
Session complete.
Cards reviewed: N
Again: X | Good: Y
Retention this session: Z%
Next review: [earliest due_date from card_state]
Append to today's conversation log:
echo "[HH:MM] review session | Cards: N | Retention: Z% | Promotions: P" \
>> "${ALGERNON_HOME}/memory/conversations/YYYY-MM-DD.md"