@bojackduy/opencode-learn
v1.4.5
Published
Pi learn system for OpenCode — Socratic teaching, graded quiz, Obsidian md_log, and visual makers. Port of amosblomqvist/learn (video: How I Use AI to Learn Things) to OpenCode.
Maintainers
Readme
opencode-learn
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.
Why
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
What's inside
| 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|500]] |
| extensions/quiz | plugins/learn.ts:quiz + quiz_batch | Graded single|multi + I don't know + note, shuffled, correctAnswer by value, TUI durable pendingDir opencode-visual-tools |
| 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.
Honour & reference
- 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.
Install
Plugin — simple (no installer)
Add to both configs (opencode needs server + TUI):
~/.config/opencode/opencode.jsonc — server (learn + visual):
{ "plugin": ["@bojackduy/opencode-learn"] }~/.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"] }Installer — skills + agents + plugins in one command
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 # removeManual
Copy plugins/, agents/, skills/teach, skills/visualize into ~/.config/opencode/ and add plugin entries above.
Usage
Mirror to Obsidian
/md_log /path/to/note.md # file must exist — backfills history, mirrors YOU/OPENCODE/Quiz as callouts, LaTeX $…$
/md_unlogView 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)Publishing (template from @bojackduy/opencode-loopd)
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.
Requirements
- OpenCode
>=1.18+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.
License
AGPL-3.0-or-later — see LICENSE. Original learn is personal, shared as-is by Amos. Original pi remains MIT.
Credits
- 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)
