I’ve been trying to learn things more deliberately lately — actually retaining stuff rather than just reading and forgetting. Flashcard apps exist, but they all have the same problem: someone has to write the cards. I don’t want to write cards. I want to specify a topic and be drilled on it immediately.
So I built tutor-cli: a terminal-based study tutor that generates its own question bank via the OpenAI API, then runs you through adaptive practice sessions using seven different learning methods.
How it works
You run bun run index.ts, enter a topic, and the tutor either loads a previously saved question bank or generates a new one. Generation takes 15–30 seconds and produces a full set of questions in questions.json — so subsequent sessions on the same topic start instantly.
From there you pick a mode:
- Adaptive session — the tutor picks method and difficulty for you based on your history
- Manual session — you choose which learning method to use
- View stats — per-method performance breakdown
- Regenerate — throw out the current question bank and generate a fresh one
The whole thing runs in your terminal with no web UI, no account, no sync service. It’s just a process and two JSON files.
Seven learning methods
The tutor doesn’t just ask questions in one way. It rotates between seven distinct methods:
| Method | What happens |
|---|---|
| Flashcard | Classic Q&A — see the question, recall the answer, self-grade |
| Cloze Deletion | Fill in the blank in a sentence with a key term removed |
| Q&A Drill | Open-ended question; your answer is graded by the LLM |
| Self-Explanation | Explain a concept from memory; LLM evaluates your explanation |
| Quiz | Multiple choice, True/False, or short answer |
| Matching | Pair terms with their definitions |
| Sequencing | Order steps or events in the correct sequence |
Having multiple methods matters more than it sounds. The same piece of knowledge feels completely different when you’re asked to recognize it in a multiple-choice question versus recall it cold or explain it in your own words. Method variety is actually one of the stronger findings in learning science — interleaving keeps the brain engaged in a way that pure repetition doesn’t.
Adaptive difficulty and method selection
Both difficulty and method selection adjust based on performance, independently.
Difficulty runs on a 1–5 scale and is recalculated based on your recent accuracy. Do well and the questions get harder; struggle and they ease off. It’s not a dramatic mechanic — just a quiet adjustment that keeps the session calibrated to where you actually are.
Method selection weights are updated separately. If you’re consistently struggling with Sequencing questions and breezing through Flashcards, the tutor shifts the session distribution to give you more Sequencing. Methods you’ve effectively mastered get scheduled less often until you need a refresher.
Spaced repetition
Individual cards are tracked using the SM-2 algorithm — the same algorithm that powers Anki. Each card has an interval and an ease factor that update after every review based on how well you recalled it. Cards you know well get reviewed less frequently; cards you’re shaky on come back sooner.
The state for all of this lives in progress.json alongside per-topic aggregate stats. Close the terminal, come back tomorrow, and the tutor picks up exactly where it left off.
The code
The project is TypeScript on Bun. The structure is fairly clean:
index.ts – main flow and session loop
state.ts – shared types: TutorState, Question, LearningMethod
adaptive.ts – difficulty and method-weight adaptation logic
callLlm.ts – OpenAI client wrapper
questions.ts – question generation and persistence
progress.ts – progress load/save helpers
methods/ – one file per learning method
plugins/cli.ts – readline-based CLI helpers
Each learning method is its own file, which made it easy to add new ones without touching anything else. The CLI helpers in plugins/cli.ts are a thin wrapper around readline — just ask(), print(), and hr(). Everything that talks to OpenAI goes through callLlm.ts, so swapping the model or the provider is a one-line change.
The LLM does two things: generate the initial question bank when you give it a topic, and grade open-ended answers for the Q&A Drill and Self-Explanation methods. The rest of the logic — difficulty tracking, method weights, spaced repetition scheduling — is all local.
Setup
git clone https://github.com/Fanna1119/tutor-cli
cd tutor-cli
bun install
Create a .env file:
OPENAI_API_KEY=your_key_here
Then:
bun run index.ts
You need Bun 1.2+ and an OpenAI API key. That’s it.
What I’d add next
A few things I’ve been thinking about:
- Multiple topics in one session — right now each session is single-topic; mixing cards from different topics is how spaced repetition apps usually work at scale
- Import/export — being able to share a
questions.jsonso others can study the same bank without generating their own - Custom question injection — letting you add cards manually alongside the AI-generated ones
- Model config — currently hardcoded to
o4-mini; making this configurable would let you trade cost against quality
For now it does exactly what I built it to do: give me something to study without making me write the material myself.