Claude Code mods: in-session JavaScript hooks for guards, readouts and review views
Anthropic's mods run JS/TS hooks inside a Claude Code session, for developers who want code, not prompts, to enforce their rules.
Picture a backend developer at a four-person agency who runs Claude Code all day against client repos. Three habits repeat every session. They remind Claude not to print anything from .env. They type /context to see why the window filled so fast. After a multi-file refactor, they scroll back through the transcript to see what changed. The reminder lives in CLAUDE.md and in chat, so it holds only as long as the model honours it. They tried a settings hook, but that's a shell script launched per event, and a script that crashes or times out can quietly let the command through.
Claude Code mods target the first part of that gap: the rule stops depending on the model. Whether a crashing mod blocks the command or lets it through, our sources don't confirm (see Where it breaks). Anthropic's getting-started post, dated October 1, 2026, describes mods as small JavaScript or TypeScript modules, shipped inside plugins, that run inside your session, see every event and can draw their own UI. As @bibryam put it, the point is "deterministic behavior without relying on prompts."
What it is
Per Anthropic's post, mods are on by default from Claude Code 2.1.287. A mod is a plugin whose hooks/hooks.json names exactly one module under modules. That module exports register(on), and on(event, matcher?, hook) adds a hook. Every hook has the same shape:
on("tool.call", { tool: "Bash" }, async ($, e, next) => {
// $ the mods API: ui, session, state, store, fs, process, clock, http, tool, command, model, ...
// e this event's input, as plain data
// next passes e to the other plugins and then to Claude Code's own behavior
return next(e);
});
Hooks chain like middleware, and a hook can observe (call next(e), then inspect the result), rewrite (pass a modified event to next) or answer (return something like { deny: "…" } without calling next). Events cover tool calls, the submitted prompt, turns starting and finishing, session start and end, slash commands, and ui.render for each piece of the interface as it's drawn.
Here's how that maps to the lede:
- The secret reminder becomes a guard: a
tool.callhook on Bash answers with a denial. A hands-on build on Towards Data Science (TDS) does this forcat .env. The author had repeated that warning in 20 of 60 sessions. - The
/contexthabit becomes a readout: Anthropic's Token Weather (built in Try it below) draws a context-window forecast above the prompt. MakeUseOf's review describes a Context-bar mod that shows a stacked breakdown by category above the prompt. - The transcript hunt becomes a review view: MakeUseOf describes Replay Theater's
/replay, which steps through the previous editing turn one diff at a time.
Unlike a settings hook, which runs a shell command per event and passes JSON over stdin and stdout, a mod is loaded once and keeps state. It draws UI that updates as events happen, and it can call back into Claude Code to open a pane, run a process, or register a slash command or a tool the model can call. The TDS author found that each settings-hook check launched a separate process and took 55–99 milliseconds on their laptop. No source measures a mod's overhead to compare.
Anthropic builds parts of Claude Code this way: Latent Space lists six built-in mods under /plugin → Installed and says mods work in both the CLI and Desktop.
Alternatives the sources cover:
- Settings hooks with
onFailure: "block": these run out of process and keep no state or UI. Developers Digest reports that v2.1.295 (October 8) added this option for command and HTTP hooks, so a broken guard blocks instead of passing. - Permission deny rules: Developers Digest notes that "a deny rule in permissions cannot crash." So they're the first choice when a policy fits a pattern, though with no custom logic or display.
- Codex CLI: relies on kernel-level sandboxing (Blake Crosley's guide: Seatbelt on macOS, Landlock plus seccomp on Linux). Developers Digest finds no fail-closed switch for its hooks, so the sandbox is the real boundary.
- Cursor hooks: per Developers Digest, they fail open by default but offer
failClosed: true.
Who it's for
Pick this up if you use Claude Code daily and can name a rule you keep retyping, a number you keep checking, or a review step you keep doing by hand. You also need to read, or have Claude write, a few dozen lines of JavaScript, and test them. This is the vibe-engineering move: replace a hoped-for behaviour with a check that runs every time.
Skip it in four cases:
- Your team is on Codex or Cursor.
- A permission deny rule already covers your policy.
- You need an extension API that won't shift between releases.
- Nobody will vet third-party mod source before it's installed.
Before and after
Before: "never print secrets" lives in CLAUDE.md and chat, you type /context when the session feels heavy, you dig through the transcript after a refactor, and any settings hook you wrote has to never go missing or time out.
After:
- A guard mod on
tool.calldenies the commands you've named, whether or not the model remembers the rule. - A readout above the prompt updates after each turn.
- A review command like
/replaywalks each edit in order (per MakeUseOf). - You run
claude plugin validateand, as TDS recommends,claude plugin test, and treat the mod as code under test.
Try it
Check your version first, per Anthropic:
claude --version # 2.1.287 or later
The shortest path is to describe the mod in a session. TDS prompted "Make a mod that blocks cat .env". Claude uses the built-in plugin-authoring skill and asks whether to turn on hot reloading.
That mod loads only in the session that made it. TDS says to copy its folder out of ~/.claude/dev-mods/ if you want to keep it. The DEV Community walkthrough, citing Anthropic's docs, says those folders are deleted without notice once they're older than cleanupPeriodDays, which defaults to 30 days.
To build by hand, follow Anthropic's worked example, Token Weather. The finished mod draws a one-line forecast of how full the context window is, just above the prompt, and updates it after each turn. The first step only puts fixed text there, which is enough to see how a mod is wired.
A mod is a plugin folder with three files you write:
token-weather/
├── .claude-plugin/
│ └── plugin.json
└── hooks/
├── hooks.json
└── token-weather.mjs
.claude-plugin/plugin.json is a standard plugin manifest: the mod's name, version, description and author.
{
"name": "token-weather",
"version": "0.1.0",
"description": "A live forecast of the context window, drawn above the prompt.",
"author": { "name": "You" }
}
hooks/hooks.json points Claude Code at the mod's code. A mod has exactly one module:
{ "modules": ["./token-weather.mjs"] }
hooks/token-weather.mjs is the mod. The band directly above the prompt is a component called AbovePrompt. Claude Code draws nothing there itself, so it's a good first target. This hook catches that band's ui.render event and returns what to draw:
// hooks/token-weather.mjs
export function register(on) {
on("ui.render", { component: "AbovePrompt" }, ($, e, next) => {
const { Box, Text } = $.ui.resolve(e);
return Box({
paddingX: 1,
children: [Text({ color: "yellow", bold: true, children: "☀ Clear skies" })],
});
});
}
register(on)is what Claude Code calls when it loads the module;onattaches hooks.on("ui.render", { component: "AbovePrompt" }, …)runs the hook each time that band is drawn. It returns its own elements without callingnext(e), so they fill the band.BoxandTextaren't globals.$.ui.resolve(e)returns the elements the surface being drawn supports, because each surface supports a slightly different set.- The result is a box with one space of padding holding "☀ Clear skies" in bold yellow.
Load it:
claude --plugin-dir ./token-weather
Per Anthropic, "☀ Clear skies" appears above the prompt. Keep the session open: the folder is watched, so each save reloads the module in place, with no restart. From there, Anthropic's post swaps the fixed text for a real reading. $.session.usage() returns the same context figures as the status line, the mod takes a reading at session start and after each turn, and it keeps the history in $.state so a reload doesn't wipe it. We haven't found an independent reproduction of the full Token Weather example.
To install someone else's mod, the DEV walkthrough shows /plugin install <name>@<marketplace> and then checking the Installed tab. None of the sources list a separate price for mods.
Where it breaks
- The API is young. Anthropic says it can change between releases. The type declarations Claude Code writes into
.claude-plugin/types/are the authority for your build. None of our sources say how breaking changes are announced. - Mods run as you. Anthropic's post says the module runs in a sandbox of its own, with no DOM and no Node. That limits the JavaScript runtime, not what a mod can reach:
$exposesfs,processandhttp. MakeUseOf, citing Anthropic's docs, says mods run with your permissions, can access files and secrets, aren't sandboxed from your system, and can start processes outside the Bash sandbox. It adds thatclaude plugin validateisn't a security audit. ClaudePluginHub scores one third-party mod, ai-cli-jobs, 27/100: it reads environment variables and can see, change or block tool calls. - Supply-chain risk is live. Help Net Security reported on October 30 that a tampered build (2.1.313) of the Claude Code extension for VS Code-compatible editors planted an SSH backdoor. It was an editor extension, not a mod, but the risk is the same: third-party code running with your access.
- Guards can fail open. Developers Digest showed a missing or timed-out settings-hook guard letting the command through unless
onFailure: "block"was set. Our sources don't confirm whether that setting applies to mods. TDS's guard adds a.catchso it fails closed on its own errors. - Coverage is narrow. TDS notes that blocking
cat .envleaves other commands that could expose secrets. Replay Theater watches only Edit and Write calls, not filesystem changes made through Bash.
Sources
- Getting started with Claude Code mods / claude.dev Blog · Anthropic
- Claude Code Mods: Custom Hooks to Fix My Biggest AI Coding Frustrations · Towards Data Science
- Claude Mods: Flipping the Harness Inside Out · latent.space
- I installed 3 Claude Code mods, and now the default version feels unfinished · MakeUseOf
- ai-cli-jobs · ClaudePluginHub
- Claude Code Mods คืออะไร? ปลั๊กอิน AI ที่ให้คุณแก้หน้าจอและพฤติกรรมของ agent เอง · DEV Community
- Claude Code extension poisoned with persistent SSH backdoor - Help Net Security · Help Net Security
- Do Your Agent Hooks Fail Open? Claude Code vs Codex vs Cursor vs Gemini CLI · Developers Digest
- Codex CLI Guide 2026: Setup, Sandbox, AGENTS.md & MCP · Blake Crosley
- @bibryam: 🌟 Claude Code Mods Explained 🌟 · @bibryam