# Claude Code Mods: Building Custom UI and Behavior from Inside the Agent


Claude Code v2.1.287, released October 1, 2026, shipped a new extensibility system called Mods. A mod is a JavaScript or TypeScript file that runs inside the Claude Code process and hooks into its internal event pipeline. **Unlike external hooks, which observe events from outside and can't modify them, mods can intercept tool calls before they execute, rewrite events mid-flight, render custom UI panes** and status bands, and stop events entirely. Some of Claude Code's own built-in features, including the `/diff` command, are implemented as mods.

This article covers how the architecture works, what the three interaction modes look like, how to build your own mods by describing them to Claude, and what the security implications are.

<iframe class="aspect-video h-auto" width="100%" height="315" src="https://www.youtube.com/embed/Hvy3ySQZuTY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>




## Mods vs. hooks

![A diagram illustrating the architectural difference between external Hooks and internal Mods, showing that Mods can rewrite events, draw UI, and replace features, while Hooks cannot.](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/9be796cc-22d5-42c8-2599-2caef72f0d00/public =1920x1080)

External hooks (`hook.sh` or similar) run as separate processes. Claude calls out to them when events occur, they receive data about the event, and they can run external logic, but they can't modify what Claude does next. They're useful for logging, notifications, and triggering external pipelines.

Mods run inside the Claude Code process. They receive the same event and can choose what happens to it: let it through unchanged, modify it before it proceeds, or stop it entirely. They can also draw UI elements: new panes, status bands above the input area, buttons, text fields, and custom animations. Mods work in the CLI and the desktop app Code tab. Organization administrators can restrict which mods load.

No Node.js, bundler, or build step is required. Claude Code loads `.js` and `.ts` files directly.

## The three interaction modes

![An animation showing the flow of events from Claude Code, through a TypeScript mod which can observe, rewrite, or skip them, before they reach the terminal.](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/55a21305-d525-4f69-4846-9e30a0761f00/lg1x =1920x1080)

**Observe:** The mod listens for an event and runs code when it fires, without changing anything. A usage counter that increments on every `tool.call` event is a simple observe-only mod.

**Rewrite:** The mod intercepts an event, changes its contents, and passes the modified version downstream. A safety mod could watch for `tool.call` events containing `rm -rf /`, rewrite the command to a safer alternative, and let the modified event proceed. The rest of the pipeline never sees the original.

**Skip:** The mod intercepts an event and returns without calling `next()`, preventing any downstream processing. A guard mod could intercept `git push --force` and stop it entirely, with or without showing an error to the user.

A hook receives the mods API as `$`. Calling `next()` passes the event onward. Not calling it stops the event. Modifying the event argument before calling `next()` rewrites it.

## Building mods by describing them to Claude

The fastest way to create a mod is to describe what you want in a Claude Code session. Claude writes the mod into `~/.claude/dev-mods/{session-id}/{mod-name}/` and loads it for the current session. These session mods are temporary and get cleaned up after `cleanupPeriodDays`. To make a mod permanent, either ask Claude to install it, or copy the directory to `~/.claude/mods/`.

### Example 1: a Minecraft HUD for usage metrics

A prompt like this produces a working mod in one pass:

```text
[output]
Can you build me a status line mod? I want an exact recreation of the
Minecraft HUD. Feel free to use the internet to download the real sprites.
I want the health bar to show my 7-day usage, saturation to show my 5-hour
usage, armor to show my Fable usage, and the XP bar to show my context
window usage.
```

Claude builds the mod, fetches the Minecraft sprite sheet, maps the usage API fields to the HUD elements, and displays it as a band above the prompt area.

![The final, polished version of the Minecraft HUD mod, displayed with a transparent background above the prompt bar.](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/897fe7ee-1117-4315-0c1b-dd3674dd3500/lg1x =1920x1080)

Two things the generated mod does that are worth noting:

