Claude Learner

Usage

The three shapes a question can take, and what you can ask Learner for directly.

The three question styles

code
What a specific changed function does.
architecture (alias archi)
Which module, directory or layer the code lives in, and why that is where it belongs.
fill
The interactive exercise above: holes cut in the real file, filled in by you.

questionStyles takes either "auto", the default, or a subset of those three. "auto" varies the format from one question to the next, picking whichever fits what changed. Naming a subset restricts it — set it to ["code"] and no exercise will ever touch a file; set it to ["fill"] if writing code back is the only feedback you trust.

There is no setting for the language of the questions. Claude mirrors whatever you are writing in the conversation.

On demand

Everything above happens on its own, once per turn. The same learner skill also answers when you ask it directly — invoke it as learner <subcommand>:

learner quiz [base-ref] [count]
Q&A over the current branch diff, right now, instead of waiting for the Stop hook — optionally against a named base ref, for a chosen number of questions.
learner status
Read-only: your level, plus what to improve — the record the lede above promises, read back to you on request. No quiz, no write.
learner improve [topic]
Coaches one weak spot — named, or the most open one on record — to mastery.
learner export [notion-page-url]
Pushes the recap into a Notion database — one row per competency theme, with a learning level derived from your session history. Needs the Notion connector; the parent page URL is asked for once, on the first export, and remembered after that.
learner sync push / pull [gist] / status / use <gist>
Carries your learning record between machines through a private gist. See Sync below.
learner events import
Backfills events.jsonl, the append-only log the Learner IDE extensions read, from your recap.md Session history — a one-time catch-up for history recorded before the log existed. Ordinary quiz and coach sessions write to it on their own; safe to run more than once.
learner update
Checks the remote version and, if it is newer, re-runs the installer pinned to it. Safe to run any time — a no-op when you are already current.
learner config [key=value …]
Views or edits settings. learner config project … scopes the edit to the current repository instead of the global default; with no arguments it prints your current settings.
learner off / learner on
Silences or restores the automatic quiz in the current repository. See Turning it off for what that writes and why.
learner pilot …
Forwards the rest of the line to the separate, opt-in pilot skill — a delegation-habit score read from your sessions themselves, off by default. Reachable directly too, as plain pilot ….
learner help
Prints its subcommand and parameter reference, then stops.

Coach mode — you write, Claude challenges

The regime above has Claude write the code and quiz you afterwards. Coach mode inverts it: you write the code, and Claude watches your working tree and comes back after you pause typing with one to three socratic questions, up to three findings anchored file:line, and up to two leads — never a patch. Your level drives both what the challenge attacks and the register it is written in.

learner coach on / learner coach off
Turns the coach regime on or off in this repository. Off is the default — a dev who never runs this sees no change. Once on, Claude is denied write access to your source: a PreToolUse hook refuses any Write, Edit or NotebookEdit outside the slice you delegate below, and hands back a copy-pasteable glob in the refusal.
learner coach delegate <glob> …
Lets Claude write inside the given globs for this session, e.g. learner coach delegate 'src/**/repository/**' — the layer that looks the same in every project, leaving you the service and the business logic. learner coach delegate none clears it.
learner coach review [base-ref]
Runs one coach review right now, off-cadence, instead of waiting for the watcher.

A review fires when you pause typing: the watcher polls your working tree every coachPollSeconds, and once it has seen coachQuietPolls consecutive quiet polls with at least coachMinLines changed since the last review, it fires — floored by coachCooldownMinutes so a run of short pauses does not turn into a run of interruptions, and forced anyway past coachMaxWaitMinutes so a long uninterrupted stretch doesn't wait for the day's end to get a review. Zero changes for coachIdleMinutes and the watcher stops itself and asks whether you want to continue. See Configuration for the seven coach* keys that tune all of this.

A review is sized by the diff it is reviewing, not fixed in advance: a small change gets one question — the challenge — and nothing else; a larger one may add a question about a third-party library actually in play, and, past a size threshold, a question about how the change is split across files. One or two questions arrive together, in the same message; only when a review earns all three are they asked one at a time — say there are three, ask the first, wait for your answer, then the next, never all three stacked in one message. Alongside the questions, the review may open with a one-line confirmation of a genuinely good decision it found in the diff (silence otherwise — an empty compliment teaches nothing), and it closes with findings anchored file:line and leads for what comes next. Once you answer, Claude teaches: the concept, the pitfall, the parameters that matter — never a patch, never a snippet built from your own code.

Both regimes feed the same record: Claude quizzes you on what it wrote, the coach challenges you on what you wrote, and learner status sees all of it.

Coach mode needs an interactive Claude Code session: the watcher runs as a Monitor, which does not exist in claude -p, in a subagent, or in a cloud session. The write refusal above still applies everywhere, because it is an ordinary hook — so a non-interactive session with coach mode on gets the denials without ever receiving a review. When the watcher cannot be armed there, the UserPromptSubmit check says so once, rather than leaving you to guess why no review ever arrives.

Pilot — a delegation score, read from the transcript

Pilot is a separate, opt-in skill, off by default (pilotEnabled: false), that scores how much of the thinking on a task you handed to Claude versus did yourself. It never asks you a question to produce that score — everything it reports comes from the sessions you already had, read straight from the transcript, never from a prompt written to test you.

Four axes, each scored 0–4 per session and rolled into a 0–100 rolling index:

