All Lessons
Lesson 066

Mods: Plugins That Run Code Inside Claude Code Itself

2026-10-02
modspluginsadvanced
Quick Quiz
What can a Claude Code Mod do that a settings hook (the shell-command kind configured in settings.json) can't?
Click to reveal answer
A Mod's JavaScript/TypeScript handlers run inside Claude Code's own process, so they can draw interface elements (panes, bands, buttons), redraw built-in UI like the spinner, and share in-memory state across hooks. A settings hook only runs an external script or HTTP request on an event — it can't touch the interface or hold state between calls.

A plugin that runs inside Claude Code, not alongside it

Claude Code has long had settings hooks — shell commands or HTTP requests that fire on lifecycle events like a tool call or a submitted prompt. Those run outside Claude Code's process: they can allow, block, or log an event, but they can't touch the interface or remember anything between calls. Mods change that. A Mod is a plugin whose JavaScript or TypeScript code registers event handlers that Claude Code calls directly, in its own process — on a tool call, a submitted prompt, or even a UI element being drawn.

Because a Mod's code runs inside Claude Code itself, it can do things a settings hook never could: draw a pane beside the transcript, redraw the built-in spinner, hold a risky shell command and ask the user before it runs, or add a /command that fires instantly with no model turn. A Mod's handlers also share the variables in its file, so one hook can track state (like a tool-call counter) while another displays it.

What a minimal Mod looks like

A small Mod is three files: a plugin manifest, a hooks.json pointer, and a code file. This complete example counts tool calls and shows the running total next to the spinner:

let calls = 0

export function register(on) {
  on('tool.call', async ($, e, next) => {
    calls += 1
    $.ui.invalidate('ui.render')
    return next(e)
  })

  on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
    return next({ ...e, props: { ...e.props, suffix: ' · tool calls: ' + calls + '…' } })
  })
}

Some of Claude Code's own features already ship as built-in Mods — /diff is one, and you can disable or replace it from /plugin. You can write a Mod by hand, or just describe what you want in a session and ask Claude to write it for you.

The catch: no sandbox

Mods run with your full permissions and aren't sandboxed, even if you've enabled Claude Code's sandboxing for Bash commands. A Mod can read your files and secrets, see every prompt and tool call in your session, and even auto-approve a tool call that a deny rule would otherwise block. Install Mods only from authors and marketplaces you trust, and run claude plugin validate ./some-mod before installing one to see exactly which events and API calls it registers.

Mods require Claude Code v2.1.287 or later and are on by default. Disable all of them at once with "disableAllHooks": true in settings.json, or start a session with --safe-mode to turn off every customization for that run.

Key Takeaway

A Mod is JavaScript that runs inside Claude Code's own process — it can draw UI and rewrite tool calls live, but since it isn't sandboxed, only install one from a source you trust, and check it first with claude plugin validate.