Bobby-cell-commits/named-subagents-mod

Claude Code mod: a themed, unique name for every subagent in the task tree, and a pane listing the running agents under those names. Replaces the retired named-subagents Python plugin.

See the code

See what people are saying

SourceMessageScoreDate

I gave my Claude Code subagents names (Turing, Magellan, Holmes) and a pane that lists them - named subagents mod (r/ClaudeAI)

When I fan out four subagents the task tree shows four general-purpose rows. I wanted to tell them apart, so I wrote a mod: every subagent gets a themed name from a 395-name pool (explorers for Explore, coders for code, detectives for debugging, …), never two live agents with the same one, and the…

0

Oct 7, 2026

README

named-subagents-mod

CI

Fan out several subagents in Claude Code and the task tree shows each one by its type. This mod gives every subagent its own themed name instead (Turing, Magellan, Holmes), drawn from a 395-name registry and never shared by two live agents. It also lists the running agents under those names in a pane beside the conversation: what each one is doing, its tokens and its clock, with its whole conversation a press away (see The agents pane).

A Claude Code 2.1.292 session in the fullscreen layout, 150 columns: four subagents fan out and the agents pane opens beside the transcript, listing them as Basquiat, Eames, PaulRand and Mucha with what each is reading, its tool count, tokens and clock; the task tree under the prompt shows the same four names; after /names set pirates and /names use pirates the next three are Bonny, Kidd and Teach, and the pane ends on a receipt for all seven

The GIF is a real session, not a mock-up: scripts/capture_demo.sh drives Claude Code in tmux and saves the screen twice a second, and scripts/render_tree_gif.py draws the whole screen for some of those frames, holding the ones with something to read. Two things are taken out: the banner is blanked and the home directory in a path reads ~. It was recorded on 0.3.0 in a 150-column terminal in the fullscreen layout (/tui fullscreen), where the pane docks beside the transcript and opens by itself. In a terminal under 144 columns you get a line under the prompt counting the running agents and a toast as each finishes, and /roster opens the pane.

It is a Claude Code mod (function hooks), so it needs Claude Code 2.1.287 or later and nothing else: no Python, no Node at runtime. It replaces the retired named-subagents Python plugin (last release 0.7.2).

