tutor-cli: An AI Study Tutor That Lives in Your Terminal

I built a CLI that generates a question bank on any topic, then drills you using seven different learning methods — with adaptive difficulty, spaced repetition, and persistent progress between sessions.

I’ve been trying to learn things more deliberately lately, actually retaining stuff instead of reading and forgetting. Flashcard apps exist, but they share one problem: someone has to write the cards. I don’t want to write cards. I want to name a topic and get drilled on it right away.

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 to 30 seconds and produces a full set of questions in questions.json, so later sessions on the same topic start instantly.

From there you pick a mode:

  • Adaptive session: the tutor picks the method and difficulty for you based on your history
  • Manual session: you choose which learning method to use
  • View stats: a 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 recognize it in a multiple-choice question versus recall it cold or explain it in your own words. Method variety is one of the stronger findings in learning science, and interleaving keeps the brain engaged in a way pure repetition doesn’t.

Adaptive difficulty and method selection

Both difficulty and method selection adjust based on performance, independently.

Difficulty runs on a 1 to 5 scale and is recalculated from your recent accuracy. Do well and the questions get harder; struggle and they ease off. It isn’t 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 with the SM-2 algorithm, the same one 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 come back less often; shaky ones 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 provider is a one-line change.

The LLM does two things: generate the initial question bank from 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, and mixing cards across topics is how spaced repetition apps usually work at scale
  • Import/export: sharing a questions.json so others can study the same bank without generating their own
  • Custom question injection: adding cards manually alongside the AI-generated ones
  • Model config: it’s currently hardcoded to o4-mini, and making it 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.