Learner
Ask the dev questions about the code they just wrote, at their level, and keep a
record of what they should level up on.
Language: mirror the dev. Write every question, feedback line and summary in the
language the dev is using in this conversation. There is no language setting.
Dispatch
learner <subcommand> [args] — the subcommand is the first token of $ARGUMENTS.
| Subcommand |
Mode |
Read |
quiz [base-ref] [count] |
Q&A over the current branch diff |
references/quiz.md |
status |
Read-only summary: level + what to improve |
this file, § Status |
improve [topic] |
Coach one weak spot to mastery |
references/improve.md |
coach on / coach off |
Turn the coach regime on/off in this repo |
references/coach.md |
coach delegate <glob> … |
Let Claude write inside those globs this session; none clears |
references/coach.md |
coach review [base-ref] |
Run one review now, off-cadence |
references/coach.md |
export [notion-page-url] |
Push the recap into a Notion database |
references/export.md |
update |
Check the remote version; re-run bootstrap.sh pinned to it if newer |
references/update.md |
config [key=value …] |
View/edit settings; config project … scopes to this repo |
this file, § Config |
off / on |
Disable/enable the automatic quiz in this repo |
this file, § Config |
help (or -h, --help) |
Print this dispatch table + the parameter table, then stop |
— |
| (empty) |
Same as config with no pairs: show current settings |
this file, § Config |
A bare config instruction with no subcommand (level=S, disable) is config shorthand.
Invoked by the Stop hook. The hook blocks with a trigger line of the form
🎓 Learner (level: S, mode: granular, styles: auto, blanks: 2) — files: a.kt b.kt.
When you see it, read references/hook-quiz.md and follow it with those values. Do not
treat the trigger as the protocol — it is only parameters.
Invoked by the coach watcher. A Monitor armed at session start blocks with
🧑🏫 Coach (level: S, cycle: 3, files: 2, lines: 62) — Service.kt Mapper.kt. When you see it,
read references/coach.md and follow it with those values. As with the quiz trigger, the line is
parameters, not the protocol.
Levels
The canonical value is the letter. Accept the full word and any case as an alias.
| Letter |
Name |
What a question targets |
Register (coach) |
D |
Discovering |
syntax, what a block is for, basic vocabulary |
name and explain each term before using it |
J |
Junior |
what the function does, where the code lives |
everyday vocabulary, a concrete example over an abstraction |
C |
Competent |
why this split, edge cases, error handling |
standard jargon assumed, basics not re-explained |
S |
Senior |
trade-offs, rejected alternatives, perf and coupling impact |
dense, allusive, no unrequested explanation |
E |
Expert |
invariants, failure modes, what breaks at scale |
context assumed, a discussion between equals |
Config
Two layers, later wins key by key:
$CLAUDE_CONFIG_DIR/learner.json (default ~/.claude/learner.json) — the dev's
defaults for every repo.
<repo>/.claude/learner.local.json — optional, gitignored, partial override.
| Key |
Values |
Default |
Effect |
level |
D/J/C/S/E |
— required |
Question difficulty |
enabled |
bool |
true |
Master switch for the automatic quiz |
questionStyles |
"auto" or subset of code/architecture/fill |
"auto" |
Allowed formats |
synthesisFrequency |
off/rare/normal/often |
normal |
Synthesis question every 0/8/4/2 questions |
blanksPerExercise |
int ≥ 1 |
2 |
// LEARNER-TODO holes in a fill exercise |
untrackGlobs |
array of globs |
[] |
Extra paths excluded from quiz material |
disabledPaths |
array of path prefixes |
[] |
Repos where learner stays silent |
coach |
bool |
false |
Coach regime: the dev writes, Claude challenges |
coachCadence |
pomodoro/threshold |
pomodoro |
Which clock drives reviews |
coachWorkMinutes |
int ≥ 1 |
25 |
First work block, in minutes |
coachWorkGrowthMinutes |
int ≥ 0 |
5 |
Added to the work block per completed cycle |
coachWorkMaxMinutes |
int ≥ 1 |
45 |
Work-block ceiling |
coachChallengeMinutes |
int ≥ 0 |
8 |
Challenge window, fixed |
coachIdleCycles |
int ≥ 1 |
2 |
Empty work blocks before the watcher stops |
coachPollSeconds |
int ≥ 5 |
45 |
Poll interval — threshold cadence only |
coachLines |
int ≥ 1 |
40 |
Lines since last review that trigger one — threshold only |
coachFiles |
int ≥ 1 |
3 |
Changed files that trigger one — threshold only |
coachEveryMinutes |
int ≥ 0 |
0 |
Elapsed-time trigger, 0 = off — threshold only |
coachCooldownMinutes |
int ≥ 0 |
5 |
Floor between two reviews — threshold only |
Styles: code = what a changed function does; architecture (alias archi) = which
module/layer it lives in and why; fill = interactive fill-in exercise in the real
source file (see references/hook-quiz.md).
To edit: read the target file, merge the new values over the existing ones, validate
(level in the five letters; enabled boolean; questionStyles "auto" or a subset;
synthesisFrequency one of the four words; ints ≥ 1; the two glob keys arrays of
non-empty strings; coach boolean; coachCadence one of the two words; every coach*
integer at or above the floor in the table above), write it, then confirm with
jq -e . <file> >/dev/null && echo OK. Reject invalid values and re-ask instead of
writing them. coachWorkMaxMinutes below coachWorkMinutes clamps to coachWorkMinutes
rather than being rejected — the intent of that pair is unambiguous. config alone edits
the global file; config project …, off and on
edit <repo>/.claude/learner.local.json and add that path to the repo's .gitignore
if it is missing. Those are the only writes into a repo.
Status
Read-only: no quiz, no config write, no data-file update.
- Level and version:
jq -r '.level // "not set"' "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/learner.json"
(a project override wins if present), and
cat "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/skills/learner/VERSION" 2>/dev/null — unless this
skill's own base directory (visible in your context when it loaded) contains /plugins/,
in which case report the version as plugin-managed instead: a plugin install never
creates that file, and Claude Code's own /plugin command is the source of truth for which
version is installed.
- Open weak spots: read the
To improve sections of the recap (see
references/data.md for paths). If nothing is recorded, say so and suggest learner quiz.
- Print one line for the level and version, then one line for coach status — on/off, the
current cycle if a coach session is running, and the delegated globs read from
$TMPDIR/claude-learner-<session-id>.coach-scope when that file exists — then a handful of
bullets: broad competency themes grouped by domain, skipping anything already under
Mastered. Summarise; never dump the file. No tables, no history.
1---2name: learner3description: Learner4---56# Learner78Ask the dev questions about the code they just wrote, at their level, and keep a9record of what they should level up on.1011**Language: mirror the dev.** Write every question, feedback line and summary in the12language the dev is using in this conversation. There is no language setting.1314## Dispatch1516`learner <subcommand> [args]` — the subcommand is the first token of `$ARGUMENTS`.1718| Subcommand | Mode | Read |19|------------|------|------|20| `quiz [base-ref] [count]` | Q&A over the current branch diff | `references/quiz.md` |21| `status` | Read-only summary: level + what to improve | this file, § Status |22| `improve [topic]` | Coach one weak spot to mastery | `references/improve.md` |23| `coach on` / `coach off` | Turn the coach regime on/off in this repo | `references/coach.md` |24| `coach delegate <glob> …` | Let Claude write inside those globs this session; `none` clears | `references/coach.md` |25| `coach review [base-ref]` | Run one review now, off-cadence | `references/coach.md` |26| `export [notion-page-url]` | Push the recap into a Notion database | `references/export.md` |27| `update` | Check the remote version; re-run `bootstrap.sh` pinned to it if newer | `references/update.md` |28| `config [key=value …]` | View/edit settings; `config project …` scopes to this repo | this file, § Config |29| `off` / `on` | Disable/enable the automatic quiz in this repo | this file, § Config |30| `help` (or `-h`, `--help`) | Print this dispatch table + the parameter table, then stop | — |31| *(empty)* | Same as `config` with no pairs: show current settings | this file, § Config |3233A bare config instruction with no subcommand (`level=S`, `disable`) is `config` shorthand.3435**Invoked by the Stop hook.** The hook blocks with a trigger line of the form36`🎓 Learner (level: S, mode: granular, styles: auto, blanks: 2) — files: a.kt b.kt`.37When you see it, read `references/hook-quiz.md` and follow it with those values. Do not38treat the trigger as the protocol — it is only parameters.3940**Invoked by the coach watcher.** A `Monitor` armed at session start blocks with41`🧑🏫 Coach (level: S, cycle: 3, files: 2, lines: 62) — Service.kt Mapper.kt`. When you see it,42read `references/coach.md` and follow it with those values. As with the quiz trigger, the line is43parameters, not the protocol.4445## Levels4647The canonical value is the letter. Accept the full word and any case as an alias.4849| Letter | Name | What a question targets | Register (coach) |50|--------|------|-------------------------|------------------|51| `D` | Discovering | syntax, what a block is for, basic vocabulary | name and explain each term before using it |52| `J` | Junior | what the function does, where the code lives | everyday vocabulary, a concrete example over an abstraction |53| `C` | Competent | why this split, edge cases, error handling | standard jargon assumed, basics not re-explained |54| `S` | Senior | trade-offs, rejected alternatives, perf and coupling impact | dense, allusive, no unrequested explanation |55| `E` | Expert | invariants, failure modes, what breaks at scale | context assumed, a discussion between equals |5657## Config5859Two layers, later wins key by key:60611. `$CLAUDE_CONFIG_DIR/learner.json` (default `~/.claude/learner.json`) — the dev's62 defaults for every repo.632. `<repo>/.claude/learner.local.json` — optional, gitignored, partial override.6465| Key | Values | Default | Effect |66|-----|--------|---------|--------|67| `level` | `D`/`J`/`C`/`S`/`E` | — required | Question difficulty |68| `enabled` | bool | `true` | Master switch for the automatic quiz |69| `questionStyles` | `"auto"` or subset of `code`/`architecture`/`fill` | `"auto"` | Allowed formats |70| `synthesisFrequency` | `off`/`rare`/`normal`/`often` | `normal` | Synthesis question every 0/8/4/2 questions |71| `blanksPerExercise` | int ≥ 1 | `2` | `// LEARNER-TODO` holes in a `fill` exercise |72| `untrackGlobs` | array of globs | `[]` | Extra paths excluded from quiz material |73| `disabledPaths` | array of path prefixes | `[]` | Repos where learner stays silent |74| `coach` | bool | `false` | Coach regime: the dev writes, Claude challenges |75| `coachCadence` | `pomodoro`/`threshold` | `pomodoro` | Which clock drives reviews |76| `coachWorkMinutes` | int ≥ 1 | `25` | First work block, in minutes |77| `coachWorkGrowthMinutes` | int ≥ 0 | `5` | Added to the work block per completed cycle |78| `coachWorkMaxMinutes` | int ≥ 1 | `45` | Work-block ceiling |79| `coachChallengeMinutes` | int ≥ 0 | `8` | Challenge window, fixed |80| `coachIdleCycles` | int ≥ 1 | `2` | Empty work blocks before the watcher stops |81| `coachPollSeconds` | int ≥ 5 | `45` | Poll interval — `threshold` cadence only |82| `coachLines` | int ≥ 1 | `40` | Lines since last review that trigger one — `threshold` only |83| `coachFiles` | int ≥ 1 | `3` | Changed files that trigger one — `threshold` only |84| `coachEveryMinutes` | int ≥ 0 | `0` | Elapsed-time trigger, `0` = off — `threshold` only |85| `coachCooldownMinutes` | int ≥ 0 | `5` | Floor between two reviews — `threshold` only |8687Styles: `code` = what a changed function does; `architecture` (alias `archi`) = which88module/layer it lives in and why; `fill` = interactive fill-in exercise in the real89source file (see `references/hook-quiz.md`).9091To edit: read the target file, merge the new values over the existing ones, validate92(`level` in the five letters; `enabled` boolean; `questionStyles` `"auto"` or a subset;93`synthesisFrequency` one of the four words; ints ≥ 1; the two glob keys arrays of94non-empty strings; `coach` boolean; `coachCadence` one of the two words; every `coach*`95integer at or above the floor in the table above), write it, then confirm with96`jq -e . <file> >/dev/null && echo OK`. Reject invalid values and re-ask instead of97writing them. `coachWorkMaxMinutes` below `coachWorkMinutes` clamps to `coachWorkMinutes`98rather than being rejected — the intent of that pair is unambiguous. `config` alone edits99the global file; `config project …`, `off` and `on`100edit `<repo>/.claude/learner.local.json` and add that path to the repo's `.gitignore`101if it is missing. Those are the only writes into a repo.102103## Status104105Read-only: no quiz, no config write, no data-file update.1061071. Level and version: `jq -r '.level // "not set"' "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/learner.json"`108 (a project override wins if present), and109 `cat "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/skills/learner/VERSION" 2>/dev/null` — unless this110 skill's own base directory (visible in your context when it loaded) contains `/plugins/`,111 in which case report the version as `plugin-managed` instead: a plugin install never112 creates that file, and Claude Code's own `/plugin` command is the source of truth for which113 version is installed.1142. Open weak spots: read the `To improve` sections of the recap (see115 `references/data.md` for paths). If nothing is recorded, say so and suggest `learner quiz`.1163. Print one line for the level and version, then one line for coach status — on/off, the117 current cycle if a coach session is running, and the delegated globs read from118 `$TMPDIR/claude-learner-<session-id>.coach-scope` when that file exists — then a handful of119 bullets: broad competency themes grouped by domain, skipping anything already under120 `Mastered`. Summarise; never dump the file. No tables, no history.