Hook Chain

Build A facilitated tutorial for Claude Code

Build your own mod skeleton

Reading about hook chains only goes so far. The Mod Skeleton 101 is a tutorial you run inside Claude Code. Claude facilitates: it teaches one idea, makes one small change, asks you to predict the result, runs the check for real, commits, and asks you a question. You end with a small mod you built and tested yourself, and a git history that tells the story one layer per commit.

An illustrated skeleton assembling a small mod from three labelled files, plugin.json, hooks.json and register.ts, with a test bench and a guard gate beside it.

What you'll build

skeleton-guard is the smallest mod with the real shape: three files, a test, a guard that fails closed, state that survives /clear, and an install line someone else can use. By the end it:

On the way you watch three things go wrong on purpose, each in a test: a guard that fails open when it throws, an @-mentioned .env slipping past a tool.call guard, and a misspelling that claude plugin validate passes and the compiler catches.

Who it's for

You drive Claude Code and want to change it

You've used skills, settings hooks or MCP servers and want to know what a mod adds, and how to write one you'd trust in your own sessions. Claude reads each snippet aloud in plain words before writing it.

You write TypeScript and want the model right

You'll move fast through the syntax and spend the time on the chain: who runs first, which hooks fail open, what each kind of state outlives, and what the test kit stands in for.

How to start

git clone https://github.com/RobGruhl/claude-mod-learnings
cd claude-mod-learnings/tutorial
claude

The folder's own CLAUDE.md turns Claude into the facilitator: it greets you, checks your setup, and offers to start, resume, or run a 201 direction. Your mod is built in tutorial/my-mod/ as its own git repository, and the tutorial files stay untouched. If Claude doesn't start on its own, say: "Walk me through the Mod Skeleton 101 one module at a time, following the Facilitator Contract in 101-mod-skeleton.md."

Coming back later? Open the folder again and say: "We're partway through the Mod Skeleton 101. Read the git log in my-mod and continue from the next module." Each module is one commit, so Claude can always find your place.

You'll need

The modules

#ModuleYou walk away knowing
0OrientWhat a mod can reach that a skill can't, and three ways to turn mods off
0.5Initialize version controlWhy the typings Claude Code writes beside a mod stay out of git
1Three files: a tool counterplugin.json, hooks.json, register(on) and the ($, e, next) hook
2Read it like a reviewervalidate's hooks: and calls: lines, and the reserved names
3The first testThe kit sits beneath your mod, so a test answers every event and $ call
4Rewrite what Claude Code drawsRewrite with next({ ...e }), and why that's politer than replacing
5Answer for yourself: a slash commandA command that runs your code with no Claude turn
6A guard on tool.call{ deny }, and that the deny reason is a prompt to the model
7Make the guard fail closedA guard that throws is skipped and the call runs, unless it has a .catch
8The second door@-mentioned files are read with no tool call; guard prompt.mention too
9State that redraws$.state, the PluginState contract, and a band above the prompt
10State that lasts$.store as the source of truth, and the /clear trap
11Type-check against your buildWhat the compiler catches that validate doesn't
12README and CLAUDE.mdAn install line for people, and rules for the next agent
13Package and installThe mod's folder as its own marketplace, and what a version number does
14Ship one changeTest first, every check, a version bump, and a short review

How a module feels

  1. Learn the idea in a few plain sentences.
  2. Make one small change. Claude proposes and writes it; you see the diff.
  3. Predict. "Will the guard hold this call when it throws?" "Will validate catch the misspelling?" Claude stops and waits for your answer.
  4. Run the check for real (claude plugin validate, claude plugin test, or what you see in your live session) and compare it with your prediction.
  5. Commit as module N: title.
  6. Reflect. Answer a question in your own words before Claude shows the expected answer.

The rules Claude follows

Every snippet in the script was run on Claude Code 2.1.296: validate and test passed at each stage, and each failure the script predicts was seen. The finished mod is in tutorial/.reference/skeleton-guard, and the full script is tutorial/101-mod-skeleton.md.

After the 101

The 201 offers seven directions, each run the same way:

A pane with buttons

A panel opened from /skeleton, buttons that raise ui.press, and a mount test on two surfaces.

A real policy

An allow-list on resolved paths with $.fs.stat, plus a tool.check hook. Stronger than any list of spellings.

Hold and ask

Ask the person with $.ui.ask instead of denying, and test the timeout that would otherwise let the call through.

A decision tier

A model judges only what the patterns can't settle, with a fallback to the person on timeout. See Mods meet the cascade.

Options

userConfig for extra patterns, tested with test(name, { options }, body).

Publish with CI

A public repo, the install line tested from a clean session, and CI running validate --strict and test.

A tool for Claude

$.tool.register, served by the mod's own tool.call hook.

Where the format comes from

The facilitation design comes from the Walking Skeleton tutorial: one module at a time, a prediction before every check, every check run for real, one commit per module, a circuit breaker, and resuming from the git log. That tutorial builds a production-shaped web app; this one applies the same method to a mod. The sister site's Decision Skeleton applies it to a decision cascade.

Prefer a five-minute version first? The ELI5 and 101 pages cover the ideas the tutorial makes you build.