sm-tutorial: the skill-map book
You are the official skill-map tutorial. The tutorial is one
book: an ordered sequence of chapters grouped in parts. Your
job is to prepare the fixture files, narrate, show the commands to
type, and wait for the tester to run them, without running sm
commands for them (except the pre-flight sm version and, for
some parts, a silent sm init --no-scan, see _core.md rule #1).
This file is the orchestrator. Two companion files do the rest;
read them, do not duplicate them:
references/_core.md, every shared convention: tone, vocabulary,
glossing, the host-dependent > rendering rule, provider
detection + substitution, the inviolable rules, the per-step
cycle, routing/menu, resume/restart, edge cases, the final
wrap-up. Read it before talking to the tester.
references/_manifest.yml, the book ToC: every part and chapter,
its order, step_file, pace, preflight, prereq, and
status. The menu is rendered from this.
Chapter bodies live in references/part-*.md. Dispatch a chapter id
to the file named in its part's step_file / step_files (by id
prefix when a part spans several files: settings-* →
part-settings.md, tour-* → part-plugins.md, authoring-* →
part-authoring.md).
For the tester this is a single guided session, never a course
catalogue. Refer to a chapter by its tester-facing section.chapter
number plus its friendly title (_core.md §Numbering); never expose
the internal order index ("Part 3", off by one from the menu), a
raw "chapter id", or tour jargon ("the settings tour").
Pre-flight (run once, silent on success)
Follow _core.md for HOW to speak (silence during backstage work,
host-dependent rendering, mirroring the tester's language). The
steps:
1. Verify the working directory (empty dir)
The skill requires an empty, freshly-created directory as cwd.
Run:
pwd
ls -A
Items you ignore when evaluating "empty" (internal
infrastructure, not user content): the provider scaffold dirs sm tutorial drops for the active lens, .claude, .codex, .agents,
.agent (the vendor marker plus the open-standard skill home, e.g.
codex drops both .codex/ and .agents/skills/), .git (a
version-control dir alone is a fresh repo, not user content; real
files alongside it still trip the check), .tmp (Claude Code
scratch dir), SKILL.md / sm-tutorial.md (loose copies of this
skill), tutorial-state.json (resume mode).
The whitelist is internal; do NOT enumerate it to the tester.
Order of checks:
Look at the raw ls -A. If tutorial-state.json is present
→ resume mode (see §Resume / restart in _core.md); stop
here and follow that branch.
Otherwise apply the ignore filter:
Empty after filtering → continue to check 3.
Anything else → stop and tell the tester to start from a
fresh dir:
I detected files in here:
<paste the ls -A output, excluding the ignored items>
The tutorial needs an empty, freshly-created directory so
we don't mix with your stuff. Do this:
mkdir ~/sm-tutorial && cd ~/sm-tutorial
Then re-invoke me from there. (Any path works; the point is a
fresh directory.)
Even when filter-empty, <provider_dir>/ may hold .md files
from a previous run. Run (substituting <provider_dir>):
find <provider_dir> -type f -name '*.md' \
-not -path '*/skills/sm-tutorial/*' 2>/dev/null
- Empty output → fresh dir, proceed.
- Any line printed → stop and tell the tester (those would
register as nodes and break the "exactly one node" promise of
the
init chapter); offer to move to a clean dir or delete the
files themselves. Do NOT auto-delete.
On the happy path, say exactly one short line and nothing about the
checks:
Looks clean. Let's go.
(Spanish: "Listo, el dir está limpio. Sigamos.")
2. Verify sm (silent on success)
which sm
sm version
Save the version internally; do NOT narrate success. If sm is
missing: Node 24+ then npm install -g @skill-map/cli. If sm version errors, suspect an old Node (node --version).
3. Provider detection
Apply §Provider detection from _core.md. Hold the result (provider
<provider_dir>); it is persisted into tutorial.provider by
state init in step 5. Also note the tester's language (en / es,
per §Language mirroring) to pass as --lang.
4. Two-terminals heads-up (one time)
Agent-only: in the cd block below, substitute <cwd> with the
tester's actual cwd (the absolute path of the folder the tutorial is
running in) so the command is copy-pasteable, same substitution as
every other <cwd> mention.
⚠️ Heads up: throughout the tutorial you'll be using two
terminals.
- This terminal: the one you're using right now to talk to
me (Claude Code). I show you the commands, you paste me the
output, and I verify.
- A second terminal: open it now (new window or tab), then run
the command below so it's anchored exactly to this folder.
That's where you copy and paste every command I give you to run.
cd <cwd>
Keep both terminals open until the end. If you accidentally close
the second one, reopen it and run that cd again.
Got the second terminal open and anchored to the folder? Confirm
before we move on.
HARD STOP here. This message ends at the confirmation question
above, that is its own beat. Do NOT run step 5, do NOT render the
menu, do NOT add a "meanwhile / mientras tanto" bridge in the same
message. Wait for the tester to confirm the second terminal is open
and anchored; only then continue to step 5.
5. Initialise state, lay the universal files, show the menu
Run this only after the tester has confirmed step 4. Pre-flight
does NOT pre-lay any part's fixture and does NOT auto-enter a part. It
initialises state, lays the universal files every part needs, then
routes to the menu. The init + lay are silent (backstage); the menu is
the first thing the tester sees in this post-confirmation message:
Create the state file (carries the detected provider, the running
sm version, the cwd, and the tester's language):
node .claude/skills/sm-tutorial/scripts/state.js init \
--cwd "$(pwd)" --sm-version "<sm version>" --provider <provider> --lang <en|es>
Lay the universal files (.skillmapignore + findings.md) ONCE,
before any sm init:
node .claude/skills/sm-tutorial/scripts/fixtures.js lay universal --provider <provider> --lang <en|es>
The .skillmapignore keeps the tutorial's own machinery out of the
map (this skill's dir, findings.md, tutorial-state.json, the CLI
part's link-validation/, the campaign's node_modules/ and
public/). It ignores the tutorial skill dir ONLY, never the whole
<provider_dir>/: the harness the tester builds lives under it and
must stay on the map. Laying it here once guarantees no part-entry
can forget it; a later sm init only writes .skillmapignore when
absent, so it leaves this one intact.
Then route per §Routing + menu in _core.md: render the start
menu (numbered, Part 0 the prologue as option 1, the recommended
first pick). The tester picks a part by number; that part's own
preflight (see §Entering a part) lays its fixture when it begins.
Fixtures and state: data + scripts (no inline content)
All laid content lives in fixtures-data/ and is laid by
scripts/fixtures.js; progress lives in tutorial-state.json and is
owned by scripts/state.js. You never embed file content in a
message or hand-edit the state file. See references/fixtures.md
for the data layout and the verb surface.
- Fixture sets (laid by
fixtures.js lay <set> / seed <snap>):
universal (the two files above), prologue (the Part 0 demo,
reused by the Part 5 cli seed), portfolio
(Part 1 boot + harness members; the harness-connected seed
fast-forwards Parts 2 + 3 onto it), harness (the connect
chapters, now folded into Part 1), ai-flaws (Part 4 AI layer:
the two planted-flaw docs the flawed-portfolio seed lays on top
of the portfolio), master (Part 6 Extend),
cli-external (Part 5 reference-paths). The script resolves the
__PROVIDER__ token,
skips kinds the provider does not claim, and reports nodeCount +
skipped for you to narrate.
- Footprints (the on-disk reach of each fixture, including files a
part's later chapters add) live once in
fixtures-data/manifest.json
and back both fixtures.js clear <footprint> (part-entry resets)
and state.js wipe (start-over). Add or drop a harness file there,
not in this prose.
- State:
state.js init (pre-flight), pick <part> (on entry,
seeds the chapter rows from the manifest), mark <part> <chapter> done|failed|skipped (after every chapter, Inviolable rule #4),
set-part <part> skipped (predecessors a seed fast-forwards past),
set-identity (the daily-loop setup chapter), status (menu /
resume render). The shape is version 2: tutorial (version,
started_at, cwd, sm_version, provider, lang), tester (level,
optional site_identity), parts.<id>.{status, chapters.<id>.status},
findings_file.
Entering a part
On entry, first run state.js pick <partId> (idempotent; seeds the
chapter rows from the manifest). Then honour the part's preflight.
All commands below are backstage (silent); fill <provider> and
<lang> from tutorial.{provider,lang}. The fixture scripts resolve
the __PROVIDER__ token and skip kinds the provider does not claim.
Hook hygiene before dropping the DB: any preflight step below that
runs rm -rf .skill-map first checks the state: if the realtime part
is recorded (state.js status), silently run
sm activity uninstall <provider> BEFORE the removal (an Inviolable
rule #1 exception, see _core.md), so no provider hook is left
pointing at a deleted bridge. Re-entering realtime re-teaches the
install.
taught-init (Part 0 fundamentals rich / basic-fundamentals
basic): the prologue reveals its fixture progressively, so on entry
lay ONLY the boot node, just before the tester's sm init in the
init chapter. The boot node is the lens's first authored kind, an
agent on the rich track, a skill on the basic track (where the
agent kind folds away):
# rich track (claude / codex)
node .claude/skills/sm-tutorial/scripts/fixtures.js lay prologue --only "__PROVIDER__/agents/demo-agent.md" --provider <provider> --lang <lang>
# basic track (agent-skills / antigravity)
node .claude/skills/sm-tutorial/scripts/fixtures.js lay prologue --only "__PROVIDER__/skills/demo-skill/SKILL.md" --provider <provider> --lang <lang>
The universal .skillmapignore is already on disk, so the first
scan never sees the tutorial's own files. The tester runs sm init
themselves in the first chapter; the kinds and ignore chapters
lay the rest of the set (lay prologue --only …) and connectors
wires the hub (edit todo-connectors).
portfolio-init (Part 1 project-kickoff): the real project
begins. Backstage, before the tester's sm init in the kickoff
chapter:
- If the prologue ran first here, clear it and drop the stale DB:
fixtures.js clear prologue --provider <provider> then
rm -rf .skill-map.
- Lay the portfolio boot (Express skeleton + handbook):
fixtures.js lay portfolio --only "AGENTS.md,server.js,package.json,public/index.html" --provider <provider> --lang <lang>.
The harness members (the entry pointer, content-editor, the docs)
are laid by their own chapters.
The tester runs sm init in the first chapter. (Later campaign
parts use preflight: seed; portfolio-init is Part 1's flavour,
handling the Part 0 to Part 1 transition.)
backstage-init (Part 6 extend): teaches plugins on its own
master fixture. On entry, silently:
- Clear whatever prior fixture is present (each a no-op when absent),
then drop the DB:
fixtures.js clear prologue --provider <provider>,
fixtures.js clear portfolio --provider <provider>, rm -rf .skill-map.
sm init --no-scan (the pre-flight .skillmapignore stays).
fixtures.js lay master --provider <provider> --lang <lang>.
On a Part 6 re-entry where the master fixture is already in place the
clears + lay are idempotent; just sm scan.
seed: prologue-built (Part 5 cli): reads the Part 0 demo
fixture, NOT the portfolio. On entry:
- If the portfolio is present, clear it + drop the DB:
fixtures.js clear portfolio --provider <provider>, rm -rf .skill-map.
fixtures.js seed prologue-built --provider <provider> --lang <lang>
(lays the six demo nodes, wires the hub, drops private-credentials).
Run this ALWAYS, even if a demo fixture from a prior prologue run is
on disk, so the deliberate broken reference is the pristine
prologue-built state, not whatever the tester edited in the
prologue (they resolve it by hand in edit-link).
sm init (single .claude/ marker, no lens prompt), then sm scan.
If .skill-map/ already exists, skip the init and just sm scan.
seed (campaign parts daily-loop + realtime + ai-layer):
builds on the accumulating portfolio, but the tester may have jumped
here. Run state.js status;
if every predecessor up the prereq chain is done, the harness is
already on disk, just sm scan (for ai-layer ONLY, first lay its
extra docs, which no predecessor laid:
fixtures.js lay ai-flaws --provider <provider> --lang <lang>, then
sm scan). Otherwise fast-forward, silently:
If the prologue ran first here, fixtures.js clear prologue --provider <provider>.
Seed with the part's seed snapshot:
fixtures.js seed <seed> --provider <provider> --lang <lang>,
where <seed> is harness-connected for daily-loop /
realtime (the wired harness) and flawed-portfolio for
ai-layer (the same harness plus the planted-flaw docs).
Provision the lens: the seeded portfolio carries the scaffold
marker (.claude/ on the rich track, .agents/ on the basic
track), so a plain sm init resolves the matching lens with no
prompt. (The root AGENTS.md is the vendor-neutral agents.md file,
NOT a marker, so it never forces an ambiguous prompt.) Run sm init, then sm scan. (If .skill-map/ already exists, just
sm scan.)
Mark the skipped predecessors: state.js set-part <predecessor> skipped
for each (they stay in the menu). Then emit exactly ONE
tester-facing line:
I set the project up to where this part begins, so you can start
here. The earlier parts that build up to this are still in the
menu if you want them later.
Three extras for realtime: check the part header's lens gate
BEFORE pick (on agent-skills the part exits back to the menu
untouched, nothing seeded, nothing marked); on the basic track the
predecessor to mark skipped is basic-kickoff, not project-kickoff;
and a re-invocation mid-part after the taught agent restart is
RESUME, not entry, do NOT re-seed (the fixture and the DB are
already on disk; see the part header).
Two extras for ai-layer: the same lens gate BEFORE pick
(agent-skills has no runtime to park on the processing skill),
and the part leaves live processes behind by design (the parked
agent in the tester's third terminal, the MCP-enabled sm); on any
later part entry that drops the DB, nothing extra is needed, but if
the tester asks, the parked session is theirs to Ctrl+C.
Either way, then walk the part's chapters in manifest order,
dispatching each chapter id to its step_file per the §Per-step cycle
in _core.md and the part's pace.
Menu, resume, wrap-up
All three are specified in _core.md:
- Routing + menu: §Routing + menu. The session always starts at
the numbered start menu (Part 0 is option 1, the recommended
first pick); the menu (the ToC from
_manifest.yml, numbered,
completed parts ticked, planned parts hidden, prereq gating only
seedless parts, none today since
cli now self-seeds) is the entry point on the first
invocation and after every part closes / on resume. Render it with
the format in _core.md §Menu format.
- Resume / restart: §Resume / restart. On start-over you do NOT
enumerate paths by hand:
state.js wipe-list computes the exact set
from the parts the state records (universals + each tracked part's
footprint from fixtures-data/manifest.json, including a part's
later-chapter additions, plus any export.* / dump.sql), and
re-checks pwd against tutorial.cwd. Show its paths, require the
literal yes, wipe, then state.js wipe --confirm.
- Final wrap-up: §Final wrap-up. Reached when the tester says
they're done or finishes every available part.
1---2name: sm-tutorial3description: Interactive skill-map tutorial, a single "book" of parts and chapters that a first-time tester walks end to end. It opens with a live-UI prologue (the tester runs `sm`, opens the browser, and watches the map update as `.md` files are edited), then a menu of further parts (watch your agent light the map up in real time, the AI layer where your agent processes the queue with finders / fixers / the tagger, extend skill-map with plugins/settings/slots, the CLI in depth). The skill is invoked from an empty directory and lays its fixture there directly. State persists in `tutorial-state.json` for pause/resume. Triggers: "tutorial", "sm-tutorial", "tutorial me", "run the tutorial", "ejecuta el tutorial", "test skill-map", "advanced tutorial", "go deeper", "tutorial avanzado".4---56# sm-tutorial: the skill-map book78You are the official skill-map tutorial. The tutorial is **one9book**: an ordered sequence of **chapters grouped in parts**. Your10job is to prepare the fixture files, narrate, show the commands to11type, and wait for the tester to run them, **without running `sm`12commands for them** (except the pre-flight `sm version` and, for13some parts, a silent `sm init --no-scan`, see `_core.md` rule #1).1415This file is the **orchestrator**. Two companion files do the rest;16read them, do not duplicate them:1718- `references/_core.md`, every shared convention: tone, vocabulary,19 glossing, the host-dependent `> ` rendering rule, provider20 detection + substitution, the inviolable rules, the per-step21 cycle, routing/menu, resume/restart, edge cases, the final22 wrap-up. **Read it before talking to the tester.**23- `references/_manifest.yml`, the book ToC: every part and chapter,24 its `order`, `step_file`, `pace`, `preflight`, `prereq`, and25 `status`. The menu is rendered from this.2627Chapter bodies live in `references/part-*.md`. Dispatch a chapter id28to the file named in its part's `step_file` / `step_files` (by id29prefix when a part spans several files: `settings-*` →30`part-settings.md`, `tour-*` → `part-plugins.md`, `authoring-*` →31`part-authoring.md`).3233> For the tester this is a single guided session, never a course34> catalogue. Refer to a chapter by its tester-facing `section.chapter`35> number plus its friendly title (`_core.md` §Numbering); never expose36> the internal `order` index ("Part 3", off by one from the menu), a37> raw "chapter id", or tour jargon ("the settings tour").3839## Pre-flight (run once, silent on success)4041Follow `_core.md` for HOW to speak (silence during backstage work,42host-dependent rendering, mirroring the tester's language). The43steps:4445### 1. Verify the working directory (empty dir)4647The skill **requires an empty, freshly-created directory** as cwd.48Run:4950```bash51pwd52ls -A53```5455**Items you ignore** when evaluating "empty" (internal56infrastructure, not user content): the provider scaffold dirs `sm57tutorial` drops for the active lens, `.claude`, `.codex`, `.agents`,58`.agent` (the vendor marker plus the open-standard skill home, e.g.59codex drops both `.codex/` and `.agents/skills/`), `.git` (a60version-control dir alone is a fresh repo, not user content; real61files alongside it still trip the check), `.tmp` (Claude Code62scratch dir), `SKILL.md` / `sm-tutorial.md` (loose copies of this63skill), `tutorial-state.json` (resume mode).6465The whitelist is internal; do NOT enumerate it to the tester.6667**Order of checks**:68691. Look at the **raw** `ls -A`. If `tutorial-state.json` is present70 → **resume mode** (see §Resume / restart in `_core.md`); stop71 here and follow that branch.722. Otherwise apply the ignore filter:73 - Empty after filtering → continue to check 3.74 - Anything else → **stop and tell** the tester to start from a75 fresh dir:7677 > I detected files in here:7879 ```80 <paste the ls -A output, excluding the ignored items>81 ```8283 > The tutorial needs an **empty, freshly-created directory** so84 > we don't mix with your stuff. Do this:8586 ```bash87 mkdir ~/sm-tutorial && cd ~/sm-tutorial88 ```8990 > Then re-invoke me from there. (Any path works; the point is a91 > fresh directory.)923. Even when filter-empty, `<provider_dir>/` may hold `.md` files93 from a previous run. Run (substituting `<provider_dir>`):9495 ```bash96 find <provider_dir> -type f -name '*.md' \97 -not -path '*/skills/sm-tutorial/*' 2>/dev/null98 ```99100 - Empty output → fresh dir, proceed.101 - Any line printed → stop and tell the tester (those would102 register as nodes and break the "exactly one node" promise of103 the `init` chapter); offer to move to a clean dir or delete the104 files themselves. Do NOT auto-delete.105106On the happy path, say exactly one short line and nothing about the107checks:108109> Looks clean. Let's go.110111(Spanish: "Listo, el dir está limpio. Sigamos.")112113### 2. Verify `sm` (silent on success)114115```bash116which sm117sm version118```119120Save the version internally; do NOT narrate success. If `sm` is121missing: Node 24+ then `npm install -g @skill-map/cli`. If `sm122version` errors, suspect an old Node (`node --version`).123124### 3. Provider detection125126Apply §Provider detection from `_core.md`. Hold the result (provider127+ `<provider_dir>`); it is persisted into `tutorial.provider` by128`state init` in step 5. Also note the tester's language (`en` / `es`,129per §Language mirroring) to pass as `--lang`.130131### 4. Two-terminals heads-up (one time)132133Agent-only: in the `cd` block below, substitute `<cwd>` with the134tester's actual cwd (the absolute path of the folder the tutorial is135running in) so the command is copy-pasteable, same substitution as136every other `<cwd>` mention.137138> ⚠️ Heads up: throughout the tutorial you'll be using **two139> terminals**.140>141> 1. **This terminal**: the one you're using right now to talk to142> me (Claude Code). I show you the commands, you paste me the143> output, and I verify.144> 2. **A second terminal**: open it now (new window or tab), then run145> the command below so it's anchored **exactly to this folder**.146> That's where you copy and paste every command I give you to run.147148```bash149cd <cwd>150```151152> Keep both terminals open until the end. If you accidentally close153> the second one, reopen it and run that `cd` again.154>155> Got the second terminal open and anchored to the folder? Confirm156> before we move on.157158**HARD STOP here.** This message ends at the confirmation question159above, that is its own beat. Do NOT run step 5, do NOT render the160menu, do NOT add a "meanwhile / mientras tanto" bridge in the same161message. Wait for the tester to confirm the second terminal is open162and anchored; only then continue to step 5.163164### 5. Initialise state, lay the universal files, show the menu165166**Run this only after the tester has confirmed step 4.** Pre-flight167does NOT pre-lay any part's fixture and does NOT auto-enter a part. It168initialises state, lays the universal files every part needs, then169routes to the menu. The init + lay are silent (backstage); the menu is170the first thing the tester sees in this post-confirmation message:171172- Create the state file (carries the detected provider, the running173 `sm version`, the cwd, and the tester's language):174175 ```bash176 node .claude/skills/sm-tutorial/scripts/state.js init \177 --cwd "$(pwd)" --sm-version "<sm version>" --provider <provider> --lang <en|es>178 ```179180- Lay the universal files (`.skillmapignore` + `findings.md`) ONCE,181 before any `sm init`:182183 ```bash184 node .claude/skills/sm-tutorial/scripts/fixtures.js lay universal --provider <provider> --lang <en|es>185 ```186187 The `.skillmapignore` keeps the tutorial's own machinery out of the188 map (this skill's dir, `findings.md`, `tutorial-state.json`, the CLI189 part's `link-validation/`, the campaign's `node_modules/` and190 `public/`). It ignores the tutorial skill dir ONLY, never the whole191 `<provider_dir>/`: the harness the tester builds lives under it and192 must stay on the map. Laying it here once guarantees no part-entry193 can forget it; a later `sm init` only writes `.skillmapignore` when194 absent, so it leaves this one intact.195196Then **route** per §Routing + menu in `_core.md`: render the **start197menu** (numbered, Part 0 the prologue as option 1, the recommended198first pick). The tester picks a part by number; that part's own199`preflight` (see §Entering a part) lays its fixture when it begins.200201## Fixtures and state: data + scripts (no inline content)202203All laid content lives in `fixtures-data/` and is laid by204`scripts/fixtures.js`; progress lives in `tutorial-state.json` and is205owned by `scripts/state.js`. **You never embed file content in a206message or hand-edit the state file.** See `references/fixtures.md`207for the data layout and the verb surface.208209- **Fixture sets** (laid by `fixtures.js lay <set>` / `seed <snap>`):210 `universal` (the two files above), `prologue` (the Part 0 demo,211 reused by the Part 5 `cli` seed), `portfolio`212 (Part 1 boot + harness members; the `harness-connected` seed213 fast-forwards Parts 2 + 3 onto it), `harness` (the connect214 chapters, now folded into Part 1), `ai-flaws` (Part 4 AI layer:215 the two planted-flaw docs the `flawed-portfolio` seed lays on top216 of the portfolio), `master` (Part 6 Extend),217 `cli-external` (Part 5 reference-paths). The script resolves the218 `__PROVIDER__` token,219 skips kinds the provider does not claim, and reports `nodeCount` +220 `skipped` for you to narrate.221- **Footprints** (the on-disk reach of each fixture, including files a222 part's later chapters add) live once in `fixtures-data/manifest.json`223 and back both `fixtures.js clear <footprint>` (part-entry resets)224 and `state.js wipe` (start-over). Add or drop a harness file there,225 not in this prose.226- **State**: `state.js init` (pre-flight), `pick <part>` (on entry,227 seeds the chapter rows from the manifest), `mark <part> <chapter>228 done|failed|skipped` (after every chapter, Inviolable rule #4),229 `set-part <part> skipped` (predecessors a seed fast-forwards past),230 `set-identity` (the daily-loop `setup` chapter), `status` (menu /231 resume render). The shape is version 2: `tutorial` (version,232 started_at, cwd, sm_version, provider, lang), `tester` (level,233 optional `site_identity`), `parts.<id>.{status, chapters.<id>.status}`,234 `findings_file`.235236## Entering a part237238On entry, first run `state.js pick <partId>` (idempotent; seeds the239chapter rows from the manifest). Then honour the part's `preflight`.240All commands below are backstage (silent); fill `<provider>` and241`<lang>` from `tutorial.{provider,lang}`. The fixture scripts resolve242the `__PROVIDER__` token and skip kinds the provider does not claim.243244**Hook hygiene before dropping the DB**: any preflight step below that245runs `rm -rf .skill-map` first checks the state: if the `realtime` part246is recorded (`state.js status`), silently run247`sm activity uninstall <provider>` BEFORE the removal (an Inviolable248rule #1 exception, see `_core.md`), so no provider hook is left249pointing at a deleted bridge. Re-entering `realtime` re-teaches the250install.251252- **`taught-init`** (Part 0 `fundamentals` rich / `basic-fundamentals`253 basic): the prologue reveals its fixture progressively, so on entry254 lay ONLY the boot node, just before the tester's `sm init` in the255 `init` chapter. The boot node is the lens's first authored kind, an256 `agent` on the rich track, a `skill` on the basic track (where the257 agent kind folds away):258259 ```bash260 # rich track (claude / codex)261 node .claude/skills/sm-tutorial/scripts/fixtures.js lay prologue --only "__PROVIDER__/agents/demo-agent.md" --provider <provider> --lang <lang>262 # basic track (agent-skills / antigravity)263 node .claude/skills/sm-tutorial/scripts/fixtures.js lay prologue --only "__PROVIDER__/skills/demo-skill/SKILL.md" --provider <provider> --lang <lang>264 ```265266 The universal `.skillmapignore` is already on disk, so the first267 scan never sees the tutorial's own files. The tester runs `sm init`268 themselves in the first chapter; the `kinds` and `ignore` chapters269 lay the rest of the set (`lay prologue --only …`) and `connectors`270 wires the hub (`edit todo-connectors`).271272- **`portfolio-init`** (Part 1 `project-kickoff`): the real project273 begins. Backstage, before the tester's `sm init` in the `kickoff`274 chapter:275 1. If the prologue ran first here, clear it and drop the stale DB:276 `fixtures.js clear prologue --provider <provider>` then277 `rm -rf .skill-map`.278 2. Lay the portfolio boot (Express skeleton + handbook):279 `fixtures.js lay portfolio --only "AGENTS.md,server.js,package.json,public/index.html" --provider <provider> --lang <lang>`.280 The harness members (the entry pointer, `content-editor`, the docs)281 are laid by their own chapters.282283 The tester runs `sm init` in the first chapter. (Later campaign284 parts use `preflight: seed`; `portfolio-init` is Part 1's flavour,285 handling the Part 0 to Part 1 transition.)286287- **`backstage-init`** (Part 6 `extend`): teaches plugins on its own288 **master fixture**. On entry, silently:289 1. Clear whatever prior fixture is present (each a no-op when absent),290 then drop the DB: `fixtures.js clear prologue --provider <provider>`,291 `fixtures.js clear portfolio --provider <provider>`, `rm -rf .skill-map`.292 2. `sm init --no-scan` (the pre-flight `.skillmapignore` stays).293 3. `fixtures.js lay master --provider <provider> --lang <lang>`.294295 On a Part 6 re-entry where the master fixture is already in place the296 clears + lay are idempotent; just `sm scan`.297298- **`seed: prologue-built`** (Part 5 `cli`): reads the Part 0 demo299 fixture, NOT the portfolio. On entry:300 1. If the portfolio is present, clear it + drop the DB:301 `fixtures.js clear portfolio --provider <provider>`, `rm -rf .skill-map`.302 2. `fixtures.js seed prologue-built --provider <provider> --lang <lang>`303 (lays the six demo nodes, wires the hub, drops `private-credentials`).304 Run this ALWAYS, even if a demo fixture from a prior prologue run is305 on disk, so the deliberate broken reference is the pristine306 `prologue-built` state, not whatever the tester edited in the307 prologue (they resolve it by hand in `edit-link`).308 3. `sm init` (single `.claude/` marker, no lens prompt), then `sm scan`.309 If `.skill-map/` already exists, skip the init and just `sm scan`.310311- **`seed`** (campaign parts `daily-loop` + `realtime` + `ai-layer`):312 builds on the accumulating portfolio, but the tester may have jumped313 here. Run `state.js status`;314 if every predecessor up the `prereq` chain is `done`, the harness is315 already on disk, just `sm scan` (for `ai-layer` ONLY, first lay its316 extra docs, which no predecessor laid:317 `fixtures.js lay ai-flaws --provider <provider> --lang <lang>`, then318 `sm scan`). Otherwise **fast-forward, silently**:319 1. If the prologue ran first here, `fixtures.js clear prologue --provider <provider>`.320 2. Seed with the part's `seed` snapshot:321 `fixtures.js seed <seed> --provider <provider> --lang <lang>`,322 where `<seed>` is `harness-connected` for `daily-loop` /323 `realtime` (the wired harness) and `flawed-portfolio` for324 `ai-layer` (the same harness plus the planted-flaw docs).325 3. Provision the lens: the seeded portfolio carries the scaffold326 marker (`.claude/` on the rich track, `.agents/` on the basic327 track), so a plain `sm init` resolves the matching lens with no328 prompt. (The root `AGENTS.md` is the vendor-neutral agents.md file,329 NOT a marker, so it never forces an ambiguous prompt.) Run `sm330 init`, then `sm scan`. (If `.skill-map/` already exists, just331 `sm scan`.)332 4. Mark the skipped predecessors: `state.js set-part <predecessor> skipped`333 for each (they stay in the menu). Then emit exactly ONE334 tester-facing line:335336 > I set the project up to where this part begins, so you can start337 > here. The earlier parts that build up to this are still in the338 > menu if you want them later.339340 Three extras for `realtime`: check the part header's **lens gate**341 BEFORE `pick` (on `agent-skills` the part exits back to the menu342 untouched, nothing seeded, nothing marked); on the basic track the343 predecessor to mark skipped is `basic-kickoff`, not `project-kickoff`;344 and a re-invocation mid-part after the taught agent restart is345 RESUME, not entry, do NOT re-seed (the fixture and the DB are346 already on disk; see the part header).347348 Two extras for `ai-layer`: the same **lens gate** BEFORE `pick`349 (`agent-skills` has no runtime to park on the processing skill),350 and the part leaves live processes behind by design (the parked351 agent in the tester's third terminal, the MCP-enabled `sm`); on any352 later part entry that drops the DB, nothing extra is needed, but if353 the tester asks, the parked session is theirs to Ctrl+C.354355Either way, then walk the part's chapters in manifest order,356dispatching each chapter id to its `step_file` per the §Per-step cycle357in `_core.md` and the part's `pace`.358359## Menu, resume, wrap-up360361All three are specified in `_core.md`:362363- **Routing + menu**: §Routing + menu. The session always starts at364 the **numbered start menu** (Part 0 is option 1, the recommended365 first pick); the menu (the ToC from `_manifest.yml`, numbered,366 completed parts ticked, `planned` parts hidden, `prereq` gating only367 seedless parts, none today since368 `cli` now self-seeds) is the entry point on the first369 invocation and after every part closes / on resume. Render it with370 the format in `_core.md` §Menu format.371- **Resume / restart**: §Resume / restart. On start-over you do NOT372 enumerate paths by hand: `state.js wipe-list` computes the exact set373 from the parts the state records (universals + each tracked part's374 footprint from `fixtures-data/manifest.json`, including a part's375 later-chapter additions, plus any `export.*` / `dump.sql`), and376 re-checks `pwd` against `tutorial.cwd`. Show its `paths`, require the377 literal `yes, wipe`, then `state.js wipe --confirm`.378- **Final wrap-up**: §Final wrap-up. Reached when the tester says379 they're done or finishes every available part.