Skip to content

Set up · Claude

Your buddy in Claude

A Block Buddy is a face for your agent, drawn from its name. In Claude Code, a mod can show it in a pane beside your session, changing as Claude thinks, works and waits for you. Use the tile, transparent corners and all. The Claude app has no avatar setting.

What a Claude Code mod can show: the tile as it is, in a pane, at any size you choose.

Get the files

Drawn in your browser from the name above. Nothing is uploaded anywhere.

A mod shows PNG, not GIF or video, so our animated loops will come to Claude Code inside a ready-made plugin, frame by frame. That plugin isn't built yet.

Claude Code: a buddy in a pane

  1. Update Claude Code to v2.1.287 or later (claude --version). Real pixels show in kitty 0.28+, Ghostty and iTerm2 3.5+. In iTerm2, use v2.1.305+ and /tui fullscreen.
  2. Download the Pane picture into ~/.claude/buddy/. Prebuilt names also have a face per mode, listed under "For agents".
  3. Ask Claude Code: "Make a mod named block-buddy that opens a pane called buddy and shows the PNG for the current mode from ~/.claude/buddy, switching on the spinner's mode." Or paste the sketch below.
  4. Run /reload-plugins, or start a new session. Your buddy sits in the pane and changes as Claude thinks, works, talks or needs you.
  5. Want it in the status line too? Add the statusline snippet below to ~/.claude/settings.json. It shows your buddy's name in its own colour.

In other terminals, inside tmux or screen, and in background sessions, a mod's Image shows its alt text instead. Colour cells that work everywhere need a file we don't make yet.

The Claude app: your connector's icon

  1. Claude shows a custom connector with the favicon of your server's main domain (example.com for mcp.example.com), not with an icon you set.
  2. Put the Pane picture on that site as its icon: <link rel="icon" href="/brass-otto-tile-128.png">.
  3. Wait for it to show. Claude fetches it through Google's favicon service, which can take a while to update.

Claude itself, Projects and Skills have no avatar or icon setting. On a shared host (*.vercel.app) or a two-part country domain (.co.uk), the connector shows the wrong icon.

For agents

A mod reacts to Claude Code's own events. Map them onto your buddy's modes and redraw the pane when one changes.

Instructions
platform: claude-code (a mod) and claude.ai (a connector)
shows:    a mod's Pane or the band above the prompt, at any cell size; claude.ai shows your domain's favicon
variant:  tile (the 19% rounded square, transparent corners)
file:     brass-otto-tile-128.png
modes:    brass-otto-tile-<mode>-128.png (hosted for prebuilt names)
vector:   brass-otto-tile.svg, for Svg in Desktop and VS Code (up to 131,072 characters)
buddy:    Brass Otto
hash:     0x4f7857573d121112474507868c95e98e2cbb66d73cc61e786482793f28ed9bb0
image:    PNG up to 2 MiB, 1 to 255 cells a side; terminal only; real pixels in kitty, Ghostty, iTerm2
per-mode: Spinner mode requesting, thinking > thinking · responding > speaking · tool-input, tool-use > working
          classic.PermissionRequest > needs-you · turn.complete reason error > error
statusline: text and 24-bit colour only. No images, and no turn state in its input.
claude.ai: connector icon = your apex domain's favicon (serverInfo.icons is ignored today)
mcp:      icons: [{src, mimeType, sizes, theme}], https or data:, same origin as the server
checked:  2026-10-21
A mod, sketched: hooks/register.js
// .claude-plugin/plugin.json, and hooks/hooks.json: {"modules":["./register.js"]}
const FROM_SPINNER = { requesting: 'thinking', thinking: 'thinking', responding: 'speaking',
                       'tool-input': 'working', 'tool-use': 'working' }
let mode = 'idle'

export function register(on) {
  const set = ($, m) => { if (m !== mode) { mode = m; $.ui.invalidate('ui.render') } }
  on('session.start', async ($, e, next) => { await $.ui.open({ id: 'buddy' }); return next(e) })
  on('turn.start', async ($, e, next) => { set($, 'thinking'); return next(e) })
  on('classic.PermissionRequest', async ($, e, next) => { set($, 'needs-you'); return next(e) })
  on('turn.complete', async ($, e, next) => { set($, e.reason === 'error' ? 'error' : 'idle'); return next(e) })
  on('ui.render', { component: 'Spinner' }, async ($, e, next) => { set($, FROM_SPINNER[e.props.mode] ?? mode); return next(e) })
  on('ui.render', { component: 'Pane' }, async ($, e, next) => {
    if (e.requestId !== 'buddy') return next(e)
    const { Box, Image, Text } = $.ui.resolve(e)
    if (e.surface !== 'terminal') return Text({ children: ['Brass Otto · ' + mode] })
    const home = await $.env.get('HOME')
    const file = `${home}/.claude/buddy/brass-otto-${mode === 'idle' ? 'tile' : 'tile-' + mode}-128.png`
    return Box({ children: [Image({ key: 'face', columns: 12, rows: 6, source: { file, format: 'png' }, alt: 'Brass Otto is ' + mode })] })
  })
}
Statusline: ~/.claude/settings.json
{ "statusLine": { "type": "command",
  "command": "printf '\\033[38;2;105;121;140m■ Brass Otto\\033[0m · %s' \"$(jq -r .model.display_name)\"" } }

The sketch uses only documented mod APIs. Mods change often: if a name has moved, your build's own types win. iTerm2 needs the picture as base64 (source.png), not a file path.

Limits

FormatClaude Code: PNG (Image), SVG (Svg, Desktop and VS Code). Connector: your site's favicon.
Max sizeImage up to 2 MiB; SVG up to 131,072 characters
DimensionsYou choose the cells, up to 255 a side. The connector icon shows at about 64 px.
CropNone in Claude Code: the tile shows as it is. The connector icon's shape unverified
AnimationYes in a mod, frame by frame. Not in the Claude app.
Who can set itYou, by installing a mod. For a connector, whoever runs its website. The connector's favicon route is seen in practice, not documented unverified
Per-mode facesYes in Claude Code, driven by its own events. No in the Claude app.

Last checked 2026-10-21 against Mods, Mods reference, Status line, Custom connectors and the MCP spec. Claude Code ships changes almost daily; we re-check this page monthly. If a step is wrong, the platform's own docs win.