Inspiration
I kept catching myself doing the thing every student does: re-read the notes, feel confident, blank two days later. Psychologists call that feeling fluency, and the research is brutal about it. Retrieval practice beats re-reading, and tutoring students to mastery before letting them advance beats almost everything else. Almost no study tool enforces either one. So I built one that does, and made it stubborn about it.
What it does
The Forge takes any topic, or your own PDFs and notes, and builds a first-principles curriculum. It teaches one concept, takes the lesson away, and quizzes you from memory. Score under 0.8 and you don't advance. It re-teaches from a new angle (an analogy, a worked example, a misconceptions pass) and quizzes you again until you clear the bar. Every answer tunes a spaced-repetition schedule to your own forgetting curve rather than an average one. At the end of a session it prints you a receipt: what you learned, your weakest concept, and when it will ambush you next.
It runs entirely on your machine with Ollama, or with an Anthropic API key if you'd rather not install a local model. No cloud, no telemetry, one SQLite file.
How we built it
Python 3.12 with exactly one dependency (LangGraph), SQLite for all state, a stdlib web server, and a vanilla-JS dashboard. Four agents run in a loop: a Synthesizer teaches, an Inquisitor quizzes, an Evaluator grades, an Orchestrator schedules reviews. The part I care most about is the grading floor. A deterministic keyword heuristic always runs underneath the LLM grader, so a dead or hallucinating model can never pass you. There's also an eval harness with 17 golden sessions that tests the teaching pipeline itself. Its LLM-judge column prints a dash until a human calibrates it, because a fabricated quality score is worse than none.
Challenges we ran into
The bug I'm most glad I caught: my grading tokenizer only matched Latin characters, so Hindi key points matched nothing and a Hindi learner would have been trapped at the mastery gate forever. Another one: the streaming parser silently swallowed mid-generation error frames, so a truncated lesson could get stored and quizzed as if it were complete. Both surfaced in adversarial review passes I ran against my own code, which convinced me those passes are worth the time.
My favorite failure was testing the live API myself. I fed it textbook-correct answers about spaced repetition and scored 0.07, because the gate wants you to reconstruct the lesson it actually taught, not recite nearby knowledge. It can't be bribed. I checked.
Accomplishments that we're proud of
Clone the repo, run one setup script, and you're answering your first quiz inside two minutes; my install harness fails CI if that ever regresses past 120 seconds. The suite is 95 offline tests that run in about twelve seconds, and CI covers macOS, Ubuntu, two Python versions, a Docker image, and a fresh-install simulation on every push. I'm also quietly proud that the whole thing has one dependency. Every framework I didn't add is a thing that can't break.
And it teaches in Spanish and Hindi. The tokenizer fix that made Hindi grading possible is the commit I'd show anyone who asks what this project taught me.
What we learned
Honest measurement is a feature. Everywhere the system doesn't know something, it prints a dash instead of a plausible guess, and that one discipline caught more bugs than any framework would have. I also learned that the review pass you don't want to run is the one that finds the real bug. Every severity-one issue in this project came out of an adversarial pass I almost skipped.
What's next for Forge
First, the boring one: publish to PyPI so install drops from clone-and-script to a single uvx command. Then the one I actually want: voice mode already works with local whisper.cpp, so the near-term goal is answering quizzes out loud on a commute, hands free. After that, a household mode with several learner profiles on one machine, which is how this becomes useful for a family or a classroom without me running any servers. The scheduler upgrade to FSRS waits until there are about a thousand real reviews to fit it against, because tuning it on synthetic data would just be guessing with extra steps.
Built With
- anthropic
- claude
- docker
- fts5
- github-actions
- javascript
- langgraph
- ollama
- pwa
- python
- sqlite
- whisper.cpp