Reference

Claude Code mods: what they are, six real ones, and how to build yours.

Six mods built and tested in one afternoon, four bugs the tests caught first, one guard that blocked its author. Plugin API checked against Claude Code 2.1.288 on 2026-10-03.

Jump to section tap to open

The 30-second answer

A Claude Code mod is a plugin of function hooks: a small TypeScript or JavaScript module that Claude Code loads into the session. It can rewrite or refuse a tool call or a prompt, and draw its own interface, from a line above the prompt to a docked pane. Install one with /plugin, or load a folder with --plugin-dir. Mods shipped on 1 October 2026.

What is a Claude Code mod?

A mod is a plugin folder with three files: a manifest that names it, a hooks/hooks.json that names one module, and the module, which exports register(on). Every on(event, hook) adds a function hook shaped ($, e, next). $ is the engine, e is what is happening, and next(e) lets it carry on. Return without calling next and your hook answers instead; call it with a changed e and everything after you sees the change.

The events cover tool calls, prompts, turns, sessions and drawing. Drawing is the new part: a hook on ui.render can put a band above the prompt, a pane beside the transcript or a line under the prompt. The module runs with no Node and no DOM, and reaches everything else through $: files, commands, the model, state and toasts.

The contract is a type file the engine writes as it loads the mod. Grep it for the event you need. The full story, with receipts, is in Chapter 57.

How do mods differ from hooks, skills and MCP?

A skill changes what the model does. A mod changes what Claude Code does around the model, including what you see. Settings hooks do not go away: they run beneath every mod's tool.call hook, and a mod can wrap them.

What it changesWhere it livesDraws UIHow you test it
ModWhat the harness does and drawsA plugin folder, loaded by /plugin or --plugin-dirYesclaude plugin test, against the engine
Settings hookAllows, blocks or annotates a lifecycle eventA shell command in settings.jsonNoPipe it a real payload
SkillWhat the model knows how to do, loaded on demandA SKILL.md folderNoUse it and read the transcript
MCP serverWhich outside tools the model can callA separate process (setup)NoCall the tool
Status lineOne line under the promptA shell script fed JSON (setup)One lineRun it on sample input

How do you install or load a mod?

  • Published: /plugin in the CLI installs it like any plugin.
  • A folder, one session: claude --plugin-dir <folder>, repeated once per mod.
  • A folder, every session: list folders in CLAUDE_CODE_PLUGIN_DIRS, in your shell or the env block of ~/.claude/settings.json. A project's settings cannot set it.
  • Built in the session: the first time a session writes a mod, Claude Code asks "Enable hot reloading for this session?". Only the person can answer; after a yes, each save reloads the mod when the turn ends.

How do you build your first mod?

Start with a mistake you keep correcting. This one refuses a zsh trap, a word that starts with =, before the command runs, and hands Claude the fix so it rewrites and reruns. It is the smallest version of the guard in Chapter 57, and it passed validate, a strict type check and an engine test on 2026-10-03.

quote-guard/.claude-plugin/plugin.json
{ "name": "quote-guard", "version": "0.1.0", "description": "Refuses an unquoted zsh =word before it runs and tells Claude the fix" }
quote-guard/hooks/hooks.json
{ "modules": ["./register.ts"] }
quote-guard/hooks/register.ts
import type { Register } from 'claude-code'

// zsh reads an unquoted word that starts with = as a command lookup
// ("= not found") and drops the rest of the line. Refuse it, say why.
export const register: Register = on => {
  on('tool.call', { tool: 'Bash' }, ($, e, next) => {
    const trap = e.command.split(/\s+/).some(word => /^=\S/.test(word))
    if (!trap) return next(e)
    $.ui.toast('quote-guard: blocked an unquoted =word')
    return { deny: "zsh reads a word starting with = as a command. Quote it: echo '===='." }
  })
}

Load it with claude --plugin-dir ./quote-guard, then ask Claude to run echo ==== done. The command is refused, a toast says why, and the model gets the fix.

What do real mods look like?

Six mods built in 32 minutes on 3 October 2026. Each fills a gap the existing setup had, not one from the launch video.

Token Weather

A band above the prompt: fill against the auto-compact line, a sparkline of twelve turns and turns left at the current growth. The status line already showed the percentage; this adds the trend.

Blast Radius

Before rm -r, git reset --hard, git clean -f or a force push, it works out what would be lost and adds it to the prompt the careful hook already raises. One prompt, not two.

Replay Theater

Records every file edit by turn. /replay steps through the diffs in a docked pane; turns without edits are skipped.

Gotcha Guard

Refuses ten shell traps from a rules file the model kept ignoring, and sends Claude the fix. Caught a missed /tmp pattern in its tests, then blocked its own author on a heredoc.

Peers

Every 30 seconds it reads the other live sessions in the folder. Edit a file a peer touched in the last half hour and Claude is told to check the diff first.

5h Pacer

The burn rate over the last hour, and whether the five-hour window fills before it resets. Warns once per window and names the pace that lands on the reset.

How do you test a Claude Code mod?

Three gates, in this order: claude plugin validate, a strict type check against the engine's type file, and claude plugin test. On the six mods above the tests caught four bugs before anything ran live: a quoted path split in two, a pattern that missed a space after >, an engine refusal over where $ was passed, and a value that was only set at session start, which a test never fires.

FAQ

What is a Claude Code mod?

A plugin of function hooks: a TypeScript or JavaScript module Claude Code loads into the session. It can rewrite or refuse an event such as a tool call or a prompt, and draw its own interface: a band above the prompt, a status line, a docked pane, a toast or its own slash command.

How is a mod different from a Claude Code hook?

A settings hook is a shell command in settings.json that reads JSON on stdin and blocks with exit code 2; it draws nothing. A mod runs inside the session, can change the event on its way through, and can draw on screen. Settings hooks still run beneath a mod, as classic.PreToolUse.

How do I install a Claude Code mod?

Install a published one with /plugin. Load a folder for one session with claude --plugin-dir <folder>, repeated per mod, or list folders in CLAUDE_CODE_PLUGIN_DIRS in the env block of ~/.claude/settings.json so every session loads them.

What files does a mod need?

Three: .claude-plugin/plugin.json with the name, hooks/hooks.json naming one module, and that module, which exports register(on). Each on(event, hook) adds a hook shaped ($, e, next).

How do I test a Claude Code mod?

Run claude plugin validate to read it the way the engine will, type-check it in strict mode against the type file the engine writes, and run claude plugin test, which loads the mod into the engine with your test standing in for what sits beneath it. Test that it fires, and that it does not fire on the wrong thing.

Can a mod show its own interface in the terminal?

Yes. A hook on ui.render draws a band above the prompt, a pane beside the transcript or a line under the prompt, and $.ui.toast shows a short notice. A pane the person did not ask for opens only on a terminal at least 144 columns wide.

Related: Ch 57: Claude Code Mods · Claude Code hooks · terminal setup · Ch 16: Hooks and Custom Subagents

Stay close

The next edition lands when this list says it does.

No course. No paywall. Operator playbooks weekly. 10K+ subscribers.