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.
Get the files
Drawn in your browser from the name above. Nothing is uploaded anywhere.
- Pane picturebrass-otto-tile-128.png128 × 128 PNG, transparent corners. For a mod's Image in the terminal, and as your site's icon.
- Vectorbrass-otto-tile.svgSVG, presentation attributes only. For a mod's Svg in Claude Desktop and VS Code.
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
- 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. - Download the Pane picture into
~/.claude/buddy/. Prebuilt names also have a face per mode, listed under "For agents". - 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.
- Run
/reload-plugins, or start a new session. Your buddy sits in the pane and changes as Claude thinks, works, talks or needs you. - 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
- Claude shows a custom connector with the favicon of your server's main domain (
example.comformcp.example.com), not with an icon you set. - Put the Pane picture on that site as its icon:
<link rel="icon" href="/brass-otto-tile-128.png">. - 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.
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// .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": { "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
| Format | Claude Code: PNG (Image), SVG (Svg, Desktop and VS Code). Connector: your site's favicon. |
|---|---|
| Max size | Image up to 2 MiB; SVG up to 131,072 characters |
| Dimensions | You choose the cells, up to 255 a side. The connector icon shows at about 64 px. |
| Crop | None in Claude Code: the tile shows as it is. The connector icon's shape unverified |
| Animation | Yes in a mod, frame by frame. Not in the Claude app. |
| Who can set it | You, 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 faces | Yes 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.