← All articles
Claude · How-to

Claude Code mods: a small file that rewrites what you see

What a Claude Code mod is, how it slots into the session as a hook, two examples from the official guide, and Recording Mode to hide secrets on screen.

Picture filming a cooking video in your own kitchen. Behind you, the fridge door is covered with an electricity bill, a pay slip and the school calendar with your kid’s name on it. You don’t want to empty the fridge door; you just want the camera to blur those papers while it films. The kitchen stays exactly as it is. Only the picture changes.

That is the problem I ran into the first time I recorded a Claude Code demo. The terminal is the kitchen: .env values scroll past, an email shows up in a tool result, a figure appears in a file. Claude Code mods are the camera that blurs.

In one sentence: a mod is a small JavaScript or TypeScript file that runs inside your Claude Code session, where it can observe what happens, answer in Claude Code’s place, or rewrite what is drawn on screen.

What a mod actually is

Claude Code already lets you shape a lot of its behaviour: settings, permission rules, slash commands, skills, a status line. Mods go one step further. According to the official guide, a mod is a Claude Code plugin whose behaviour lives in a JavaScript or TypeScript module. The folder is a normal plugin with a .claude-plugin/plugin.json manifest, hooks/hooks.json names exactly one module under modules, and that module exports register(on, options).

Inside register, every call to on(event, matcher?, hook) adds a hook. The events cover tool calls, the prompt as submitted, turns starting and finishing, the session starting and ending, slash commands, and ui.render, which fires for every piece of the interface as it is drawn. The module runs in its own sandbox, with no DOM and no Node, so everything it does outside itself goes through $, the mods API.

The difference with the hooks you put in settings matters. A settings hook runs a shell command for each event and talks JSON over stdin and stdout. A mod is loaded once and stays in the session: it can keep state, draw UI that updates as events arrive, open a pane, run a process, register a slash command or a tool the model can call. Anthropic eats its own cooking here, too: AGENTS.md support and the /diff pane are built as mods, with their source in the public anthropics/claude-code repository under mods/.

You need Claude Code 2.1.287 or later. Mods are on by default in that build, but the API can change between releases: each time a mod loads, Claude Code writes the type declarations for your build into the mod’s .claude-plugin/types/ folder, and those are the authority for your version.

Every hook has the same shape. This is the example from the guide, verbatim:

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 form a chain, like middleware in a web server. Your hook runs, next(e) hands the event to the next plugin, and at the bottom Claude Code does what it would have done anyway. From that position, a hook has exactly three moves.

Eventtool.callYour mod($, e, next)Other pluginssame shapeClaude Codedoes the workObserveawait next(e), then lookRewritenext({ ...e, command })Answer{ deny } without nextnext(e) hands the event to the next link
An event goes through your mod before reaching the other plugins and Claude Code. From there, the mod observes, rewrites or answers.

Observe: call await next(e) first, then look at the result, for example to take a reading after each turn. Rewrite: pass a modified event, next({ ...e, command }), so the rest of the chain sees something else. Answer: return { deny } without calling next, which refuses a tool call or serves a command yourself. Everything a mod does is a combination of those three.

Two examples from the official guide

The guide builds Token Weather, about 80 lines, which draws one line above the prompt with a live forecast of the context window: ☀ Clear under 25%, ☁ Cloudy, ☂ Showers, ☇ Storm from 75%, ↯ Compact soon at 90% and up. In the guide’s recording, the band goes from 18% to 67% to 81% of a 200k window over three turns. It is pure observation: it reads $.session.usage() after each turn and redraws.

The second one, Blast Radius, uses the third move. When Claude calls Bash with rm -rf, git reset --hard, git clean, a force push or a database migration, it holds the call, works out what the command would touch, and opens a pane with Proceed and Cancel. In the demo it holds rm -rf build and lists the 9 files (1.1 MB) it would delete. Cancel sends Claude a refusal with the reason. The guide is honest about its limit: it reads the command text, so $(…), aliases and scripts that call rm get past it. It is a safety net, not a permission system; use permission rules for a hard block.

Recording Mode: the screen changes, not the data

The mod that solves my kitchen problem is not from the guide. Recording Mode comes from a community repository by Nate Herk, under the MIT licence. You type /rec before you hit record, and it applies to every open chat within 3 seconds; /rec off turns it off everywhere.

While it is on, it masks on screen API keys and tokens, every value in a .env file in the project folder or its parents, emails, names, phone numbers, addresses, card and account numbers, money, and figures next to business words such as revenue or payroll. /rec strict also masks every large figure and percentage. It keeps .env files, SSH and cloud keys, Claude’s memory folder and finance documents closed, and a red ● REC sits above the prompt.

Real result.env, keys, emailsClaudegets the real dataRecording Moderewrites what is drawnScreen●●●● masked
With Recording Mode, Claude still works on the real data. Only what is drawn on screen is masked.

The key point is in the README: tool results from mail, chat, calendar, CRM or finance tools are hidden on screen, but Claude still gets the real result. Only the screen changes. That is exactly the fridge door from the opening: the kitchen is untouched, the camera blurs.

Try it

First, check your version: 2.1.287 or later.

claude --version

Then add the community mods repository, after reading it.

claude plugin marketplace add nateherkai/claude-code-mods

Install Recording Mode, open a new chat, then type /rec before you record.

claude plugin install recording-mode@nateherk-mods

To make it yours, /rec config creates a config.json under ~/.claude/mods-data/recording-mode/ where you list names to always mask, your own name to keep visible, and private paths Claude may not open while recording.

Writing your own

You don’t need to learn the API to get started. Run claude, describe the mod you want in plain words, and allow hot reload when it asks: the mod shows up when the turn ends, and every later tweak reloads in place. The guide’s advice is to keep data in $.state rather than module variables, because each reload runs register again. Since a mod is just a plugin, you share it like one: a GitHub repository with a marketplace file is enough.

In short

A mod is a link in the chain between what happens in your session and what Claude Code does or draws. Observe, rewrite, answer: three moves are enough for a weather band, a guard on rm -rf or a camera that blurs your secrets. Start with Recording Mode before your next demo, then describe your own to Claude.

Sources

  1. Consonance · Claude Code mods: two examples from the guide, and a real mod for recording your screen
  2. claude.dev · Getting started with Claude Code mods
  3. GitHub · nateherkai/claude-code-mods, Recording Mode (MIT)

#claude-code#mods#plugins#privacy