Full Stack · AI
StudyForge
Notes in, durable memory out — with or without AI.
- 695 tests
- FSRS-6 verified against reference
- MIT
01The problem
Most study tools ask you to trust them.
Flashcard apps make you write the cards. “AI study tools” make you trust a model you cannot inspect — and stop working when the API key runs out.
StudyForge takes the material you already have, does the tedious part deterministically, and is honest about the difference between “the document says X is defined as Y” and “I understand X.” It runs on your machine, stores everything in one SQLite file, and is fully functional with no AI configured at all.
02From notes to durable memory
Notes
Paste text or upload .txt, .md and PDFs. Text is normalised — hyphenation rejoined, hard wraps unwrapped, page numbers removed — then split at semantic boundaries.
Understanding
Concepts are extracted from evidence actually present in the text: definition sentences, glossary lines, headings, repeated terms — each scored by how much that evidence proves.
Review
Deterministic flashcards and quizzes, scheduled by FSRS-6. The queue prioritises overdue reviews, then due ones, then the concepts you keep getting wrong.
Learning
Accuracy, due counts, and weak-concept analysis computed from what you actually did — with every percentage showing the sample it came from.
03Zero-cost, and useful with no AI
Zero-cost, and useful with no AI
AI_PROVIDER=none is the default. Two capabilities are marked never uses AI, by design rather than “not implemented”: scheduling and weak-concept classification are arithmetic, and
handing them to a probabilistic text generator would make them unreproducible and untestable —
so a language model cannot reach either one.
If you want AI, Ollama runs models locally — nothing leaves your machine. StudyForge never downloads a model for you; if the configured one is missing it says so and carries on with the deterministic path.
04The study engine
A schedule you can reproduce is a schedule you can trust.
The FSRS-6 implementation is ~150 lines of closed-form arithmetic in the hottest path of the product. Owning it means the rules are reviewable and covered by the project’s own tests: the forgetting-curve identities, the four-rating ordering, the spacing effect, and difficulty clamping under 50 consecutive failures.
Before being frozen, the implementation was verified against the reference FSRS implementation across 4,096 review transitions — and the verification script ships in the repository, so anyone can rerun it. The engine reads no clock and holds no state; the caller supplies the time.
05Honest by construction
Honest by construction
The interface refuses to imply knowledge it does not have:
- a concept answered twice is “not enough data”, not “mastered”
- every percentage shows its sample — 88%, from 8 answers
- a rate with no data renders as —, never as 0%
- every generated card links back to the exact passage it came from
- every status label has a written definition, shown next to it in the UI
06Inside the product
Inside the product
07Engineering decisions
Engineering decisions
- SQLite, deliberately
-
Local-first means no server and no connection string, and FTS5 gives full-text search with
nothing extra installed. Foreign keys and WAL are enabled explicitly at connect time,
because SQLite ships with FK enforcement off — without that, the declared
ondeleterules would be inert. - HTMX rather than React
- Almost every interaction is server-driven: rate a card and the server decides what comes next. A SPA would add a build step, a second data model and a hydration boundary to solve a problem this application does not have.
- No vector database
- At one person’s scale, FTS5 is the right tool. Adding embeddings and a vector store to search a few thousand paragraphs would be architecture for its own sake.
- The domain layer imports nothing
- The FSRS engine, chunking, extraction, generation, and queue building import nothing from SQLAlchemy, FastAPI or any AI provider. That is what makes the algorithms exhaustively testable — and what guarantees no model can reach the scheduler.
08Testing
695 tests, including the unfriendly ones.
Coverage includes golden vectors for the scheduler, determinism assertions (chunking, extraction, generation and queue building produce identical output across repeated runs), and a security suite: path traversal, content-type spoofing, XSS through every user-controlled field, FTS and SQL injection, and error disclosure. Every AI failure mode is tested against a mock transport — CI never contacts a live model.
09Stack and links
Stack and links
Python 3.12 · FastAPI · Jinja2 + HTMX · SQLAlchemy 2 (typed) · Alembic · SQLite + FTS5 ·
Pydantic 2 · pypdf · uv · Ruff · mypy --strict · pytest · Playwright · GitHub Actions.
Repository · Study-engine verification · Privacy model · Architecture