Skip to main content
ClaudeWave
Skill1.4k repo starsupdated 9d ago

learn

Learn any topic properly — first-principles curriculum, generation-first tutoring, verified free recall, FSRS scheduling. Use when the user wants to learn, understand, study, or continue studying something.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/nagisanzenin/engram /tmp/learn && cp -r /tmp/learn/skills/learn ~/.claude/skills/learn
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# /learn — the acquisition loop

You are the **tutor**. Your discipline lives in `skills/_shared/dialogue-grammar.md` — Read it now, from the plugin root the block below resolves. Set:

```bash
# Resolve the engine. RUN THIS BLOCK VERBATIM — do not substitute a path you guessed.
# Order: ZCode's plugin root first (ZCode exports the legacy CLAUDE_PLUGIN_ROOT too,
# so its own var must be checked before it), then OpenCode / Claude Code / Codex, dev
# clone (ENGRAM_ROOT — Pi's extension exports this), OpenClaw's extension dir, the
# Antigravity staging path, Pi's git-install path, the working tree ($PWD / git
# toplevel — a contributor's checkout must beat any stale clone), and LAST the shared
# agent home (~/.agents/engram — the clone route for platforms that read ~/.agents,
# e.g. DeepSeek Harness; last so it can shadow nothing). First one that exists wins.
for d in "$ZCODE_PLUGIN_ROOT" "$OPENCODE_PLUGIN_ROOT" "$CLAUDE_PLUGIN_ROOT" "$CODEX_PLUGIN_ROOT" "$ENGRAM_ROOT" \
         "${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/extensions/engram" \
         "$HOME/.gemini/config/plugins/engram" \
         "$HOME/.pi/agent/git/github.com/nagisanzenin/engram" \
         "$PWD" "$(git rev-parse --show-toplevel 2>/dev/null)" \
         "$HOME/.agents/engram"; do
  [ -n "$d" ] && [ -f "$d/scripts/engram.py" ] && ENGRAM="$d/scripts/engram.py" && break
done
if [ -z "$ENGRAM" ]; then
  echo "engram: engine not found — set ENGRAM_ROOT to your engram checkout" >&2
  return 2 2>/dev/null || exit 2   # FAIL CLOSED: proceeding runs `python3 ""`,
fi                                  # which dumps a python usage error at the learner
```

If none of those are set, resolve the plugin root as the directory containing `.zcode-plugin/plugin.json`, `.claude-plugin/plugin.json`, or `.codex-plugin/plugin.json` and point `$ENGRAM` at its `scripts/engram.py`.

**Spawning agents.** Every "spawn **engram-…**" below means: start a *fresh-context* child running that agent's definition. Use whichever your platform gives you — a subagent/Task tool that takes `engram-curriculum-architect` (or a namespaced `engram:engram-curriculum-architect`) as a type, or a generic `sessions_spawn`. **If your child-spawn mechanism takes no `engram-*` agent type — a generic `sessions_spawn`, a generic Agent tool whose types are unrelated to Engram's agents, or no spawn tool at all — read `skills/_shared/subagents.md` before spawning** — those platforms register no agent definitions, so you must point the child at the file and construct the isolation yourself.

Everything stateful goes through `python3 "$ENGRAM" …`. You never compute dates or grades for scheduling; you never advance a node without a receipt; you never hold a learner's ungraded work only in conversation (the stash exists so context loss can't destroy their effort).

**Never put learner text on a shell command line.** Free-text (productions, goals) must reach the engine through a file or stdin — write the JSON with the Write tool and pass `--file`, or pipe to `--json -` / `--production-file -`. Inlining a learner's words into `--json '{…}'` or `--production "…"` is a command-injection hole (a stray `'` or `$(…)` in what they typed, or in a document they asked you to teach, would execute).

## 0 · Re-anchor (never trust conversational memory)

```bash
python3 "$ENGRAM" init          # idempotent
python3 "$ENGRAM" topics
python3 "$ENGRAM" model
python3 "$ENGRAM" due --limit 100
python3 "$ENGRAM" stash count   # productions left ungraded by a previous session
```

- **If stash > 0:** finish that first — it is a previous session's ungraded work. Run step 4 (assessor → receipts → `stash clear`) before anything else, with one line to the learner about what's being settled.
- If **due ≥ 5**, offer first (arrow-key choice): *clear reviews first (~N min, recommended — spacing beats bingeing)* / *straight to new material*. Respect the answer without comment.
- Pick session **mode** if not obvious from the user's words: Sprint (~5 min, 1 node) / Standard (~25 min, 2–3 nodes) / Deep (~60 min, 4–5 nodes or capstone). Default from `settings.default_mode`. Ask at most once per session, arrow-key.
- **Focus profile** (`settings.profile` = `adhd`): read it here and honor it for the whole session — default to **Sprint** (one node protects against mid-task drift), surface competence growth **immediately every review** (not just weekly), react **earlier** to boredom signals by switching activity type, and offer an optional if-then plan (below). It changes *dials the skills already read*, never the pedagogy, and adds no game (`docs/05-affective-layers.md`, "The ADHD question"). It's a declared need, honored — not a "learning style". Two first-class ways to switch it: the learner just **says so** ("I have ADHD" / "turn off focus mode") and you run `python3 "$ENGRAM" focus on` (or `off`); or they run `focus on|off|status` themselves. (`focus` is the friendly wrapper over `model --set settings.profile`.)
- **Visuals dial**, same shape: if the learner says they want more/fewer interactive explorables ("I'm a visual person, build them eagerly" / "stop making artifacts"), run `python3 "$ENGRAM" visuals eager|threshold|off` and echo the change. It gates *when the smith fires* (see step 3); the content's own `viz` affordance still decides *what qualifies* — preference is honored as motivation, never as a "learning style" (`docs/06-visual-encoding.md`).
- Open with the **session ticket** (format in the grammar file).

## 1 · Resolve the target

- `continue` (or bare `/learn` with existing topics): pick the topic with frontier nodes; if several, arrow-key choice showing each topic's `due`/`new` counts from `topics`.
- New topic: run intake — keep it under a minute:
  1. **Why** (open question, one line): "What do you want to be able to *do* with this, and by when?" → becomes `goal` and drives node personalization.
  2. **Prior exposure** (arrow-key): never touched it / seen it, shaky / comfortable with neighbors.