**Undocumented API access.** The public mod API exposes 5-hour and 7-day usage figures but not Fable-specific usage. Claude examined what the `/usage` command does internally, found an undocumented API endpoint that returns the detailed breakdown, and called it with an authenticated request. A mod can do anything Claude Code itself can do, including using internal endpoints.

**Graceful degradation.** The desktop app can render SVG. The terminal cannot. The mod detects which environment it's running in. In the desktop app it renders the full pixel-perfect Minecraft HUD as an SVG. In the terminal it falls back to a Unicode block-character approximation of the same layout, so the mod works everywhere without any additional configuration.

### Example 2: a fake Twitch chat that backseats your coding sessions

A more complex prompt for a pane-based mod with AI-generated content:

```text
[output]
Make me a Claude Code mod called backseat: a fake Twitch chat that
backseats Claude while it works. When a turn starts, open a pane titled
"Backseat - LIVE" beside the transcript. Collect what Claude does
(tool name, a short summary, and whether it succeeded). Every few seconds,
call $.model.complete with model 'haiku' to write 2-4 short chat messages
reacting to it, Twitch style, with text emotes. Big moments: a failed test
-> chat spams F. rm -rf or git push --force -> monkaS.
Turn complete -> a gifted-subs alert.
```

The generated mod opens a scrolling pane on the right side of the transcript and continuously generates messages using the Haiku model (fast and cheap, to avoid slowing down the main task). As Claude reads files, runs tests, or executes shell commands, the chat reacts.

![The Claude Code interface with the "Backseat - LIVE" pane on the right, showing a stream of colorful, AI-generated chat messages reacting to the ongoing task.](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/5bcfd6b0-6ddb-42e7-ea95-d891ebb81e00/lg2x =1920x1080)

The chat detects specific events and responds to them: a build failure triggers a spam of `F` messages, a `git push --force` triggers `monkaS`, and a completed turn triggers a gifted-subs animation. Users can interact with it: typing `/backseat` reopens the pane if closed.

This example demonstrates two less obvious mod capabilities: running a separate model call on a cadence using `$.model.complete`, and building persistent interactive state across a session using `$.state`.

## Validating and testing mods

Before installing a community mod, run:

```command
claude plugin validate <directory>
```

This reads the plugin manifest and hooks module and reports any errors, the events the mod handles, and every mods API call it makes, without executing the mod code. It's the primary tool for reviewing what a mod will actually do before you load it.

For mods you're building yourself, add test files ending in `.test.ts` or `.test.tsx` and run:

```command
claude plugin test
```

This runs the test suite against the mod without loading it into a live Claude session.

To try a mod for one session without installing it:

```command
claude --plugin-dir ~/mods/my-mod
```

The complete TypeScript declarations covering every event, method, and render element are at [github.com/anthropics/claude-code](https://github.com/anthropics/claude-code/blob/main/mods/types/claude-code.d.ts). Full documentation is at [code.claude.com/docs/en/plugins/mods/overview](https://code.claude.com/docs/en/plugins/mods/overview).

## Security

Mods run with the full permissions of the Claude Code user. They are not sandboxed. A mod can read and write files, execute shell commands, make network requests, and intercept and rewrite every event in the pipeline including system prompts and tool call outputs. The only thing a mod cannot restyle is the permission prompt.

This means a malicious mod could rewrite your prompts to leak information, execute harmful commands silently, or read sensitive files and exfiltrate them. The `claude plugin validate` command helps you audit what a mod will do, but it's a static analysis tool, not a runtime sandbox.

The practical rule: only install mods from sources you trust, or mods you wrote yourself or had Claude write in your session. For organizations, administrators can configure which mods are allowed to load, providing a policy-level control that individual users can't override.

The first official community mod from Anthropic is "You Should Know" (`cc-plugin-you-should-know@builtin`), which runs a separate agent watching Claude's output and sends a "Heads up" message when it spots something important the user might have missed. Enable it with `/plugin enable cc-plugin-you-should-know@builtin`.