Pi learn system for OpenCode — teaching that locks in, not just delivers.
Port of the
pilearn harness to OpenCode. Original system by Amos Blomqvist from How I Use AI to Learn Things (thumbnail:piby Mario Zechner /earendil-works/pi).
Quiz TUI — multi-select Which of these are rare earth elements? with ☐ 1.Cerium → ☑, I don't know — genuine gap, Note (optional) Tab-to-edit, 0 selected → ↳ Submit (Space toggle, ↓ to Submit → Enter). Durable pendingDir survives kill.
Two brains can hold the same facts — one as disconnected lone facts, the other as a dependency graph where every fact is derivable from a few core truths. Teaching here builds that graph: nodes (unconditional truths) → edges (motivated discovery, 3Blue1Brown-style how could I have discovered this?).
- Probe → Plan → Teach — every session locates your edge (graded
quizprobes), scopes goal (nativequestion), plans DAG, then teaches node-by-node withquiz-check. - Verifies, not hallucinates —
researchersubagent (tasksubagent_type=researcher) before any shaky claim. - Logs to Obsidian —
md_logmirrorsYOU/OPENCODE/Quiz/Questionas> [!quote]/> [!abstract]/> [!question|success|failure]callouts, LaTeX$…$rendered in Obsidian.viz/PNGs embed as![[viz-*.png|500]].
Keywords: opencode opencode-plugin learn teach quiz md-log obsidian 3blue1brown socratic
Pi original amosblomqvist/learn |
Opencode port personal/.opencode |
Notes |
|---|---|---|
skills/teach/SKILL.md |
skills/teach/SKILL.md |
quiz + native question (custom ask removed to cut hallucination, question is single source), task researcher |
skills/visualize/SKILL.md |
skills/visualize/SKILL.md |
task subagent_type=mermaid-maker/svg-maker + `![[filename |
extensions/quiz |
plugins/learn.ts:quiz + quiz_batch |
Graded `single |
extensions/ask-user-question |
removed — use native question |
One less tool → less overhead/hallucination |
extensions/md-log |
plugins/learn.ts:md_log/md_unlog opencode.json:md_log |
> [!quote] YOU / > [!abstract] OPENCODE + backfill client.session.messages + chat.message/experimental.text.complete/tool.execute |
extensions/visual-tools mermaid/svg |
plugins/learn.ts:write_mermaid/edit/render + write_svg/edit/render |
STAGING_ROOT=tmp/opencode-visual-tools, Chrome+mmdc / rsvg-convert→magick, viz/ publish |
agents/researcher mermaid-maker svg-maker |
agents/{researcher,mermaid-maker,svg-maker}.md |
researcher safe_bash → bash:ask in opencode; makers get write_*/render_* at primary (* :allow) per user choice |
Plus plugins/learn-tui.tsx — modal TUI QuizDialog/QuizBatchDialog (4-state hit/miss/false-alarm/correct-rejection success/error/warning solid bg inverted, 0a/15 lighter, ○/✓/✗), durable pendingDir .opencode/learn-pending watch+poll 700ms + hb 2s .tui-alive. v1 + v2 hosts supported via per-host modules (learn-v1/learn-v2, lazy entry) with mouse/keyboard hover parity, theme-accent ramp handling, and free-text note → AI classify on both.
- Pi — Mario Zechner —
picoding agent /earendil-works/pi— the runtime this port targets away from. - Learn system — Amos Blomqvist —
amosblomqvist/learn— the teaching philosophy (unconditional truths,how could I have discovered this?) and thequiz/ask/md-log/visual-toolsharness. This port keeps theprobe→plan→teachDAG andresearcherverification verbatim. - Video — How I Use AI to Learn Things (
assets/thumbnail.pngin original) — watch first.
This is a personal port, shared as-is. Original
learnis for one learner (Amos) — editskills/teach/SKILL.mdto fit you.
Add to both configs (opencode needs server + TUI):
~/.config/opencode/opencode.jsonc — server (learn + visual):
~/.config/opencode/tui.json — TUI (learn-tui):
{ "plugin": ["@bojackduy/opencode-learn"] }Use the bare package name in both files, not @bojackduy/opencode-learn/tui//server —
opencode already picks the right export (./tui vs ./server) based on which host loads it.
A scoped-package spec with a /tui or /server suffix is silently broken: npm-package-arg
parses the second slash as a local directory reference instead of a package+subpath reference,
so the plugin never resolves or activates, with no error logged anywhere.
Restart OpenCode. Verify /md_log, quiz, write_mermaid appear in tool list.
Local checkout:
// opencode.jsonc
{ "plugin": ["./path/to/personal/.opencode"] }
// tui.json
{ "plugin": ["./path/to/personal/.opencode/plugins/learn-tui.tsx"] }npx -y @bojackduy/opencode-learn@latestInstalls:
plugin→opencode.jsonc/tui.json(package spec@bojackduy/opencode-learn@<version>)agents/→~/.config/opencode/agents/{researcher,mermaid-maker,svg-maker}.mdskills/→~/.config/opencode/skills/{teach,visualize}/SKILL.md+marker-pdf-parser/notebooklm-lecture-notescommands/→~/.config/opencode/commands/{md_log,md_unlog}.md(if present)
Re-run to update. Then restart OpenCode.
Uninstall:
npx -y @bojackduy/opencode-learn@latest --uninstallOr global:
npm i -g @bojackduy/opencode-learn@latest
opencode-learn # install
opencode-learn --uninstall # removeCopy plugins/, agents/, skills/teach, skills/visualize into ~/.config/opencode/ and add plugin entries above.
Mirror to Obsidian
/md_log /path/to/note.md # file must exist — backfills history, mirrors YOU/OPENCODE/Quiz as callouts, LaTeX $…$
/md_unlog
View in Obsidian — viz/ PNGs embed as ![[viz-*.png|500]], mermaid $$…$$.
Quiz — probe & check
quiz(question="What is 2+2?", options=[{label:"3"}, {label:"4"}], correctAnswer="4", explanation="…")
quiz_batch(quizzes=[{question:"…", options:[…], correctAnswer:["Red","Blue"], explanation:"…", multiSelect:true}])
Single → TUI popup QuizDialog (single/multi + I don't know + note). Batch → deck 1/3→3/3 QuizBatchDialog (same 4-state hit/miss/false-alarm/correct-rejection solid bg inverted). Both durable pendingDir .opencode/learn-pending — kill opencode mid-popup → re-show on restart.
Quiz dialogs are asynchronous. The agent must call quiz or quiz_batch alone, end that assistant turn once the dialog is displayed, and continue only after the TUI injects the learner's answer.
Open forks: native question (single/multi Other).
Visual — one correct picture
task(subagent_type="mermaid-maker", prompt="graph TD: packet → ordering → reliable stream, 3 nodes only")
# → returns filename: viz-packet-*.png → embed ![[viz-*.png|500]] (md_log mirrors)
This harness follows opencode-loopd's npm + installer template (~/Code/opencode-loopd):
package.json—name:@bojackduy/opencode-learnversionbin:opencode-learn=scripts/install-node.mjsfiles:[plugins,agents,skills,commands,dist]publishConfig access publicpeerDependencies @opencode-ai/pluginscripts/install-node.mjs— idempotentopencode.jsonc/tui.jsonpluginarray rewrite (keeps comments,formatPluginArray),OPENCODE_CONFIG_DIRoverride,commands/*.md+skills/*copy,--uninstallpurge,ensureDependency@opencode-ai/plugin.tsconfig.json+bun build→dist/fortui(solid) if needed,prepack: bun run typecheck && bun test && bun run build.
Release:
bun run typecheck && bun test && bun run build
npm version patch -m "chore: release %s" && git push && git push --tags
# GH Action .github/workflows/npm-publish.yml on v*.*.* → npm publish --access public + gh releaseSee ~/Code/opencode-loopd/{package.json,scripts/install-node.mjs,.github/workflows/npm-publish.yml,README.md#Install} as template.
- OpenCode v1 (
>=1.18) and v2 — dual compatible (server + TUI:learn-v1for.tui,learn-v2for.setup) +bun >=1.1 ask-user-questionnot needed — nativequestionused- Visual:
Chrome(/Applications/Google Chrome.app/...) +@mermaid-js/mermaid-cli(bundled) orrsvg-convert/magickfor SVG.viz/inside vault.
AGPL-3.0-or-later — see LICENSE. Original learn is personal, shared as-is by Amos. Original pi remains MIT.
- Mario Zechner —
piagent, TUI, extension API - Amos Blomqvist —
learnteaching system,quiz/md-log/visual-tools, video + repo - Port to OpenCode —
personal/.opencodelearn+learn-tui(visualSTAGING_ROOTopencode-visual-tools,OPENCODEblock,questiondedup,quiz_batchbeautifulQuiz i/N)

{ "plugin": ["@bojackduy/opencode-learn"] }