Skip to content

Commit 53661d7

Browse files
committed
feat: replace SM-2 with FSRS-5, add enrich/feedback/analytics/sync, expand content rules to 14
1 parent 7077a2d commit 53661d7

27 files changed

Lines changed: 3429 additions & 975 deletions

.editorconfig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
root = true
2+
3+
[*]
4+
indent_style = space
5+
indent_size = 4
6+
end_of_line = lf
7+
charset = utf-8
8+
trim_trailing_whitespace = true
9+
insert_final_newline = true
10+
11+
[*.md]
12+
trim_trailing_whitespace = false
13+
14+
[*.{yaml,yml}]
15+
indent_size = 2
16+
17+
[Makefile]
18+
indent_style = tab
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Fix: Code Review Issues (5 items from diff review)
2+
3+
## Issues
4+
5+
1. `scripts/learn.py:137``n_modules = n` assigned but never used
6+
2. `scripts/learn.py:139``topic_lower = topic.lower().strip()` computed but never used
7+
3. `scripts/learn.py:358``_validate_deck_file()` defined but never called
8+
4. (NIT) Auto-discover test sort order — skip, cosmetic only
9+
5. (NIT) `cmd_epub` long signature — skip, readability only
10+
11+
## Fix Plan
12+
13+
### scripts/learn.py
14+
15+
**Line 137**: Delete `n_modules = n`
16+
17+
**Line 139**: Delete `topic_lower = topic.lower().strip()`
18+
19+
**Line 358-365**: Delete `_validate_deck_file()` entirely (unused dead code — `cmd_validate` does its own deck loading inline)
20+
21+
### No other changes
22+
23+
Tests pass as-is. These are dead code removals only.
24+
25+
## Verification
26+
27+
```bash
28+
python3 scripts/learn.py --help # still works
29+
python3 tests/test_learn.py # 59/59 pass
30+
```

AGENTS.md

Lines changed: 114 additions & 39 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# Learn Anything
22

3-
Structured learning framework for any subject — study via CLI with spaced repetition (SM-2). Three-theory pedagogy: Marva Collins, Feynman Technique, Desirable Difficulties.
3+
Structured learning framework for any subject — study via CLI with spaced repetition (FSRS-5). Three-theory pedagogy: Marva Collins, Feynman Technique, Desirable Difficulties.
44

55
## Features
66

77
- **Interactive curriculum creation**: LLM-driven syllabus + lesson + MCQ generation
88
- **CLI study system**: read lessons, Feynman explain-back, MCQ drills, spaced repetition
9-
- **SM-2 spaced repetition**: optimal recall intervals, mixed-module interleaving
9+
- **FSRS-5 spaced repetition**: optimal recall intervals, mixed-module interleaving
1010
- **Cost-effective**: ~$0.10 per course creation, $0 per study session
1111
- **Portable**: Markdown files importable into Anki, Obsidian, Notion
1212