The name is for you to read: the agent is not told its name (the engine does not put a mod-set name into the subagent's context), so there is no SubagentStart queue, ledger or file lock, and no burst-start pairing to get wrong.

Install

Type this at the prompt of a terminal session:

/plugin install named-subagents-mod --marketplace Bobby-cell-commits/named-subagents-mod

Answer y to add the marketplace, pick a scope (user = every session), and set the options or keep their defaults. The options screen is where you can type your own names straight away (see Your own names). The mod is active from then on; no reload is needed.

From a shell instead:

claude plugin marketplace add Bobby-cell-commits/named-subagents-mod
claude plugin install named-subagents-mod@named-subagents-mod --scope user

Your own names

Three ways in, all feeding the same pool. Use whichever is nearest to hand.

1. The options screen (at install, or later with /plugin configure named-subagents-mod or /config). Type names into Your names, separated by commas: Ripley, Deckard, Mary Shelley. They join every built-in pool and get about half of the draws while one of them is free, so even two names show up often. Turn on Use only my names to leave the built-in names out.

2. The /names command, in any session. It keeps your names in one file and applies to the next agent dispatched:

/names                             what is set, and where the files are
/names add Ripley "Mary Shelley"   more names, for every built-in pool
/names remove Sisyphus             never draw this name
/names rename Turing Alan          call one name something else
/names set pirates Kidd Bonny      define a set (a pool of your own); same name again replaces it
/names unset pirates               drop a set
/names use pirates | auto          draw every agent from one pool, or go back to picking by task
/names only on | off               leave out the built-in names
/names import <file>               merge a names file, a JSON list, or one name per line
/names reset                       clear your file (a .bak copy is kept)

import joins what it reads with what you have: lists are added to, and a set of the same name gets the new names as well.

3. A names file, for whole sets, dotfiles and sharing: ~/.claude/named-subagents.json (under CLAUDE_CONFIG_DIR when that is set). A project can carry its own at .claude/named-subagents.json, layered on top of yours. Every key is optional:

{
  "only": false,
  "use": "pirates",
  "names": ["Ripley", "Deckard"],
  "remove": ["Sisyphus"],
  "rename": { "Turing": "Alan" },
  "sets": {
    "pirates": { "names": ["Blackbeard", "Bonny", "Kidd"], "for": ["Explore"], "keywords": ["search", "find"] },
    "code": { "names": ["Neo", "Trinity"], "replace": true }
  }
}
KeyMeaning
namesExtra names. They join every built-in pool, not the sets you define, and get about half of the draws while one of them is free (so do names a set adds to a built-in pool).
renameOld name to new name.
removeNames never drawn. Applied after rename, so a renamed name is hidden by its new name.
setsA set is a pool of your own. for lists the agent types that draw from it and wins unless one pool is pinned (use, or the Name pool option); keywords match the task description. A set named like a built-in pool (code, explore, …) adds to that pool, or with "replace": true takes its place. "pirates": ["Kidd", "Bonny"] is short for a set with just names.
useOne pool for every agent, whatever its type. Wins over the Name pool option; auto or absent leaves the choice to that option, which picks by type and task unless you pinned a pool there.
onlytrue leaves out everything before this file, the built-in names included.

Order: built-in names, your file, the project's file, then the options screen's names. examples/pirates.json is a set to try, from a checkout of this repository: /names import examples/pirates.json.

The name rule. Claude Code accepts an agent name made of letters, digits, _ and -, starting with a letter or digit, up to 64 characters, and refuses the whole dispatch for anything else. So names are cleaned on the way in: Mary Shelley becomes MaryShelley, Zoë becomes Zoe, O'Brien becomes OBrien. A name with nothing usable in it (名前, an emoji) is skipped and reported.

Limits. A names file is read as untrusted input, since a project's arrives with the repository. A file over 256 KB is not read. A list holds up to 2,000 names, a file up to 100 sets, and a set up to 200 for or keywords entries; what is over is left out and reported. Anything quoted from a file in a warning or in /names output has its control characters replaced, so a file cannot send escape sequences to your terminal. A name holding a control character is skipped.

When a file is wrong. A file that is not valid JSON, a name that cannot be used, or an unknown key raises a toast and a status line once per change of the file; everything else in the file still applies, and agents are always named. /names lists the problems, and will not edit a file it cannot read in full, because rewriting it would drop the unread part; /names reset starts clean and keeps a .bak.

The agents pane

A roster of the session's subagents, one row an agent, in columns: its mark (spinning while it runs), its name, its task, the tool call it is running now or how it ended, its tool count, tokens and clock. From a live session (three agents, Claude Code 2.1.292):

✻ Agents · Haiku 4.5                                                             3 running

· DaVinci  Read retry.txt and write design es…  Read(retry.txt)    1 tool    25.1k     5s
✳ Hokusai  Read cache.txt and write design es…  Read(cache.txt)    1 tool    25.2k     4s
✽ Mucha    Read parser.txt and write design e…  Read(parser.txt)   1 tool    25.2k     3s

── timeline ──────────────────────────────────────────────────────────────────────────────
✻ DaVinci  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━    5s
✻ Hokusai  ············━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━    4s
✻ Mucha    ························━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━    3s

The names are the ones in Claude Code's own task tree: both read the engine's agent list. An agent the model named itself is listed under that name; one with no name (naming turned off) reads Type(description).

  • Where it shows. In the fullscreen layout (/tui fullscreen) it docks beside the transcript. On the main screen it is a summary of up to eight rows above the prompt, in the same columns. It opens by itself when an agent starts, in a terminal at least 144 columns wide; narrower than that, /roster opens it, and until then a line under the prompt counts the running agents (✻ 2 of 4 agents running).
  • A conversation. Press an agent's name or task: the pane widens and shows its brief, its replies and its tool calls with their results. b goes back, k and j step through it, Esc gives the keyboard back.
  • Folding. Ten seconds after the last agent finishes the pane folds to a tab above the prompt (◂ Agents ✓ 3); press the tab to bring it back, and a new agent brings it back by itself. The ▸ handle on the pane's left edge folds it by hand. /roster opens or closes it.
  • Also there. A model shared by every agent is said once, in the header. An agent's own subagents sit indented under it. A timeline puts the latest batch on one time axis. A finished batch gets a receipt (✓ 3 done in 8s · 21s of agent time (2.6× in parallel) · 3 tool uses · 158k tokens) and each finish a toast. ■ Stop, then Confirm stop, ends a running agent through Claude Code's own TaskStop. A background agent between turns counts as done; a teammate between turns reads waiting.
  • What it reaches. It watches: the agent list, each agent's tool calls (name and a short argument), its token usage, and its transcript while you have it open. Stop is its one action. It makes no network request, runs no process and keeps nothing after the session.

The pane is agentpane 1.1.4 by Anji Xu (MIT), brought into this mod with a name column, the roster layout and a few wording changes. See Credits.

What it reaches, and what it trusts

Everything the mod does goes through Claude Code's plugin API; it runs no process and makes no network request. What it reads and writes:

  • Reads: the session's agent list; every Agent dispatch (to set its name); each agent's tool calls (the tool's name and a short argument), its token usage and the model it runs on; an agent's transcript, only while you have its conversation open in the pane; HOME, USERPROFILE and CLAUDE_CONFIG_DIR; your names file and the project's; and a file you name to /names import.
  • Writes: your names file (~/.claude/named-subagents.json) and its .bak, on /names edits only. Nothing else, and nothing is kept after the session beyond that file.
  • One action: TaskStop on the agent whose conversation you have open, after you press Stop and then Confirm stop. The consent it gives the engine names the agent's type and id, never text a model wrote.

What it draws is not all yours. Agent names and descriptions are written by the model; tool arguments and results and the agents' replies come from whatever the agent read, a web page or a repository included; and a project's names file arrives with the repository. So all of it is treated as untrusted text: control characters, escape sequences and the characters that reorder text are removed before anything is drawn or quoted, every line is cut to length, a names file is bounded in size and in how many names, sets and routes it may hold, and a name must pass the Agent tool's own rule. An agent's replies are drawn as Markdown, as Claude Code draws its own transcript, so text an agent read can shape what its conversation shows you (a heading, a link, a line that looks like a button); it cannot press anything, run anything or reach the network, and a link in a reply is not pressable. The pane's buttons are its own elements, not text.

To check this without trusting the README, clone the repository and run claude plugin validate .: its calls: line lists every engine method the mod can call. For 0.3.0 that is $.agent.list, $.clock, $.command.register, $.env.get, $.fs.{exists,read,stat,write}, $.session.{messages,root,surfaces}, $.state, $.tool.call and $.ui.*; no $.http, $.process, $.model or $.mcp. A review of 0.3.0 for exploitable paths found none; its notes are in the changelog.

What it does

  • tool.call{Agent}: if the call has no name, draws one and calls next({ ...e, name }). The description is left as is. A model-supplied name passes through untouched.
    • Pool: the theme option pins one; auto matches subagent_type first (generic roles like general-purpose go by description keywords first), then the default pool. The pool is the built-in one with your names layered on; both names files are checked on every dispatch.
    • Uniqueness: skips every name in $.agent.list() and every in-flight draw. An exhausted pool spills to the default pool, then to any free name, then to Name-2, Name-3, …
  • agent.spawn: after the spawn, checks the name reached it and that $.agent.list() shows it on the new agent id. Anything else raises a toast and a status line (named-subagents: drew X but …). Neither hook can block a dispatch: both carry a .catch that continues the call.
  • The pane: agent.spawn lists an agent the moment it starts, a once-a-second read of $.agent.list() keeps the list current, tool.call records what each agent is doing, turn.step its tokens and model, and two ui.render hooks draw the pane and the summary above the prompt. Every one of them passes its event on unchanged.
  • One status line for both. Naming's alarm stands on it until the next clean spawn (a names file that is wrong, until it is fixed); with agents running and the pane off screen the count leads and the alarm follows: ✻ 2 agents running · named-subagents: your names file: not valid JSON ….
  • A failure in the pane's part of a shared hook does not skip naming's part, and naming's "naming failed" alarm is raised only when the name did not reach the call.

Options (userConfig)

Set at install, later with /plugin configure named-subagents-mod or /config (type the option's title to find it; a change applies at once), or in ~/.claude/settings.json under pluginConfigs, keyed by the plugin's id: named-subagents-mod@named-subagents-mod installed from the marketplace, named-subagents-mod@inline loaded with --plugin-dir. A project's .claude/settings.local.json did not carry them (Claude Code 2.1.292); --settings <file> does.

FieldDefaultMeaning
themeautoauto, or a category key (code, explore, debug, …) to always use that pool
enabledtruefalse turns naming off without uninstalling (and /names with it)
namesemptyYour names, separated by commas; they join every built-in pool
only_customfalsetrue leaves the built-in names out
panetruefalse turns the pane off: names only (see below)
autoOpentrueopen the pane when an agent starts; off, /roster opens it
foldAfter10seconds after the last agent finishes before the pane folds; 0 keeps it open
motiontrueanimate the spinner; off, it stands still and the clocks still run
toaststruea toast when agents finish
keepFinished8finished agents the list keeps (1–30)
statusLinetruecount the running agents under the prompt while the pane is not on screen

The first four are naming's. pane (Show the agents pane on the options screen) is the pane's one switch, and the six after it (Pane: …) adjust the pane while it is on. To have names without the pane, turn pane off: nothing opens, nothing is counted under the prompt, no finish toast and no tab appear, the agent list is not read every second and /roster is not offered. Naming, /names and the check of each spawned agent's name work as before. Turned off mid-session, an open pane closes and its list is forgotten; /roster stays in the command list until the session ends (a session cannot take a command back) and answers that the pane is switched off. enabled turns off naming only: the pane then lists agents by type.

Layout

  • hooks/index.ts: the hooks module hooks.json names; it registers the two halves.
  • hooks/names.ts: naming's hooks. hooks/draw.ts: pure draw logic. hooks/custom.ts: pure custom-names logic (the name rule, the names file, layering, /names edits). hooks/pool.ts: generated.
  • hooks/pane.tsx: the pane's hooks and drawing, and the two hooks both halves share (session.start, agent.spawn: a plugin hooks an event once). hooks/live.tsx, hooks/lanes.tsx: the spinner, clocks and timeline, drawn on the terminal's own frame clock. hooks/time.ts: pure time helpers. hooks/status.ts: the one status line the halves share. types/index.d.ts: the pane's $.state contract.
  • registry.json: the name pool (14 categories, 395 names), the source of hooks/pool.ts.
  • scripts/gen_pool.mjs: regenerates hooks/pool.ts from registry.json; --check exits 1 when it is stale.
  • scripts/capture_demo.sh, scripts/render_tree_gif.py: record and draw assets/demo.gif (tmux and Python with Pillow; not needed to use the mod). assets/demo-frames/ is the recording the GIF was drawn from, so python3 scripts/render_tree_gif.py assets/demo-frames assets/demo.gif redraws it.
  • spec/: draw and custom-names logic tests (plain node). tests/: hook tests (the engine's test kit): names.test.ts, pane.test.tsx and pane-logic.test.ts (the pane's own), and together.test.tsx (naming and the pane in one plugin).
  • examples/: a names file to import. probes/: the live proofs and the TUI capture driver.

Checks

node scripts/gen_pool.mjs --check   # pool matches the registry
node --test spec/*.spec.ts          # draw and custom-names logic, plain node 22.18+ (62 tests)
claude plugin test .                # hooks against the engine's test kit (150 tests)
claude plugin validate .

CI runs the two node checks; the two claude checks need a local Claude Code.

Develop

claude --plugin-dir . loads the checkout for one session. To run every session from a checkout, add the folder as a marketplace (edits apply after /reload-plugins):

claude plugin marketplace add /path/to/named-subagents-mod
claude plugin install named-subagents-mod@named-subagents-mod --scope user

Headless proof and TUI evidence: probes/mods-names-proof/ (naming), probes/custom-names-probe/ (custom names) and probes/pane-fold/ (one plugin for both: what the engine allows, and the live captures).

Known limits

  • The name shows in the task tree and in $.agent.list(); the transcript's launch list and finish notices quote the description only.
  • The name is display-only: a subagent cannot say its own name, and nothing records which name ran which task after the session ends.
  • A set smaller than the number of live agents runs out: the next draw comes from the default pool, then from any free name, then gets a number (Ripley-2).
  • /names edits your file only, and only while the whole file reads cleanly: one unknown key or bad entry and it asks you to fix the file by hand first. A project's names file is edited by hand. A project file can rename or hide names for anyone who opens that project (names only, within the name rule).
  • Overlapping draws (two dispatches in flight at once) are covered by the kit test only. In live runs the engine started same-message dispatches 0.5–2 s apart.
  • With the retired 0.7.2 Python plugin also enabled, the mod's name wins, but the Python hooks still run (see probes/mods-names-proof/README.md). Uninstall the Python plugin.
  • The pane opens by itself only in a terminal at least 144 columns wide (Claude Code's rule for a pane nobody asked for). Below that you get the line under the prompt and the toasts, and /roster.
  • A row has no token count in a pane under 88 columns and no tool count under 72; both are in the agent's conversation header.
  • The pane's start times are when it first saw an agent, and its tokens count from when the mod loaded.
  • Naming's alarm and the pane's finish notice share the plugin's one toast: the newer replaces the older. The alarm also stays on the status line.
  • A reload of the mod (an option changed in /config, /reload-plugins) forgets a standing alarm. A names file that is still wrong is alarmed again at the next dispatch; a "drew X but…" alarm is not.
  • If /roster cannot be registered the mod says so in a toast, and the pane still opens by itself and counts agents.
  • With the separate agentpane plugin also installed there are two panes with the same id. Uninstall it: claude plugin uninstall agentpane@claude-agentpane.
  • Not tried live: the pane in the desktop app, VS Code and mobile with named agents (the test kit draws them); a teammate's waiting row.
  • On the options screen a number option (fold after, finished agents listed) reads blank until you set it; the default (10, 8) applies all the same.
  • The mods API is new (Claude Code 2.1.287, 2026-10-01) and a release may change what this mod relies on; tested on 2.1.291 and 2.1.292 only. Both install paths above were tried on 2.1.292 from a clean CLAUDE_CONFIG_DIR.

Credits

The agents pane is agentpane by Anji Xu, version 1.1.4, used under the MIT licence. Its notice is kept in LICENSE-agentpane and covers hooks/pane.tsx, hooks/live.tsx, hooks/lanes.tsx, hooks/time.ts, types/index.d.ts, tests/pane.test.tsx and tests/pane-logic.test.ts, which carry this mod's changes on top.

The pane here is a copy, so agentpane's later fixes arrive only by hand. It was taken at upstream commit 17be889 (1.1.4). To bring a newer one in:

git clone https://github.com/xuanji86/claude-agentpane && cd claude-agentpane
git diff 17be889 <new commit> -- hooks/ types/

Apply that diff by hand to the files listed above (hooks/hooks.json there is not used here; a new or changed option is in .claude-plugin/plugin.json, so diff that file too). Three have other names there: hooks/register.tsx is hooks/pane.tsx here, hooks/pane.test.tsx is tests/pane.test.tsx and hooks/agentpane.test.ts is tests/pane-logic.test.ts. Then run the checks under Checks, and write the new commit here and at the top of hooks/pane.tsx. The command is /roster here and /agentpane there.

License

MIT. See LICENSE; the pane's files are under LICENSE-agentpane, also MIT.

agents
claude-code
claude-code-mod
claude-code-plugin
subagents
tui
typescript

Bobby-cell-commits/named-subagents-mod

Claude Code mod: a themed, unique name for every subagent in the task tree, and a pane listing the running agents under those names. Replaces the retired named-subagents Python plugin.

See the code

See what people are saying

SourceMessageScoreDate

I gave my Claude Code subagents names (Turing, Magellan, Holmes) and a pane that lists them - named subagents mod (r/ClaudeAI)

When I fan out four subagents the task tree shows four general-purpose rows. I wanted to tell them apart, so I wrote a mod: every subagent gets a themed name from a 395-name pool (explorers for Explore, coders for code, detectives for debugging, …), never two live agents with the same one, and the…

0

Oct 7, 2026

README

named-subagents-mod

CI

Fan out several subagents in Claude Code and the task tree shows each one by its type. This mod gives every subagent its own themed name instead (Turing, Magellan, Holmes), drawn from a 395-name registry and never shared by two live agents. It also lists the running agents under those names in a pane beside the conversation: what each one is doing, its tokens and its clock, with its whole conversation a press away (see The agents pane).

A Claude Code 2.1.292 session in the fullscreen layout, 150 columns: four subagents fan out and the agents pane opens beside the transcript, listing them as Basquiat, Eames, PaulRand and Mucha with what each is reading, its tool count, tokens and clock; the task tree under the prompt shows the same four names; after /names set pirates and /names use pirates the next three are Bonny, Kidd and Teach, and the pane ends on a receipt for all seven

The GIF is a real session, not a mock-up: scripts/capture_demo.sh drives Claude Code in tmux and saves the screen twice a second, and scripts/render_tree_gif.py draws the whole screen for some of those frames, holding the ones with something to read. Two things are taken out: the banner is blanked and the home directory in a path reads ~. It was recorded on 0.3.0 in a 150-column terminal in the fullscreen layout (/tui fullscreen), where the pane docks beside the transcript and opens by itself. In a terminal under 144 columns you get a line under the prompt counting the running agents and a toast as each finishes, and /roster opens the pane.

It is a Claude Code mod (function hooks), so it needs Claude Code 2.1.287 or later and nothing else: no Python, no Node at runtime. It replaces the retired named-subagents Python plugin (last release 0.7.2).

The name is for you to read: the agent is not told its name (the engine does not put a mod-set name into the subagent's context), so there is no SubagentStart queue, ledger or file lock, and no burst-start pairing to get wrong.

Install

Type this at the prompt of a terminal session:

/plugin install named-subagents-mod --marketplace Bobby-cell-commits/named-subagents-mod

Answer y to add the marketplace, pick a scope (user = every session), and set the options or keep their defaults. The options screen is where you can type your own names straight away (see Your own names). The mod is active from then on; no reload is needed.

From a shell instead:

claude plugin marketplace add Bobby-cell-commits/named-subagents-mod
claude plugin install named-subagents-mod@named-subagents-mod --scope user

Your own names

Three ways in, all feeding the same pool. Use whichever is nearest to hand.

1. The options screen (at install, or later with /plugin configure named-subagents-mod or /config). Type names into Your names, separated by commas: Ripley, Deckard, Mary Shelley. They join every built-in pool and get about half of the draws while one of them is free, so even two names show up often. Turn on Use only my names to leave the built-in names out.

2. The /names command, in any session. It keeps your names in one file and applies to the next agent dispatched:

/names                             what is set, and where the files are
/names add Ripley "Mary Shelley"   more names, for every built-in pool
/names remove Sisyphus             never draw this name
/names rename Turing Alan          call one name something else
/names set pirates Kidd Bonny      define a set (a pool of your own); same name again replaces it
/names unset pirates               drop a set
/names use pirates | auto          draw every agent from one pool, or go back to picking by task
/names only on | off               leave out the built-in names
/names import <file>               merge a names file, a JSON list, or one name per line
/names reset                       clear your file (a .bak copy is kept)

import joins what it reads with what you have: lists are added to, and a set of the same name gets the new names as well.

3. A names file, for whole sets, dotfiles and sharing: ~/.claude/named-subagents.json (under CLAUDE_CONFIG_DIR when that is set). A project can carry its own at .claude/named-subagents.json, layered on top of yours. Every key is optional:

{
  "only": false,
  "use": "pirates",
  "names": ["Ripley", "Deckard"],
  "remove": ["Sisyphus"],
  "rename": { "Turing": "Alan" },
  "sets": {
    "pirates": { "names": ["Blackbeard", "Bonny", "Kidd"], "for": ["Explore"], "keywords": ["search", "find"] },
    "code": { "names": ["Neo", "Trinity"], "replace": true }
  }
}
KeyMeaning
namesExtra names. They join every built-in pool, not the sets you define, and get about half of the draws while one of them is free (so do names a set adds to a built-in pool).
renameOld name to new name.
removeNames never drawn. Applied after rename, so a renamed name is hidden by its new name.
setsA set is a pool of your own. for lists the agent types that draw from it and wins unless one pool is pinned (use, or the Name pool option); keywords match the task description. A set named like a built-in pool (code, explore, …) adds to that pool, or with "replace": true takes its place. "pirates": ["Kidd", "Bonny"] is short for a set with just names.
useOne pool for every agent, whatever its type. Wins over the Name pool option; auto or absent leaves the choice to that option, which picks by type and task unless you pinned a pool there.
onlytrue leaves out everything before this file, the built-in names included.

Order: built-in names, your file, the project's file, then the options screen's names. examples/pirates.json is a set to try, from a checkout of this repository: /names import examples/pirates.json.

The name rule. Claude Code accepts an agent name made of letters, digits, _ and -, starting with a letter or digit, up to 64 characters, and refuses the whole dispatch for anything else. So names are cleaned on the way in: Mary Shelley becomes MaryShelley, Zoë becomes Zoe, O'Brien becomes OBrien. A name with nothing usable in it (名前, an emoji) is skipped and reported.

Limits. A names file is read as untrusted input, since a project's arrives with the repository. A file over 256 KB is not read. A list holds up to 2,000 names, a file up to 100 sets, and a set up to 200 for or keywords entries; what is over is left out and reported. Anything quoted from a file in a warning or in /names output has its control characters replaced, so a file cannot send escape sequences to your terminal. A name holding a control character is skipped.

When a file is wrong. A file that is not valid JSON, a name that cannot be used, or an unknown key raises a toast and a status line once per change of the file; everything else in the file still applies, and agents are always named. /names lists the problems, and will not edit a file it cannot read in full, because rewriting it would drop the unread part; /names reset starts clean and keeps a .bak.

The agents pane

A roster of the session's subagents, one row an agent, in columns: its mark (spinning while it runs), its name, its task, the tool call it is running now or how it ended, its tool count, tokens and clock. From a live session (three agents, Claude Code 2.1.292):

✻ Agents · Haiku 4.5                                                             3 running

· DaVinci  Read retry.txt and write design es…  Read(retry.txt)    1 tool    25.1k     5s
✳ Hokusai  Read cache.txt and write design es…  Read(cache.txt)    1 tool    25.2k     4s
✽ Mucha    Read parser.txt and write design e…  Read(parser.txt)   1 tool    25.2k     3s

── timeline ──────────────────────────────────────────────────────────────────────────────
✻ DaVinci  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━    5s
✻ Hokusai  ············━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━    4s
✻ Mucha    ························━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━    3s

The names are the ones in Claude Code's own task tree: both read the engine's agent list. An agent the model named itself is listed under that name; one with no name (naming turned off) reads Type(description).

  • Where it shows. In the fullscreen layout (/tui fullscreen) it docks beside the transcript. On the main screen it is a summary of up to eight rows above the prompt, in the same columns. It opens by itself when an agent starts, in a terminal at least 144 columns wide; narrower than that, /roster opens it, and until then a line under the prompt counts the running agents (✻ 2 of 4 agents running).
  • A conversation. Press an agent's name or task: the pane widens and shows its brief, its replies and its tool calls with their results. b goes back, k and j step through it, Esc gives the keyboard back.
  • Folding. Ten seconds after the last agent finishes the pane folds to a tab above the prompt (◂ Agents ✓ 3); press the tab to bring it back, and a new agent brings it back by itself. The ▸ handle on the pane's left edge folds it by hand. /roster opens or closes it.
  • Also there. A model shared by every agent is said once, in the header. An agent's own subagents sit indented under it. A timeline puts the latest batch on one time axis. A finished batch gets a receipt (✓ 3 done in 8s · 21s of agent time (2.6× in parallel) · 3 tool uses · 158k tokens) and each finish a toast. ■ Stop, then Confirm stop, ends a running agent through Claude Code's own TaskStop. A background agent between turns counts as done; a teammate between turns reads waiting.
  • What it reaches. It watches: the agent list, each agent's tool calls (name and a short argument), its token usage, and its transcript while you have it open. Stop is its one action. It makes no network request, runs no process and keeps nothing after the session.

The pane is agentpane 1.1.4 by Anji Xu (MIT), brought into this mod with a name column, the roster layout and a few wording changes. See Credits.

What it reaches, and what it trusts

Everything the mod does goes through Claude Code's plugin API; it runs no process and makes no network request. What it reads and writes:

  • Reads: the session's agent list; every Agent dispatch (to set its name); each agent's tool calls (the tool's name and a short argument), its token usage and the model it runs on; an agent's transcript, only while you have its conversation open in the pane; HOME, USERPROFILE and CLAUDE_CONFIG_DIR; your names file and the project's; and a file you name to /names import.
  • Writes: your names file (~/.claude/named-subagents.json) and its .bak, on /names edits only. Nothing else, and nothing is kept after the session beyond that file.
  • One action: TaskStop on the agent whose conversation you have open, after you press Stop and then Confirm stop. The consent it gives the engine names the agent's type and id, never text a model wrote.

What it draws is not all yours. Agent names and descriptions are written by the model; tool arguments and results and the agents' replies come from whatever the agent read, a web page or a repository included; and a project's names file arrives with the repository. So all of it is treated as untrusted text: control characters, escape sequences and the characters that reorder text are removed before anything is drawn or quoted, every line is cut to length, a names file is bounded in size and in how many names, sets and routes it may hold, and a name must pass the Agent tool's own rule. An agent's replies are drawn as Markdown, as Claude Code draws its own transcript, so text an agent read can shape what its conversation shows you (a heading, a link, a line that looks like a button); it cannot press anything, run anything or reach the network, and a link in a reply is not pressable. The pane's buttons are its own elements, not text.

To check this without trusting the README, clone the repository and run claude plugin validate .: its calls: line lists every engine method the mod can call. For 0.3.0 that is $.agent.list, $.clock, $.command.register, $.env.get, $.fs.{exists,read,stat,write}, $.session.{messages,root,surfaces}, $.state, $.tool.call and $.ui.*; no $.http, $.process, $.model or $.mcp. A review of 0.3.0 for exploitable paths found none; its notes are in the changelog.

What it does

  • tool.call{Agent}: if the call has no name, draws one and calls next({ ...e, name }). The description is left as is. A model-supplied name passes through untouched.
    • Pool: the theme option pins one; auto matches subagent_type first (generic roles like general-purpose go by description keywords first), then the default pool. The pool is the built-in one with your names layered on; both names files are checked on every dispatch.
    • Uniqueness: skips every name in $.agent.list() and every in-flight draw. An exhausted pool spills to the default pool, then to any free name, then to Name-2, Name-3, …
  • agent.spawn: after the spawn, checks the name reached it and that $.agent.list() shows it on the new agent id. Anything else raises a toast and a status line (named-subagents: drew X but …). Neither hook can block a dispatch: both carry a .catch that continues the call.
  • The pane: agent.spawn lists an agent the moment it starts, a once-a-second read of $.agent.list() keeps the list current, tool.call records what each agent is doing, turn.step its tokens and model, and two ui.render hooks draw the pane and the summary above the prompt. Every one of them passes its event on unchanged.
  • One status line for both. Naming's alarm stands on it until the next clean spawn (a names file that is wrong, until it is fixed); with agents running and the pane off screen the count leads and the alarm follows: ✻ 2 agents running · named-subagents: your names file: not valid JSON ….
  • A failure in the pane's part of a shared hook does not skip naming's part, and naming's "naming failed" alarm is raised only when the name did not reach the call.

Options (userConfig)

Set at install, later with /plugin configure named-subagents-mod or /config (type the option's title to find it; a change applies at once), or in ~/.claude/settings.json under pluginConfigs, keyed by the plugin's id: named-subagents-mod@named-subagents-mod installed from the marketplace, named-subagents-mod@inline loaded with --plugin-dir. A project's .claude/settings.local.json did not carry them (Claude Code 2.1.292); --settings <file> does.

FieldDefaultMeaning
themeautoauto, or a category key (code, explore, debug, …) to always use that pool
enabledtruefalse turns naming off without uninstalling (and /names with it)
namesemptyYour names, separated by commas; they join every built-in pool
only_customfalsetrue leaves the built-in names out
panetruefalse turns the pane off: names only (see below)
autoOpentrueopen the pane when an agent starts; off, /roster opens it
foldAfter10seconds after the last agent finishes before the pane folds; 0 keeps it open
motiontrueanimate the spinner; off, it stands still and the clocks still run
toaststruea toast when agents finish
keepFinished8finished agents the list keeps (1–30)
statusLinetruecount the running agents under the prompt while the pane is not on screen

The first four are naming's. pane (Show the agents pane on the options screen) is the pane's one switch, and the six after it (Pane: …) adjust the pane while it is on. To have names without the pane, turn pane off: nothing opens, nothing is counted under the prompt, no finish toast and no tab appear, the agent list is not read every second and /roster is not offered. Naming, /names and the check of each spawned agent's name work as before. Turned off mid-session, an open pane closes and its list is forgotten; /roster stays in the command list until the session ends (a session cannot take a command back) and answers that the pane is switched off. enabled turns off naming only: the pane then lists agents by type.

Layout

  • hooks/index.ts: the hooks module hooks.json names; it registers the two halves.
  • hooks/names.ts: naming's hooks. hooks/draw.ts: pure draw logic. hooks/custom.ts: pure custom-names logic (the name rule, the names file, layering, /names edits). hooks/pool.ts: generated.
  • hooks/pane.tsx: the pane's hooks and drawing, and the two hooks both halves share (session.start, agent.spawn: a plugin hooks an event once). hooks/live.tsx, hooks/lanes.tsx: the spinner, clocks and timeline, drawn on the terminal's own frame clock. hooks/time.ts: pure time helpers. hooks/status.ts: the one status line the halves share. types/index.d.ts: the pane's $.state contract.
  • registry.json: the name pool (14 categories, 395 names), the source of hooks/pool.ts.
  • scripts/gen_pool.mjs: regenerates hooks/pool.ts from registry.json; --check exits 1 when it is stale.
  • scripts/capture_demo.sh, scripts/render_tree_gif.py: record and draw assets/demo.gif (tmux and Python with Pillow; not needed to use the mod). assets/demo-frames/ is the recording the GIF was drawn from, so python3 scripts/render_tree_gif.py assets/demo-frames assets/demo.gif redraws it.
  • spec/: draw and custom-names logic tests (plain node). tests/: hook tests (the engine's test kit): names.test.ts, pane.test.tsx and pane-logic.test.ts (the pane's own), and together.test.tsx (naming and the pane in one plugin).
  • examples/: a names file to import. probes/: the live proofs and the TUI capture driver.

Checks

node scripts/gen_pool.mjs --check   # pool matches the registry
node --test spec/*.spec.ts          # draw and custom-names logic, plain node 22.18+ (62 tests)
claude plugin test .                # hooks against the engine's test kit (150 tests)
claude plugin validate .

CI runs the two node checks; the two claude checks need a local Claude Code.

Develop

claude --plugin-dir . loads the checkout for one session. To run every session from a checkout, add the folder as a marketplace (edits apply after /reload-plugins):

claude plugin marketplace add /path/to/named-subagents-mod
claude plugin install named-subagents-mod@named-subagents-mod --scope user

Headless proof and TUI evidence: probes/mods-names-proof/ (naming), probes/custom-names-probe/ (custom names) and probes/pane-fold/ (one plugin for both: what the engine allows, and the live captures).

Known limits

  • The name shows in the task tree and in $.agent.list(); the transcript's launch list and finish notices quote the description only.
  • The name is display-only: a subagent cannot say its own name, and nothing records which name ran which task after the session ends.
  • A set smaller than the number of live agents runs out: the next draw comes from the default pool, then from any free name, then gets a number (Ripley-2).
  • /names edits your file only, and only while the whole file reads cleanly: one unknown key or bad entry and it asks you to fix the file by hand first. A project's names file is edited by hand. A project file can rename or hide names for anyone who opens that project (names only, within the name rule).
  • Overlapping draws (two dispatches in flight at once) are covered by the kit test only. In live runs the engine started same-message dispatches 0.5–2 s apart.
  • With the retired 0.7.2 Python plugin also enabled, the mod's name wins, but the Python hooks still run (see probes/mods-names-proof/README.md). Uninstall the Python plugin.
  • The pane opens by itself only in a terminal at least 144 columns wide (Claude Code's rule for a pane nobody asked for). Below that you get the line under the prompt and the toasts, and /roster.
  • A row has no token count in a pane under 88 columns and no tool count under 72; both are in the agent's conversation header.
  • The pane's start times are when it first saw an agent, and its tokens count from when the mod loaded.
  • Naming's alarm and the pane's finish notice share the plugin's one toast: the newer replaces the older. The alarm also stays on the status line.
  • A reload of the mod (an option changed in /config, /reload-plugins) forgets a standing alarm. A names file that is still wrong is alarmed again at the next dispatch; a "drew X but…" alarm is not.
  • If /roster cannot be registered the mod says so in a toast, and the pane still opens by itself and counts agents.
  • With the separate agentpane plugin also installed there are two panes with the same id. Uninstall it: claude plugin uninstall agentpane@claude-agentpane.
  • Not tried live: the pane in the desktop app, VS Code and mobile with named agents (the test kit draws them); a teammate's waiting row.
  • On the options screen a number option (fold after, finished agents listed) reads blank until you set it; the default (10, 8) applies all the same.
  • The mods API is new (Claude Code 2.1.287, 2026-10-01) and a release may change what this mod relies on; tested on 2.1.291 and 2.1.292 only. Both install paths above were tried on 2.1.292 from a clean CLAUDE_CONFIG_DIR.

Credits

The agents pane is agentpane by Anji Xu, version 1.1.4, used under the MIT licence. Its notice is kept in LICENSE-agentpane and covers hooks/pane.tsx, hooks/live.tsx, hooks/lanes.tsx, hooks/time.ts, types/index.d.ts, tests/pane.test.tsx and tests/pane-logic.test.ts, which carry this mod's changes on top.

The pane here is a copy, so agentpane's later fixes arrive only by hand. It was taken at upstream commit 17be889 (1.1.4). To bring a newer one in:

git clone https://github.com/xuanji86/claude-agentpane && cd claude-agentpane
git diff 17be889 <new commit> -- hooks/ types/

Apply that diff by hand to the files listed above (hooks/hooks.json there is not used here; a new or changed option is in .claude-plugin/plugin.json, so diff that file too). Three have other names there: hooks/register.tsx is hooks/pane.tsx here, hooks/pane.test.tsx is tests/pane.test.tsx and hooks/agentpane.test.ts is tests/pane-logic.test.ts. Then run the checks under Checks, and write the new commit here and at the top of hooks/pane.tsx. The command is /roster here and /agentpane there.

License

MIT. See LICENSE; the pane's files are under LICENSE-agentpane, also MIT.

agents
claude-code
claude-code-mod
claude-code-plugin
subagents
tui
typescript