Claude Learner

Install

What Learner needs, the ways in, what lands where, and which platforms can run it.

Requirements

Claude Code plugin

claude plugin marketplace add Tykok/learning-with-claude
claude plugin install learner@learning-with-claude

Installs and enables the skills and their hooks natively — no ~/.claude file copying, no learner-install step. Claude Code manages updates itself (/plugin update learner); run learner update and it will tell you the same thing rather than trying to curl a second, traditional install on top. Already installed via curl, clone, Homebrew, or apt? Run uninstall.sh (or learner-uninstall) first — running both wires every hook twice.

apt (Debian/Ubuntu)

# one time
curl -fsSL https://tykok.github.io/learning-with-claude/apt/learner.gpg \
  | sudo gpg --dearmor -o /usr/share/keyrings/learner.gpg
echo "deb [signed-by=/usr/share/keyrings/learner.gpg] https://tykok.github.io/learning-with-claude/apt stable main" \
  | sudo tee /etc/apt/sources.list.d/learner.list

# from then on
sudo apt update && sudo apt install learner
learner-install --level S --synthesis normal --blanks 2

One curl remains — fetching the repository's trust anchor once, the same pattern Docker's and HashiCorp's own apt repos use. There is no keyless way to establish that first trust, but after this one-time step, sudo apt update && sudo apt upgrade learner is the whole update story — no more curl involved, ever.

Prefer not to add a repository? Grab the .deb directly from Releases instead:

curl -LO https://github.com/Tykok/learning-with-claude/releases/download/v0.3.0/learner_0.3.0_all.deb
sudo apt install ./learner_0.3.0_all.deb
learner-install --level S --synthesis normal --blanks 2

v0.3.0 is this release. Check Releases for the current version if you're reading this after a newer one has shipped.

Homebrew

brew install tykok/tap/learner
learner-install --level S --synthesis normal --blanks 2

A personal tap (Tykok/homebrew-tap), not homebrew-core. Each tagged release updates it.

Both apt and Homebrew only stage the files and drop learner-install / learner-uninstall on PATH — neither touches ~/.claude on its own. Run learner-install afterward, same flags as install.sh below. Uninstalling reverses the same way: sudo apt remove learner / brew uninstall learner only remove those two wrapper binaries — the payload under ~/.claude still needs learner-uninstall (same as uninstall.sh) to actually come out.

Clone and run

A first-class path, not a fallback: it is the one that lets you read the installer before you run it.

git clone https://github.com/Tykok/learning-with-claude
cd learning-with-claude
./install.sh                       # prompts for level / synthesis / blanks
./install.sh --dry-run             # print what would happen, write nothing
./install.sh --yes                 # never prompt; defaults for anything unset
./install.sh --level S --synthesis normal --blanks 2    # non-interactive, one shot

To install a release rather than whatever main says today, clone its tag: git clone --depth 1 --branch v0.5.0 https://github.com/Tykok/learning-with-claude. There is no path that pipes a download into a shell: every install runs an install.sh you have on disk and can read first.

The installer is idempotent: re-running re-copies the hooks and the skills and re-merges the hook wiring without duplicating entries, and it never overwrites a config you already have. It writes nothing into any repository. Every path it touches is under $CLAUDE_CONFIG_DIR (default ~/.claude), and every wired hook command carries the literal ${CLAUDE_CONFIG_DIR:-$HOME/.claude} rather than an expanded path, so moving your config directory later needs no reinstall.

Hook wiring is read once, when a Claude Code session starts. Installing (or re-installing) while a session is already open changes nothing in it — quit and start a new session for the hooks to take effect.

What gets installed, and where

Everything lives under $CLAUDE_CONFIG_DIR, written $CFG below.