direction
Did you set the target and the constraints, or ask for "something that works"?
verification
Did you read what came back — evidenced by naming something concrete from it: a function, a line, a branch of the logic?
contradiction
Did you ever object, correct, or ask why?
writing
Did you write any of the code yourself? Exact when the session's coach tally covers everything a plain git diff still finds in the working tree; estimated from that diff otherwise — including under coach mode itself, on the block a watcher cycle never got to measure, since a tally alone is a lower bound, not a guaranteed total, and git alone cannot say who typed what beyond it; and, for a session held outside any git repository at all, not scored rather than guessed at zero — a dash, not a low score.

The three axes above (not writing, which never gates it) settle into one of six profiles once each has enough assessable sessions behind it — Pilot, Co-pilot, Observer, Backseat, Cargo, Passenger — but no profile is named off two or three sessions: until the floor is met, the dashboard shows the axes it does have and says so instead of guessing.

Pilot measures a habit, not you: it is not a measure of intelligence and not a measure of cognitive health. A score is a model reading a transcript against a written rubric, the same instrument that scores the exercises above — a defensible signal about a pattern in how a task got delegated, not a clinical or cognitive claim about the person who delegated it.

Once a day, if sessions are waiting, a subagent judges them against the rubric and writes the result to your dashboard — never inside the session being judged. Every axis score carries one supporting quote from the transcript; a score with no quote to show for it is recorded as not-assessable, never as a zero. Once a week (pilotCadenceDays by default), Claude opens a weekly brief after answering your first request of that session, never instead of it: the facts with no adjectives, one question about what pushed you there that week, one mechanism from the advice corpus that matches your weakest axis, and one counter-manoeuvre negotiated with an expiry — never two live manoeuvres at once, never a lecture, and "not now" defers it without penalty.

pilot (bare)
Renders the dashboard: index per axis, profile (once there is enough data), and the active manoeuvre, if any.
pilot on / pilot off
Prints the privacy paragraph below in full, then flips pilotEnabled. Reachable as learner pilot on too.
pilot brief
Runs the weekly brief right now, off-cadence.
pilot score
Drains the scoring queue right now, off-cadence.
pilot why <date>
Shows the quotes behind that row's scores.
pilot forget [--all|--before <date>]
Purges stored quotes — every one, or every one before a date.

Privacy — read this before turning it on. Pilot reads every prompt you have typed, in every repository, including ones where the automatic quiz above is switched off — that is exactly why it defaults to off and stays opt-in rather than a setting you would stumble into. Everything stays local: the transcript is referenced by path and never copied, and the judgement that turns a session into scores runs in a subagent on this machine — nothing about it leaves that Claude Code itself was not already sending.

Sync — carry your record between machines

learner sync moves your learning record — memory.md, recap.md and the global learner.json — between machines through one private GitHub gist. It is the only path that ever sends the record off the machine, and it is manual only: no hook pushes anything, on any machine; nothing leaves until you type it.

learner sync push
Snapshots the local record to the gist. The first push asks before creating it, and creates it --secret. A secret gist is unlisted, not access-controlled: anyone who has the URL can read it, without a GitHub account — it carries your repo names, file names and the wording of your weak spots, plus pushedFrom (the machine_name plugin option, if set), learner.json's disabledPaths (absolute local paths) and events.jsonl (the text of every question you were asked and each repo's absolute path), so treat the link like a password.
learner sync pull [gist-url]
Backs up the local record first, to ${CLAUDE_CONFIG_DIR:-$HOME/.claude}/learner/backups/<timestamp>/, then three-way merges memory.md — a line you deleted here because you mastered it stays deleted, even if the other side still has it — unions the Session history table, and lets Claude merge the theme sections. Name a gist URL the first time you pull on a new machine; after that it is remembered.
learner sync status
Read-only: the gist URL, when you last pushed and pulled, and what is not pushed yet.
learner sync use <gist-url>
Repoints this machine at a different gist — for a dev who already has one from another machine.

learner export (Notion) is unaffected by any of this: it stays the human-readable view of your record, not a restore path. The gist carries the raw state, and needs gh and a GitHub token you hand over — a fine-grained token with only the Gists permission: the github_token plugin option (stored in your system keychain), or LEARNER_GITHUB_TOKEN for a curl, Homebrew or apt install. Learner never reads the credential gh auth login stored. Worth making a habit: learner sync push before you switch machines, so the record you left behind is the one you pick back up.

Agent salvo — questions while the subagents work

When Claude hands work to subagents, the main conversation would otherwise go quiet. It owes you a short burst instead, once per dispatched agent: two questions — about the delegation itself, the branch diff, the code those agents are about to touch, or an open weak spot — then one fill-in exercise cut in your own code. Three agents dispatched at once earn three salvos, served one per turn as you answer. The moment the last agent returns, the unserved ones are dropped: the queue never trails into work that has resumed.

The exercise is cut by a dedicated agent launched while you answer the questions, so it is ready when you get to it. You will see it start with a description beginning learner-prep: — that prefix is a contract, not a label: the salvo deliberately does not count its own preparation agent as an agent to quiz you about.

In coach mode the salvo is questions only. Cutting the exercise needs a write, and coach-gate.sh denies it — the barrier is not weakened for the learner's convenience.

One limitation, stated where you will hit it: if your client runs subagents synchronously, the salvo lands just after the result instead of during the wait. The questions are still asked; only the overlap is lost. No hook fires when a subagent starts, so there is no mechanism that does better.

learner config agentSalvo=false
Turns the salvo off. On is the default: it costs nothing in a session that dispatches no agent.
learner config agentSalvoQuestions=1
Questions per salvo, before the exercise. 0 means exercise only.
learner config agentSalvoFill=false
Questions only, no exercise.

Next: Configuration — every setting Learner reads.