@@ -24,7 +24,7 @@ learn.sh start <subject> Show overview + modules
2424
learn.sh quiz <subject> <mod> MCQ drill
2525
learn.sh explain <subject> <mod> Feynman technique prompt
2626
learn.sh feynman <subject> <mod> Alias for explain
27-
learn.sh review <subject> SM-2 spaced repetition
27+
learn.sh review <subject> FSRS-5 spaced repetition
2828
learn.sh stats <subject> Progress + retention
2929
learn.sh export <subject> Anki CSV export
3030
learn.sh epub <subject> [file] Export course to EPUB book
@@ -41,7 +41,7 @@ subjects/<topic>/
4141
│ │ └── quiz.yaml # 8-10 MCQs
4242
│ └── ...
4343
└── srs/
44-
├── deck.json # SM-2 card state
44+
├── deck.json # FSRS-5 card state
4545
└── stats.json # Study history
4646
```
4747

@@ -59,7 +59,7 @@ subjects/<topic>/
5959
|---------|----------|-------|
6060
| **LEARN** | 45-60 min | Read lesson, reframe, MCQ drill |
6161
| **EXPLAIN** | 15-20 min | Feynman explain-back, AI gap detection |
62-
| **REVIEW** | 10-15 min | SM-2 spaced repetition (daily) |
62+
| **REVIEW** | 10-15 min | FSRS-5 spaced repetition (daily) |
6363
| **MIXED** | 30-45 min | REVIEW + LEARN + EXPLAIN combined |
6464

6565
## EPUB Generation

SKILL.md

Lines changed: 91 additions & 21 deletions
Large diffs are not rendered by default.

content-verify.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Content Verification — Evidence-Based Quality Check
2+
3+
Load after each module generation. Verify against criteria below before presenting.
4+
5+
## Checklist (from Content Design Mod17)
6+
7+
- [ ] Concrete problem/example first, not abstract definition?
8+
- [ ] ≤2 concepts per section (~WM limit, CLT Mod2)?
9+
- [ ] Active engagement: cloze, predict, error-spot? (Retrieval Mod7, Feedback Mod12)
10+
- [ ] Immediate feedback after every exercise? (Feedback Mod12)
11+
- [ ] Non-redundant diagram for structure/relationships? (Dual Coding Mod6, Redundancy Effect CLT Mod2)
12+
- [ ] No extraneous fluff? (CLT Mod2 — extraneous load)
13+
- [ ] Builds on previous modules? (schema building, CLT Mod2)
14+
- [ ] Ends with retrieval opportunity (Feynman/Drill)? (Retrieval Mod7)
15+
16+
## Redundancy Effect Check
17+
18+
If same info appears through verbal AND visual channel simultaneously, mark violation:
19+
20+
| Violation | Example | Fix |
21+
|-----------|---------|-----|
22+
| Diagram repeats text paragraph | Paragraph describing flowchart + same flowchart | Remove paragraph. Diagram alone sufficient. |
23+
| Narration + identical on-screen text | "The heart pumps blood" written AND narrated | Use narration OR text, not both (Mayer redundancy principle). |
24+
| Separate legend for self-labeled diagram | "Fig 1: A=heart, B=lungs" when labels already on diagram | Remove legend. Integrate labels onto diagram (spatial contiguity). |
25+
26+
## Syntax Validation
27+
28+
- [ ] All code blocks opened with ``` are closed?
29+
- [ ] Heading hierarchy valid (no skipped levels)?
30+
- [ ] Mermaid blocks have valid diagram type keyword?
31+
- [ ] Mermaid `style` statements use valid hex colors?
32+
- [ ] Mermaid `subgraph`/`end` blocks paired?
33+
- [ ] Links `[text](url)` and images `![alt](src)` well-formed?
34+
- [ ] Bold `**` and italic `*` markers properly closed?
35+
- [ ] Table header/separator column counts match?
36+
37+
Run `learn.sh validate-content <topic> [module]` for automated checks.
38+
39+
## Design Strategies (use ≥2 per module)
40+
41+
| Strategy | Usage | Science |
42+
|----------|-------|---------|
43+
| **Chunking** | Break complex topics into 2-4 sub-topics per section | CLT Mod2 — WM ~4 chunk limit |
44+
| **Fading worked examples** | Full worked → partial (fill blanks) → independent | CLT Mod2 — worked example effect |
45+
| **Self-explanation prompts** | "Why does this step work?" after each claim | Deep Proc Mod5 — elaborative interrogation |
46+
| **Pre-training** | Introduce key terms before complex interaction | CLT Mod2 — reduced momentary intrinsic load |
47+
48+
## 14 Quality Rules Reference
49+
50+
| # | Rule | Science module |
51+
|---|------|----------------|
52+
| 1 | Explain conventions | CLT Mod2 (extraneous load) |
53+
| 2 | Answer implicit Qs | Deep Proc Mod5 (elaboration) |
54+
| 3 | Pull-to-par intuition | CLT Mod2 (causal chain) |
55+
| 4 | Causal chain first | CLT Mod2 + Deep Proc Mod5 |
56+
| 5 | Practical context | Deep Proc Mod5 (elaboration) |
57+
| 6 | "How likely" | Feedback Mod12 (prediction calibration) |
58+
| 7 | Common misconceptions | Error-Driven Learning Mod12 |
59+
| 8 | Socratic throughout | Deep Proc Mod5 (elaborative interrogation) |
60+
| 9 | Dual coding (non-redundant) | Dual Coding Mod6 + CLT Mod2 (redundancy) |
61+
| 10 | Concrete-first ordering | CLT Mod2 (schema building) |
62+
| 11 | Cloze deletions | Retrieval Practice Mod7 |
63+
| 12 | Predict-next | Error-Driven Learning Mod12 |
64+
| 13 | Error-spotting | Error-Driven Learning Mod12 |
65+
| 14 | Graduated examples | CLT Mod2 (fading worked examples) |
66+
67+
If any item fails, rewrite affected section. Cite violated principle.
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"$id": "https://learn-anything.dev/schemas/cumulative_question.json",
4+
"title": "Cumulative Quiz Question",
5+
"description": "Schema for a single cumulative quiz question (mcq, cloze, or tf)",
6+
"oneOf": [
7+
{ "$ref": "#/$defs/mcq" },
8+
{ "$ref": "#/$defs/cloze" },
9+
{ "$ref": "#/$defs/tf" }
10+
],
11+
"$defs": {
12+
"mcq": {
13+
"type": "object",
14+
"required": ["id", "type", "question", "source_modules", "options", "answer", "explanation", "difficulty", "tags"],
15+
"properties": {
16+
"id": {
17+
"type": "string",
18+
"pattern": "^cum\\.\\d+$",
19+
"description": "Question ID: cum.N"
20+
},
21+
"type": {
22+
"type": "string",
23+
"const": "mcq"
24+
},
25+
"question": {
26+
"type": "string",
27+
"minLength": 1,
28+
"description": "Question text"
29+
},
30+
"source_modules": {
31+
"type": "array",
32+
"items": { "type": "integer" },
33+
"minItems": 1,
34+
"description": "Module numbers this question covers"
35+
},
36+
"options": {
37+
"type": "object",
38+
"minProperties": 4,
39+
"maxProperties": 4,
40+
"additionalProperties": { "type": "string" },
41+
"description": "Answer options with uppercase keys: A, B, C, D"
42+
},
43+
"answer": {
44+
"type": "string",
45+
"enum": ["A", "B", "C", "D"],
46+
"description": "Correct answer key"
47+
},
48+
"explanation": {
49+
"type": "string",
50+
"description": "Why this answer is correct"
51+
},
52+
"difficulty": {
53+
"type": "integer",
54+
"enum": [1, 2, 3],
55+
"description": "1=recall, 2=comprehension, 3=application"
56+
},
57+
"tags": {
58+
"type": "array",
59+
"items": { "type": "string" },
60+
"description": "Content tags"
61+
}
62+
}
63+
},
64+
"cloze": {
65+
"type": "object",
66+
"required": ["id", "type", "question", "source_modules", "answer", "explanation", "difficulty", "tags"],
67+
"properties": {
68+
"id": {
69+
"type": "string",
70+
"pattern": "^cum\\.\\d+$",
71+
"description": "Question ID: cum.N"
72+
},
73+
"type": {
74+
"type": "string",
75+
"const": "cloze"
76+
},
77+
"question": {
78+
"type": "string",
79+
"description": "Sentence with {blank} for term to fill in"
80+
},
81+
"source_modules": {
82+
"type": "array",
83+
"items": { "type": "integer" },
84+
"minItems": 1,
85+
"description": "Module numbers this question covers"
86+
},
87+
"answer": {
88+
"type": "string",
89+
"description": "The term that fills the blank"
90+
},
91+
"explanation": {
92+
"type": "string",
93+
"description": "Why this term is correct"
94+
},
95+
"difficulty": {
96+
"type": "integer",
97+
"enum": [1, 2, 3],
98+
"description": "1=recall, 2=comprehension, 3=application"
99+
},
100+
"tags": {
101+
"type": "array",
102+
"items": { "type": "string" },
103+
"description": "Content tags"
104+
}
105+
}
106+
},
107+
"tf": {
108+
"type": "object",
109+
"required": ["id", "type", "statement", "source_modules", "answer", "explanation", "difficulty", "tags"],
110+
"properties": {
111+
"id": {
112+
"type": "string",
113+
"pattern": "^cum\\.\\d+$",
114+
"description": "Question ID: cum.N"
115+
},
116+
"type": {
117+
"type": "string",
118+
"const": "tf"
119+
},
120+
"statement": {
121+
"type": "string",
122+
"description": "Statement to evaluate as true or false"
123+
},
124+
"source_modules": {
125+
"type": "array",
126+
"items": { "type": "integer" },
127+
"minItems": 1,
128+
"description": "Module numbers this question covers"
129+
},
130+
"answer": {
131+
"type": "boolean",
132+
"description": "True if statement is correct, False if incorrect"
133+
},
134+
"explanation": {
135+
"type": "string",
136+
"description": "Why true/false, referencing concepts from source modules"
137+
},
138+
"difficulty": {
139+
"type": "integer",
140+
"enum": [1, 2, 3],
141+
"description": "1=recall, 2=comprehension, 3=application"
142+
},
143+
"tags": {
144+
"type": "array",
145+
"items": { "type": "string" },
146+
"description": "Content tags"
147+
}
148+
}
149+
}
150+
}
151+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"$id": "https://learn-anything.dev/schemas/cumulative_quiz.json",
4+
"title": "Cumulative Quiz",
5+
"description": "Schema for cumulative_quiz.yaml — cross-module quiz covering 3-5 modules",
6+
"type": "array",
7+
"items": { "$ref": "cumulative_question.schema.json" },
8+
"minItems": 8,
9+
"maxItems": 10
10+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* Cumulative Quiz Question — cross-module question types (mcq, cloze, tf).
3+
* Schema: https://learn-anything.dev/schemas/cumulative_question.json
4+
*/
5+
6+
export interface CumulativeMCQ {
7+
/** Question ID: cum.N */
8+
id: string;
9+
type: 'mcq';
10+
/** Question text */
11+
question: string;
12+
/** Module numbers this question covers */
13+
source_modules: number[];
14+
/** Answer options with uppercase keys: A, B, C, D */
15+
options: Record<string, string>;
16+
/** Correct answer key */
17+
answer: 'A' | 'B' | 'C' | 'D';
18+
/** Why this answer is correct */
19+
explanation: string;
20+
/** 1=recall, 2=comprehension, 3=application */
21+
difficulty: 1 | 2 | 3;
22+
/** Content tags */
23+
tags: string[];
24+
}
25+
26+
export interface CumulativeCloze {
27+
/** Question ID: cum.N */
28+
id: string;
29+
type: 'cloze';
30+
/** Sentence with {blank} for term to fill in */
31+
question: string;
32+
/** Module numbers this question covers */
33+
source_modules: number[];
34+
/** The term that fills the blank */
35+
answer: string;
36+
/** Why this term is correct */
37+
explanation: string;
38+
/** 1=recall, 2=comprehension, 3=application */
39+
difficulty: 1 | 2 | 3;
40+
/** Content tags */
41+
tags: string[];
42+
}
43+
44+
export interface CumulativeTF {
45+
/** Question ID: cum.N */
46+
id: string;
47+
type: 'tf';
48+
/** Statement to evaluate as true or false */
49+
statement: string;
50+
/** Module numbers this question covers */
51+
source_modules: number[];
52+
/** True if statement is correct, False if incorrect */
53+
answer: boolean;
54+
/** Why true/false, referencing concepts from source modules */
55+
explanation: string;
56+
/** 1=recall, 2=comprehension, 3=application */
57+
difficulty: 1 | 2 | 3;
58+
/** Content tags */
59+
tags: string[];
60+
}
61+
62+
/** Discriminated union of all cumulative question types */
63+
export type CumulativeQuestion = CumulativeMCQ | CumulativeCloze | CumulativeTF;
64+
65+
/** Cumulative quiz is an array of cross-module questions */
66+
export type CumulativeQuiz = CumulativeQuestion[];
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export type { SRSCard } from './card';
22
export type { SRSDeck } from './deck';
33
export type { QuizQuestion, Quiz } from './question';
4+
export type { CumulativeQuestion, CumulativeMCQ, CumulativeCloze, CumulativeTF, CumulativeQuiz } from './cumulative_question';
45
export type { Syllabus, SyllabusModule } from './syllabus';
56
export type { SessionStats, StudySession } from './stats';
67
export type { Feedback, ModuleRating, ContentFlag } from './feedback';

0 commit comments

Comments
 (0)