PathRole
$CFG/skills/learner/SKILL.mdThe learner hub skill: dispatch, levels, config
$CFG/skills/learner/references/The two shared protocols: hook-quiz.md, data.md
$CFG/skills/{quiz,status,improve,coach,export,update}/One skill per subcommand, each holding its own protocol. A plugin install exposes the same directories as /learner:quiz and friends
$CFG/skills/learner/VERSIONThe installed version string; re-copied unconditionally on every install/re-install, so it always matches what's on disk
$CFG/skills/learner/INSTALL_ORIGINHow this install got here — curl, brew or apt; re-stamped on every install/re-install
$CFG/skills/pilot/SKILL.mdThe pilot skill: dispatch, the four axes, the privacy paragraph
$CFG/skills/pilot/references/The protocols: rubric.md, score.md, brief.md, dashboard.md, mechanisms.md
$CFG/hooks/learner-config.shShared config resolution — sourced-only, never run on its own
$CFG/hooks/learner-onboard.shSessionStart — reports a broken install and nothing else
$CFG/hooks/learner-update-check.shSessionStart (second entry) — notifies once a day when a newer version is out; no jq dependency
$CFG/hooks/coach-gate.shPreToolUse on Write/Edit/NotebookEdit — refuses writes outside the delegated slice, when coach mode is on
$CFG/hooks/learner-record-edit.shPostToolUse on Write/Edit — records the files edited this session
$CFG/hooks/learner-quiz.shStop — the quiz trigger, and the LEARNER-TODO guardrail
$CFG/hooks/learner-cleanup.shSessionEnd — deletes this session's scratch files
$CFG/hooks/coach-watch.shNo static entry — armed as a Monitor by learner-onboard.sh at session start, when coach mode is on; runs the review cadence
$CFG/hooks/coach-armed-check.shUserPromptSubmit (second entry) — warns, at most once per session, when coach mode is on but the watcher was never armed
$CFG/hooks/pilot-record.shSessionEnd (second entry, timeout 15) — turns one finished transcript into one line of delegation counters, when Pilot is enabled
$CFG/hooks/pilot-brief.shSessionStart (third entry) — decides whether a scoring pass, a weekly brief, or neither is due
$CFG/hooks/pilot-nudge.shUserPromptSubmit — reminds the dev of a live Pilot manoeuvre; never exits 2, so it can never block or erase a prompt
$CFG/hooks/learner-sync.shUtility — carries the learning record (memory.md, recap.md, learner.json) between machines through a private gist
$CFG/hooks/learner-agent-track.shCounts the subagents in flight so the salvo knows when you are waiting
$CFG/hooks/learner-event.shUtility — the only writer of learner/events.jsonl, the append-only event log the Learner IDE extensions read
$CFG/settings.jsonHook wiring, merged in; a .bak of the pre-Learner file is kept beside it
$CFG/learner.jsonYour global config
$CFG/learner/Empty directory, created by the installer: the skill writes memory.md, recap.md and export.json into it at runtime, and the update-check hook writes its throttle stamp (.last-update-check) there too
$CFG/learner/memory.mdOpen weak spots — the only file read to choose a question. Created by the skill on first use, not by the installer
$CFG/learner/recap.mdReadable dashboard: to improve, mastered, session history. Also created on first use
$CFG/learner/events.jsonlAppend-only event log (one line per question asked, answered, skipped or abandoned) read by the Learner IDE extensions; written only by learner-event.sh, never holds code. Created on the first question
$CFG/learner/export.jsonWhich Notion database learner export pushes to, and when it last ran. Created on the first export, not by the installer
$CFG/learner/pilot-queueOne line per finished session awaiting a scoring pass, written by pilot-record.sh; truncated once drained. Only when Pilot is enabled
$CFG/learner/pilot.mdThe Pilot dashboard: Sessions, Index and Manoeuvres blocks. Written by a scoring subagent, never by the installer
$CFG/learner/pilot-evidence.mdThe quotes behind each numeric score, capped at 200 characters each and fully purgeable with pilot forget
$CFG/learner/pilot-stampsscore=/brief=/declined= timestamps that pace the scoring pass and the weekly brief
$CFG/learner/pilot-devlinesPer-session line tallies from the coach watcher, consumed and truncated by the scoring pass
$CFG/learner/sync.jsonGist id and last push/pull times for learner sync. Created on the first sync, not by the installer
$CFG/learner/sync-base/The state both sides last agreed on — the ancestor for the next learner sync merge
$CFG/learner/backups/<timestamp>/A copy of the local record taken before every learner sync pull writes anything

Fifteen hook files ship and twelve are wired, into SessionStart (three times — learner-onboard.sh, learner-update-check.sh and pilot-brief.sh all fire there), PreToolUse (coach-gate.sh on the Write|Edit|NotebookEdit matcher, plus learner-agent-track.sh --start on its own Task matcher), PostToolUse (learner-record-edit.sh on Write|Edit, plus learner-agent-track.sh --end on Task), Stop, SessionEnd (twice — learner-cleanup.sh and pilot-record.sh, the latter at a raised timeout of 15 since it reads a whole transcript) and UserPromptSubmit (twice — pilot-nudge.sh and coach-armed-check.sh). Three ship unwired: learner-config.sh is sourced-only, and Claude Code never invokes it directly; coach-watch.sh is never a static entry either — learner-onboard.sh arms it as a Monitor at session start, only once coach mode is on; and learner-sync.sh is never wired to a hook event at all — the skill invokes it directly, only when the dev types learner sync. Twelve of the other thirteen source learner-config.sh — every hook but learner-cleanup.sh, which needs none of it.

Platforms

PlatformSupportedNotes
macOSyesneeds jq
Linuxyesneeds jq
Windows via WSLyesit is a Linux environment
Windows via Git Bashyesprovides the POSIX sh the hooks need
Windows, nativenothe hooks are POSIX sh scripts; with no POSIX shell, Claude Code cannot run them

Native Windows is a genuine gap rather than an untested platform. Every hook is a POSIX sh script and each is wired as sh "…", so without a POSIX shell on the machine there is nothing for Claude Code to execute. WSL and Git Bash both supply one, and on either of them Learner behaves exactly as it does on Linux.

Next: Usage — the three shapes a question takes.