Claude Code mods: making the interface your own

A context bar, image previews, and inline diagrams show what changes when the coding tool itself becomes programmable.

In this note

A terminal can be a surprisingly good place to work with a coding agent. The conversation, commands, and changes stay together. But a few small things keep sending you elsewhere: an image turns into [Image #1], a diagram arrives as a block of source, and a setting you want to check lives behind another command.

Those are interface problems. A better answer from the model doesn't make the attachment visible again or put a useful control beside the prompt.

Anthropic introduced Claude Code mods on October 1. They let code change the application around the conversation. Three small examples make that idea tangible: a context bar, a hover preview for attached images, and Mermaid diagrams rendered directly in the transcript.

The three examples are in my Agent Harness repository, alongside reusable agent skills.

What a mod changes

A mod is JavaScript or TypeScript loaded inside Claude Code. It registers functions for events such as a turn finishing or a piece of the interface being drawn. Each function can let the event continue, change what gets passed along, or supply the result itself.

The packaging is familiar: mods ship inside plugins. A plugin is the installable bundle; the mod is the code in that bundle that participates in Claude Code's behaviour. That distinction matters because a plugin can also contain skills or an MCP server.

This also makes mods different from a shell hook, which runs a separate command when a configured event occurs. A mod stays loaded in the session and can connect an event to an interface that the person using Claude Code can interact with.

Context beside the prompt

The context-bar example puts the current model, effort setting, working folder, Git branch, permission mode, and context usage in one band above the input. The model and effort labels open menus. That turns a readout into a place to act.

Its implementation separates collecting information from displaying it. At session start and after a completed turn, it reads the host's usage figures, checks the working directory and branch, and updates the stored values. A separate once-per-second check keeps the model, effort, and permission labels in step with the host.

The distinction is useful: the usage number is a reading from Claude Code, not a fresh measurement made by the bar. The mod doesn't make the context window larger. It makes the reported usage easier to notice before sending another request.

An open effort menu with high selected above a context bar showing Sonnet 5.5, the working folder, main branch, auto permission mode, and 3 percent context usage.
The effort menu sits beside the information it changes. Detail from an author-supplied Claude Code v2.1.289 capture, added after this article's October 2 date. Open the full capture.

Selecting an effort level runs Claude Code's existing /effort command. Selecting a model runs /model with a family alias, then checks the session's model again. The menu gives those commands another entrance; the host still decides which choices it supports.

That's a useful boundary to keep visible. A button can offer a choice that a particular host or account won't accept. The mod needs to handle that result rather than assume that changing its label changed the session.

Keep other mods in view

A band above the prompt sounds simple until two plugins both want to draw there. The context bar and the Mermaid actions use the same render site, named AbovePrompt. How do they coexist?

A hook receives three arguments: $ is the mods API, e is the event, and next continues through the remaining handlers. Calling next(e) gives the other hooks and Claude Code a chance to produce their result. A UI hook can then include that result in its own layout.

One render site / two customizations

Keep the drawing that comes back.

hooks/register.jsIllustrative composition
export function register(on) {
  on('ui.render', { component: 'AbovePrompt' },
    async ($, e, next) => {
      const { Box, Text } = $.ui.resolve(e);
      const below = await next(e);

      return Box({
        flexDirection: 'column',
        children: [
          Text({ children: 'A custom status line' }),
          below
        ]
      });
    });
}
What the combined band contains

A custom status line This hook adds it

Copy code · Save PNG · Hide Returned by another hook

The highlighted lines preserve the result from the rest of the chain. Omitting below would discard that drawing. This simplifies the composition used by context-bar and mermaid-inline.

The launch walkthrough describes this as a chain of hooks. That makes next more than boilerplate: whether a hook calls it, what it passes, and what it returns determine how customizations stack.

Here the result is visual, but the same question matters for behaviour. A tool hook that answers an event itself stops the usual path. A hook that observes and continues leaves the rest of the path available. Composition is part of the feature's design.

An image reference you can see

After an image has been sent, its numbered reference is a useful identifier and a poor reminder of its contents. The image-preview example makes that reference hoverable. Move over [Image #1] and a thumbnail appears beside the message.

A three-tier architecture image appears in a hover card near an Image number 1 reference in a sent Claude Code prompt, while the assistant's explanation remains in the transcript.
The attachment becomes inspectable from its reference in the conversation. Detail from the same supplied v2.1.289 capture, added after the article date. The overlapping transcript text is visible in the original capture.

The code links image numbers to source-file metadata in the session messages. It uses macOS sips to make a PNG thumbnail, caches the result, and draws it in the user-message row. When it can't resolve the image or create a thumbnail, it leaves the normal message rendering in place.

That dependency on metadata is easy to miss. The visible number isn't the image, and the mod needs a route from the number to an available file. This implementation is also macOS-specific and targets an image-capable terminal. It isn't evidence that the same preview works in every Claude Code surface.

The change is small, but its purpose is precise: bring the thing being discussed back into view without reopening it elsewhere. It doesn't change what image the model received.

From Mermaid source to a picture

Mermaid describes diagrams as text. That's convenient for a model to generate and for a developer to edit, but the structure is often easier to understand once it's drawn. The mermaid-inline example closes that gap inside the conversation.

It looks for complete mermaid code fences in assistant messages. For each diagram, it writes the source to a temporary file and runs the Mermaid CLI, mmdc, to produce a PNG. The rendered image replaces that block in the displayed message; surrounding prose remains Markdown.

Claude Code displays a Mermaid architecture diagram with client devices, a server, and a database inside its transcript, with Copy code, Save PNG, and Hide actions above the prompt.
The diagram is visible where Claude's reply appears, with actions for the newest diagram above the prompt. Detail from an author-supplied v2.1.289 capture, added after the article date. Open the full capture.

Two details keep this from becoming a fragile decoration. The parser waits for a closing fence, so a half-written streaming block remains text. If the renderer fails, the original code block is displayed instead. A cache avoids repeatedly rendering identical source within the loaded module.

The buttons operate on the newest diagram. Copy code preserves the editable source. Save PNG renders a separate file on a white background. Hide clears the action row; it doesn't remove every diagram from the transcript.

A mod supplies the integration, not every dependency. This one still needs mmdc and terminal image support. Its save-and-open action also uses the macOS open command. And a neatly rendered diagram can still describe the wrong architecture: displaying the output doesn't verify it.

Start with one visible change

For a first mod, pick a change that's easy to see and easy to judge. A branch label above the prompt is a better starting requirement than an entire replacement interface. Anthropic's mod creation guide also supports describing the feature to Claude Code and letting it write the plugin.

Make a Claude Code mod that shows the current Git branch
above the prompt. Update it after each completed turn.
Preserve anything other mods draw in the same band.
If this folder isn't a Git repository, show nothing.

That request defines an event, a location, and a failure case. It also says what should happen when the feature shares space with another customization.

The minimal package has a manifest at .claude-plugin/plugin.json, a hooks/hooks.json file naming the module, and the module exporting register. For a local plugin directory, the basic review loop is:

claude --version
claude plugin validate ./branch-label
claude --plugin-dir ./branch-label

Mods require v2.1.287 or later. Inspect the generated types for the installed host when working against the API, and test the visible result in the interface where it will be used. Validation can help inspect a package; it doesn't establish that a menu works, a thumbnail appears, or two mods share a render site correctly.

There is also a real trust boundary. Anthropic's announcement says mods aren't sandboxed and run with Claude Code's access to the machine. A pleasant-looking UI doesn't limit the code behind it. Read the module and its process, file, and network calls before treating a plugin as a cosmetic add-on.

A smaller gap between work and interface

The useful idea in mods is that a recurring interruption can become a small piece of software. A setting can live beside the prompt. An attachment can stay visible from its reference. A diagram can appear where its source was generated.

Each example has a narrow job, a host API behind it, and a fallback when the ideal path isn't available. That gives a practical way to choose the next customization: find something the interface keeps making you leave the conversation to do, then build the smallest change that brings it back.

Keep this article in your starred list.

↑ ↓ to explore · Enter to open