Review spaced-repetition facts that are due today. Applies SM-2 algorithm to update interval, ease, and next_review in each fact's frontmatter. Updates review-log.jsonl. Use when the user says "revisar", "review facts", "study", or "/learn-review".
Installs into .claude/skills of the current project.
Are you the author of Learn Review?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/evolution-foundation-learn-review)
---
name: learn-review
description: Review spaced-repetition facts that are due today. Applies SM-2 algorithm to update interval, ease, and next_review in each fact's frontmatter. Updates review-log.jsonl. Use when the user says "revisar", "review facts", "study", or "/learn-review".
---
# Learn Review
Reviews facts in `workspace/learning/facts/` whose `next_review` date is today or in the past. Applies SM-2 grading and rewrites frontmatter in-place. Records every grade in `workspace/learning/.state/review-log.jsonl`.
## SM-2 Formula (implement exactly as specified)
Given current `reps`, `interval`, `ease`, `lapses`:
**Again (grade 0):**
- `reps = 0`
- `interval = 1`
- `ease = max(1.3, ease - 0.2)` (round to 2 decimal places)
- `lapses = lapses + 1`
**Hard (grade 3):**
- `interval = round(interval * 1.2)` (minimum 1)
- `ease = max(1.3, ease - 0.15)` (round to 2 decimal places)
- `reps = reps + 1`
**Good (grade 4):**
- If `reps == 0`: `interval = 1`
- Else if `reps == 1`: `interval = 6`
- Else: `interval = round(interval * ease)` (minimum 1)
- `ease` is unchanged
- `reps = reps + 1`
**Easy (grade 5):**
- Same interval as Good, then additionally: `interval = round(interval * 1.3)` (minimum 1)
- `ease = ease + 0.15` (round to 2 decimal places)
- `reps = reps + 1`
**For all grades:** `next_review = review_date + interval days`
**Ease floor:** 1.3. Never let ease drop below 1.3 regardless of how many Again grades.
## Workflow
### Step 1 β Scan for due facts
1. Read all `.md` files in `workspace/learning/facts/`
2. Parse the frontmatter of each file
3. Get today's date (YYYY-MM-DD)
4. Select facts where `next_review <= today`
5. Sort by `next_review` ascending (oldest due first)
6. Take up to 5 facts (N=5 default)
If no facts are due:
> "Nenhum fato vencido hoje. π PrΓ³xima revisΓ£o: {earliest next_review across all facts}."
> Stop here.
If `workspace/learning/facts/` does not exist or is empty:
> "Nenhum fato encontrado. Use /learn-capture para adicionar fatos primeiro."
> Stop here.
### Step 2 β Review loop (one fact at a time)
For each due fact (up to 5):
**2a. Show the question:**
```
ββββββββββββββββββββββββββββββββββ
π Deck: {deck} | Fato {current}/{total_due_shown}
ββββββββββββββββββββββββββββββββββ
β {Retrieval Q content}
[Pense na resposta antes de prosseguir. Pressione Enter quando pronto.]
```
Wait for the user to confirm they've thought about it (any input is fine).
**2b. Show the answer:**
```
β Resposta:
{Fact content}
π‘ Por quΓͺ importa:
{Why it matters content}
```
**2c. Ask for grade:**
```
Como foi?
0 - Again (errei / nΓ£o lembrei)
3 - Hard (lembrei com dificuldade)
4 - Good (lembrei bem)
5 - Easy (muito fΓ‘cil)
```
Wait for the user to enter 0, 3, 4, or 5. Accept also the words "again", "hard", "good", "easy" (case-insensitive).
### Step 3 β Apply SM-2 and update file
For the grade received:
1. Compute `prev_interval = current interval`
2. Compute `prev_ease = current ease`
3. Apply SM-2 formula above to get `new_interval`, `new_ease`, `new_reps`, `new_lapses`
4. Compute `new_next_review = today + new_interval days`
5. Rewrite the fact file with updated frontmatter, preserving the body content exactly
**Frontmatter rewrite rules:**
- Update only: `next_review`, `interval`, `ease`, `reps`, `lapses`
- Preserve all other fields unchanged: `id`, `source`, `deck`, `created`
- Preserve the body (everything after the closing `---`) exactly as-is
### Step 4 β Append to review log
Append one JSON line to `workspace/learning/.state/review-log.jsonl` (create file if it doesn't exist, create directory if needed):
```json
{"ts": "{ISO8601_timestamp}", "fact_id": "{id}", "grade": "{again|hard|good|easy}", "prev_interval": {N}, "new_interval": {M}, "prev_ease": {X}, "new_ease": {Y}}
```
Grade string mapping: 0β"again", 3β"hard", 4β"good", 5β"easy"
### Step 5 β Next fact
Continue with the next due fact. After all N facts (or all due facts if < N):
```
ββββββββββββββββββββββββββββββββββ
β SessΓ£o de revisΓ£o concluΓda!
Revisados: {N} fatos
Resultado: {X} Good/Easy | {Y} Hard | {Z} Again
PrΓ³xima revisΓ£o: {earliest next_review across all facts}
ββββββββββββββββββββββββββββββββββ
```
## Verification helper (Grade Good progression)
When testing, the interval sequence for repeated Good grades starting from `reps=0, interval=1, ease=2.5`:
| Review | Grade | reps before | interval before | β reps after | β interval after |
|--------|-------|-------------|-----------------|--------------|-----------------|
| 1st | Good | 0 | 1 | 1 | 1 |
| 2nd | Good | 1 | 1 | 2 | 6 |
| 3rd | Good | 2 | 6 | 3 | 15 (round(6*2.5))|
## Constraints
- Max N=5 facts per session. If more are due, the user can run again.
- ONLY update files in `workspace/learning/facts/` and `workspace/learning/.state/review-log.jsonl`.
- Do NOT modify `deck` metadata files or any file outside these two locations.
- Do NOT skip the log write β even if the user types a grade quickly, always append to the log.
- If a fact file cannot be read (corrupted frontmatter), skip it and report: "β Fato {filename} ignorado β frontmatter invΓ‘lido."