A Claude Code plugin for AI-assisted learning: a teaching method that produces lecture notes, graded checks with instant feedback, verified diagrams, and a lesson log that fills an Obsidian note live.
Ported from amosblomqvist/learn,
which is built as a .pi configuration for the pi coding agent. Pi extensions
can register tools and draw their own terminal UI; Claude Code plugins cannot,
so the two interactive pieces (quiz and md-log) are rebuilt on Claude Code
primitives — AskUserQuestion for the question UI, hooks for grading, and a
small script the model writes notes through. The teaching philosophy, the
visualize skill and the three subagents carry over largely as they are.
| Skill | Invocation | What it does |
|---|---|---|
teach |
/learn:teach <topic> |
The teaching method: one calibration question, a plan with a dependency map from unconditional truths, then lecture notes section by section — practical by default, no math unless the topic is math — with a graded check only where a section needs one. Turns the lesson log on. |
quiz |
/learn:quiz <topic> |
Graded multiple-choice questions through AskUserQuestion, one at a time, adapting difficulty to each answer. Every graded question gets a Skip row. |
md-log |
/learn:md-log [path | on | off] |
Link a markdown file as the lesson log and turn logging on or off. |
visualize |
(used by teach) |
Adds one correct, minimal diagram to a lesson via a maker subagent that renders it and looks at the result. |
Subagents: researcher (web research for fact-checking), mermaid-maker,
svg-maker. The makers render through npx — Mermaid via
@mermaid-js/mermaid-cli (downloads a headless Chromium on first use), SVG via
@resvg/resvg-js-cli.
An Obsidian vault is a folder of markdown, so the log is written straight into it — no Obsidian plugin, no MCP server.
/learn:md-log ~/path/to/Vault/Lessons/dp.md
Keep the note open in Obsidian; its file watcher re-renders on every write. The note is the handout, the terminal is the lecture hall. Three things land in the note, each the moment it happens:
| In the note | How it gets there |
|---|---|
| Lesson content — sections, examples, recaps, the plan and its mermaid map, diagram embeds | The model writes it with mdlog.py note <<'MDLOG' … MDLOG, which appends when the command runs. Markdown, LaTeX and mermaid render natively. |
> [!question] Quiz — … |
A PreToolUse hook writes every AskUserQuestion as a question box before you're asked, options numbered as shown in the terminal. |
> [!success] Quiz — correct ✓ / > [!failure] Quiz — incorrect ✗ / > [!question] Quiz — I don't know / > [!example] Answer |
A PostToolUse hook grades your pick the instant you answer. Skipping removes the question box again. |
Nothing else is mirrored — not reply text, not prompts, not tool output.
The first version mirrored reply text from the session transcript. That can't be live: Claude Code persists reply text to the transcript late and unevenly (text emitted mid-turn often isn't there until the turn ends, while tool calls land promptly), so lesson sections showed up in Obsidian long after they were on screen, sometimes after the check that followed them. A tool call is immediate and deterministic, so lesson content goes through one. The teaching skill treats that as the format: sections go to the handout, the terminal carries only cues, questions and verdicts.
AskUserQuestion has no notion of a correct answer, so the model ends a quiz
question with a marker:
What does TCP add on top of IP?
<!-- answer: 2 -->
The PreToolUse hook removes it before the question is shown (via
updatedInput), shuffles the options so the key isn't positional, appends a
Skip row (graded questions carry 2–3 real options so it fits in
AskUserQuestion's four), and grades the answer when it comes back, telling
the model the verdict and displayed order through additionalContext.
Skipping retracts the question box and tells the model to move on without
comment. idk in the free-text "Other" slot is logged as a gap rather than a
wrong answer; 2 — guessing is graded as a pick of 2 with the note passed
along.
Under ~/.claude/plugin-data/learn/ (a fixed path, so it survives plugin
updates and reinstalls):
active-log— the linked file. Remembered across sessions.sessions/<id>.json— per session: whether logging is on, and the grading key for questions in flight.
Logging starts off in every new session so ordinary work never touches
the note; /learn:md-log on (or a path, or entering /learn:teach) turns it
on. When it's off, note prints its text instead of writing it, so a lesson
never silently vanishes. Resumed and compacted sessions keep their state.
Editing the note by hand while a lesson is running can lose a write: Obsidian saves its own buffer over whatever arrived mid-edit. Reading is fine.
To see exactly what the hooks receive, touch ~/.claude/plugin-data/learn/debug
and read debug.log there; remove the flag when done.
Local marketplace during development:
/plugin marketplace add /path/to/learn
/plugin install learn@jayden-local
Requires python3 (any 3.9+) for the log and node/npx for the diagram makers.