named-subagents 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bobby-cell-commits
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,301 @@
1
+ Metadata-Version: 2.4
2
+ Name: named-subagents
3
+ Version: 0.3.0
4
+ Summary: Themed, non-repeating nicknames for Claude Code subagents β€” a userspace port of Codex's nickname_candidates
5
+ Author: Bobby-cell-commits
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Bobby-cell-commits/named-subagents
8
+ Project-URL: Repository, https://github.com/Bobby-cell-commits/named-subagents
9
+ Project-URL: Issues, https://github.com/Bobby-cell-commits/named-subagents/issues
10
+ Project-URL: Changelog, https://github.com/Bobby-cell-commits/named-subagents/blob/master/CHANGELOG.md
11
+ Keywords: claude-code,subagents,agents,nicknames,fan-out,orchestration,multi-agent
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
+ Requires-Python: >=3.8
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Dynamic: license-file
29
+
30
+ # named-subagents
31
+
32
+ **Themed, non-repeating nicknames for Claude Code subagents** β€” a userspace port
33
+ of [Codex's per-instance `nickname_candidates`](https://developers.openai.com/codex/subagents),
34
+ grown into a full identity layer.
35
+
36
+ [![CI](https://github.com/Bobby-cell-commits/named-subagents/actions/workflows/ci.yml/badge.svg)](https://github.com/Bobby-cell-commits/named-subagents/actions/workflows/ci.yml)
37
+ ![python](https://img.shields.io/badge/python-3.8%2B-blue) ![node](https://img.shields.io/badge/node-%E2%89%A516-brightgreen) ![deps](https://img.shields.io/badge/runtime%20deps-0-success)
38
+
39
+ When you fan out several Claude Code subagents, parallel instances of one role
40
+ are three identical `Explore` labels. Codex instead gives every spawned instance
41
+ a distinct human-legible **nickname**. Claude Code has no such field β€” requested
42
+ in [anthropics/claude-code#9206](https://github.com/anthropics/claude-code/issues/9206),
43
+ closed *"not planned"* β€” so this library emulates it, and goes further:
44
+ nicknames are **themed to the kind of task**, **never repeat across runs**, and
45
+ each one knows **who it's named after**.
46
+
47
+ ```
48
+ 🧭 Hudson [Explore] map the auth module ← explorers explore
49
+ πŸ€” Plato [architect] why was event-sourcing chosen ← philosophers ponder
50
+ πŸ” Bosch [debugger] root-cause the flaky test ← detectives debug
51
+ ```
52
+
53
+ ## The idea in one line
54
+
55
+ A subagent has two names: its **role** (what it *is* β€” `Explore`, `worker`, …,
56
+ native via `subagent_type` / `.claude/agents/*.md`) and its **nickname** (which
57
+ *instance* β€” `Hudson`, `Nansen`, …). This library adds the second.
58
+
59
+ | Codex | Claude Code native | This library |
60
+ |---|---|---|
61
+ | agent `name` (identity + routing) | `subagent_type` | β€” (unchanged) |
62
+ | `nickname_candidates` (per-instance display) | *(none)* | βœ… themed pools |
63
+ | β€” | β€” | βœ… non-repeat across runs (ledger) |
64
+ | β€” | β€” | βœ… task β†’ theme auto-matching |
65
+ | β€” | β€” | βœ… pins, bios, custom themes, stats, doctor |
66
+
67
+ ## Install
68
+
69
+ ```bash
70
+ pip install named-subagents # Python 3.8+, zero dependencies
71
+ npm i named-subagents # Node β‰₯ 16, ESM, zero dependencies, types shipped
72
+ ```
73
+
74
+ Both ship the same 395-name registry and a `named-subagents` CLI. Or vendor it:
75
+ drop the `named_subagents/` folder (Python) or `js/named_subagents.mjs` +
76
+ `registry.json` (JS) into your repo β€” stdlib/`node:` builtins only.
77
+
78
+ ## Themes
79
+
80
+ 395 names across 14 categories, each globally unique, each with a one-line bio:
81
+
82
+ | Category | Task shape | Name theme | e.g. |
83
+ |---|---|---|---|
84
+ | `explore` | map / search a codebase | Explorers & navigators | Magellan, Shackleton |
85
+ | `code` | implement features | Programmers & computing pioneers | Turing, Hopper, Ada |
86
+ | `research` | external info gathering | Scientists & researchers | Curie, Feynman |
87
+ | `reflect` | design rationale, inner workings | Philosophers | Socrates, Kant |
88
+ | `debug` | root-cause hunting | Detectives | Holmes, Poirot |
89
+ | `test` | edge cases, fuzz, adversarial | Tricksters | Loki, Anansi |
90
+ | `review` | critique, verdict | Judges & jurists | Solomon, Ginsburg |
91
+ | `security` | audit, threat model | Guardians & sentinels | Argus, Heimdall |
92
+ | `design` | UI / UX / visual | Artists & designers | DaVinci, Rams |
93
+ | `data` | analysis, stats, ML | Mathematicians & statisticians | Gauss, Noether |
94
+ | `orchestrate` | plan, coordinate | Strategists & generals | SunTzu, Napoleon |
95
+ | `docs` | technical writing | Writers & authors | Orwell, Borges |
96
+ | `build` | infra / refactor / perf | Engineers & inventors | Tesla, Brunel |
97
+ | `default` | catch-all | Celestial (stars) | Orion, Vega |
98
+
99
+ Pools are deliberately diverse (Ibn Battuta, Zheng He, Ada Lovelace, Ramanujan,
100
+ Confucius, Hypatia, Murasaki, …) β€” good practice, and larger pools mean rarer
101
+ generation cycling.
102
+
103
+ ## Usage
104
+
105
+ ```python
106
+ from named_subagents import Registry, Ledger, plan_fanout
107
+
108
+ reg = Registry.load()
109
+ ledger = Ledger(".named-subagents-ledger.json") # non-repeat across runs
110
+
111
+ plan = plan_fanout(
112
+ ["map the auth module", "map the billing module", "map the search module"],
113
+ reg, ledger=ledger, role="Explore",
114
+ )
115
+ for a in plan:
116
+ # a.agent_kwargs() -> {subagent_type, description, prompt}, Agent-tool-ready
117
+ print(a.emoji, a.nickname, a.subagent_type, "β€”", a.bio)
118
+ ```
119
+
120
+ ```js
121
+ import { Registry, Ledger, planFanout } from "named-subagents";
122
+
123
+ const reg = Registry.load();
124
+ const ledger = new Ledger(".named-subagents-ledger.json");
125
+ const plan = planFanout(["map auth", "map billing", "map search"],
126
+ reg, { ledger, role: "Explore" });
127
+ ```
128
+
129
+ **Cross-language parity is CI-enforced**: same md5-seeded ordering, same
130
+ registry, same ledger format β€” identical inputs give byte-identical outputs,
131
+ and either language can continue a ledger the other wrote.
132
+
133
+ The generated `prompt` prepends a persona preamble telling the agent to begin
134
+ its report with `[Hudson]`, so parallel results come back **attributed by
135
+ nickname**. Add `with_bio=True` / `withBio: true` (CLI: `--bio-in-prompt`) and
136
+ each agent also learns who it's named after.
137
+
138
+ **Attribution never depended on the agent complying.** The nickname is already
139
+ in the dispatch metadata β€” it *is* the display label your runner shows β€” so it
140
+ is deterministic regardless of what the agent writes. The `[Hudson]` self-tag is
141
+ only for the case where you have the raw report *text* and nothing else; for
142
+ that path, `attribute(nickname, report)` / `attribute()` verifies the prefix and
143
+ repairs it (missing β†’ prepended, wrong nickname β†’ replaced; idempotent).
144
+
145
+ ### CLI
146
+
147
+ ```bash
148
+ named-subagents categories # the 14 themes
149
+ named-subagents resolve --task "audit auth for injection" # -> security
150
+ named-subagents resolve --task "audit auth" --explain # ...+ why (keywords, scores)
151
+ named-subagents allocate --category reflect --count 3
152
+ named-subagents assign --role Explore --task "map the router" \
153
+ --count 4 --ledger .ledger.json # Agent payloads
154
+ named-subagents bio Heimdall # who is this figure?
155
+ named-subagents stats --ledger .ledger.json # pool burn-down, generations
156
+ named-subagents doctor # self-checks (see below)
157
+ ```
158
+
159
+ > **Recording a demo?** `scripts/record-demo.sh` runs a short, narrated
160
+ > walkthrough suitable for `asciinema rec` (or pipe the cast to a GIF) β€” see its
161
+ > header for the exact commands.
162
+
163
+ ### Stable identities: pins
164
+
165
+ Always call the security agent **Argus**:
166
+
167
+ ```bash
168
+ named-subagents assign --task "audit the release" --category security --pin security=Argus
169
+ ```
170
+
171
+ Pinned names bypass the ledger (a stable identity *recurs* by design) and are
172
+ reserved out of normal draws, so nobody else can be issued `Argus`.
173
+
174
+ ### Recycle or burn names
175
+
176
+ ```bash
177
+ named-subagents release --category explore --name Hudson --ledger .ledger.json # recycle
178
+ named-subagents retire --category explore --name Columbus --ledger .ledger.json # never again
179
+ ```
180
+
181
+ `release` returns a short-lived agent's name to the pool; `retire` removes a
182
+ name permanently (every generation). If retire/pins empty a pool entirely you
183
+ get a clear `PoolExhaustedError` up front.
184
+
185
+ ### Custom themes & config
186
+
187
+ `--config PATH`, `$NAMED_SUBAGENTS_CONFIG`, or
188
+ `~/.config/named-subagents/config.json` (and, **opt-in**, a project-local
189
+ `./.named-subagents.json` β€” see the security note below):
190
+
191
+ ```json
192
+ { "pins": { "security": "Argus" },
193
+ "categories": { "starships": { "theme": "Star systems", "emoji": "πŸš€",
194
+ "keywords": ["fleet"], "names": ["Enterprise", "Rocinante"] } },
195
+ "extend": { "explore": { "names": ["Kupe"] } } }
196
+ ```
197
+
198
+ New categories are added, same-key categories replace the bundled one, `extend`
199
+ appends to an existing pool. Everything is re-validated on load β€” global
200
+ uniqueness and a strict name pattern (see [SECURITY.md](SECURITY.md); custom
201
+ names are untrusted input that ends up inside agent prompts).
202
+
203
+ Since 0.3 the project-local **`./.named-subagents.json` is opt-in** β€” it is the
204
+ one untrusted-input surface (a repo you cloned controls it), so it is *not*
205
+ auto-loaded unless you pass `--cwd-config` or set `NAMED_SUBAGENTS_CWD_CONFIG=1`.
206
+ `--no-cwd-config` (or `NAMED_SUBAGENTS_NO_CWD_CONFIG=1`) forces it off and wins
207
+ over any opt-in. Explicit `--config PATH`, `$NAMED_SUBAGENTS_CONFIG`, and the
208
+ home config are always honored (deliberate or user-owned).
209
+
210
+ ### Collision-avoidance against real agents
211
+
212
+ `--avoid-installed` (or `plan_fanout(..., avoid_installed=True)`) scans
213
+ `.claude/agents/` + `~/.claude/agents/` frontmatter and guarantees nicknames
214
+ are disjoint from your installed agent names β€” case-insensitive, at the base-name
215
+ level, enforced at draw time.
216
+
217
+ ### Orchestrator adapters
218
+
219
+ ```bash
220
+ named-subagents assign --task "…" --count 4 --format workflow # Workflow snippet
221
+ named-subagents assign --task "…" --count 4 --format swarm # swarm YAML fragment
222
+ named-subagents assign --task "…" --count 4 --format labels # generic JSON
223
+ ```
224
+
225
+ ### Doctor (self-awareness)
226
+
227
+ `named-subagents doctor` checks: registry integrity (uniqueness, sanitization,
228
+ bios coverage), ledger health, pin validity, installed-agent collisions,
229
+ version consistency across `__init__.py`/`pyproject.toml`/`package.json`, and β€”
230
+ when both runtimes are present β€” a live Python↔JS parity probe. Non-zero exit
231
+ on failure; `--json` for machines.
232
+
233
+ ### `/named-fanout` skill
234
+
235
+ A ready-made Claude Code skill wrapping the CLI lives in
236
+ [`skill/named-fanout/`](skill/named-fanout/SKILL.md):
237
+
238
+ ```bash
239
+ cp -r skill/named-fanout ~/.claude/skills/
240
+ ```
241
+
242
+ ## How non-repeat works
243
+
244
+ `allocate()` draws from the category pool in a deterministic md5-seeded order,
245
+ records used names in the **ledger**, and skips them next time. When a pool is
246
+ exhausted it advances a **generation** and suffixes names (`Magellan`,
247
+ `MagellanΒ·2`, …). A display name is never issued to two concurrently-live
248
+ holders, and is never reused at all *unless you explicitly `release` it*.
249
+ Allocation is deterministic given `(category, ledger-state)` β€” resume- and
250
+ re-run-safe (the same reason Claude Code Workflows ban `Math.random`).
251
+
252
+ ## Routing is best-effort
253
+
254
+ Category resolution is `explicit category > subagent_type match > task-keyword
255
+ match > default`. The keyword layer is a **heuristic, not a classifier** β€” for
256
+ guaranteed themes pass `category=` or `role=` explicitly.
257
+
258
+ ## Where this sits (community landscape)
259
+
260
+ [`COMMUNITY.md`](COMMUNITY.md) surveys 11 community Claude Code agent projects.
261
+ The whole ecosystem names agents by **functional role**; none provide
262
+ per-instance nicknames, task-themed names, or a non-repeating ledger. This is
263
+ an **identity layer that composes _under_** orchestrators like `claude-swarm`,
264
+ `metaswarm`, or `claude-flow` rather than competing with them β€” that's what the
265
+ `--format` adapters are for.
266
+
267
+ ## Tests
268
+
269
+ ```bash
270
+ python3 test_named_subagents.py # 266 checks incl. state-machine campaigns
271
+ node js/test_named_subagents.mjs # 279 checks (mirror suite)
272
+ scripts/parity_check.sh # cross-language gate (both runtimes)
273
+ ```
274
+
275
+ CI runs Python 3.8/3.12/3.13, Node 18/20/22, install smokes for both package
276
+ managers, and the parity gate.
277
+
278
+ ## Files
279
+
280
+ | Path | Role |
281
+ |---|---|
282
+ | `named_subagents/` | Python package (reference impl) + **canonical `registry.json`** |
283
+ | `js/` | JS/ESM npm package (twin port; `js/registry.json` is generated at pack time) |
284
+ | `skill/named-fanout/` | Claude Code skill wrapping the CLI |
285
+ | `FINDINGS.md` / `COMMUNITY.md` | research record + ecosystem survey |
286
+ | `SECURITY.md` / `CONTRIBUTING.md` | threat model / parity discipline |
287
+ | `ROADMAP.md` | candidate improvements for future releases |
288
+
289
+ ## Roadmap
290
+
291
+ 0.3.0 shipped most of the backlog β€” release automation with supply-chain
292
+ provenance, cwd-config opt-in, type-surface verification + `py.typed`,
293
+ attribution + ledger session/lock helpers, and `resolve --explain` backed by a
294
+ measured accuracy eval (see [`CHANGELOG.md`](CHANGELOG.md)). What's left β€”
295
+ adoption media, the actual npm/PyPI publish, lint/coverage CI, and the
296
+ probe-gated auto-namer β€” is tracked in [`ROADMAP.md`](ROADMAP.md). Contributions
297
+ welcome (see [`CONTRIBUTING.md`](CONTRIBUTING.md)).
298
+
299
+ ## License
300
+
301
+ [MIT](LICENSE)
@@ -0,0 +1,272 @@
1
+ # named-subagents
2
+
3
+ **Themed, non-repeating nicknames for Claude Code subagents** β€” a userspace port
4
+ of [Codex's per-instance `nickname_candidates`](https://developers.openai.com/codex/subagents),
5
+ grown into a full identity layer.
6
+
7
+ [![CI](https://github.com/Bobby-cell-commits/named-subagents/actions/workflows/ci.yml/badge.svg)](https://github.com/Bobby-cell-commits/named-subagents/actions/workflows/ci.yml)
8
+ ![python](https://img.shields.io/badge/python-3.8%2B-blue) ![node](https://img.shields.io/badge/node-%E2%89%A516-brightgreen) ![deps](https://img.shields.io/badge/runtime%20deps-0-success)
9
+
10
+ When you fan out several Claude Code subagents, parallel instances of one role
11
+ are three identical `Explore` labels. Codex instead gives every spawned instance
12
+ a distinct human-legible **nickname**. Claude Code has no such field β€” requested
13
+ in [anthropics/claude-code#9206](https://github.com/anthropics/claude-code/issues/9206),
14
+ closed *"not planned"* β€” so this library emulates it, and goes further:
15
+ nicknames are **themed to the kind of task**, **never repeat across runs**, and
16
+ each one knows **who it's named after**.
17
+
18
+ ```
19
+ 🧭 Hudson [Explore] map the auth module ← explorers explore
20
+ πŸ€” Plato [architect] why was event-sourcing chosen ← philosophers ponder
21
+ πŸ” Bosch [debugger] root-cause the flaky test ← detectives debug
22
+ ```
23
+
24
+ ## The idea in one line
25
+
26
+ A subagent has two names: its **role** (what it *is* β€” `Explore`, `worker`, …,
27
+ native via `subagent_type` / `.claude/agents/*.md`) and its **nickname** (which
28
+ *instance* β€” `Hudson`, `Nansen`, …). This library adds the second.
29
+
30
+ | Codex | Claude Code native | This library |
31
+ |---|---|---|
32
+ | agent `name` (identity + routing) | `subagent_type` | β€” (unchanged) |
33
+ | `nickname_candidates` (per-instance display) | *(none)* | βœ… themed pools |
34
+ | β€” | β€” | βœ… non-repeat across runs (ledger) |
35
+ | β€” | β€” | βœ… task β†’ theme auto-matching |
36
+ | β€” | β€” | βœ… pins, bios, custom themes, stats, doctor |
37
+
38
+ ## Install
39
+
40
+ ```bash
41
+ pip install named-subagents # Python 3.8+, zero dependencies
42
+ npm i named-subagents # Node β‰₯ 16, ESM, zero dependencies, types shipped
43
+ ```
44
+
45
+ Both ship the same 395-name registry and a `named-subagents` CLI. Or vendor it:
46
+ drop the `named_subagents/` folder (Python) or `js/named_subagents.mjs` +
47
+ `registry.json` (JS) into your repo β€” stdlib/`node:` builtins only.
48
+
49
+ ## Themes
50
+
51
+ 395 names across 14 categories, each globally unique, each with a one-line bio:
52
+
53
+ | Category | Task shape | Name theme | e.g. |
54
+ |---|---|---|---|
55
+ | `explore` | map / search a codebase | Explorers & navigators | Magellan, Shackleton |
56
+ | `code` | implement features | Programmers & computing pioneers | Turing, Hopper, Ada |
57
+ | `research` | external info gathering | Scientists & researchers | Curie, Feynman |
58
+ | `reflect` | design rationale, inner workings | Philosophers | Socrates, Kant |
59
+ | `debug` | root-cause hunting | Detectives | Holmes, Poirot |
60
+ | `test` | edge cases, fuzz, adversarial | Tricksters | Loki, Anansi |
61
+ | `review` | critique, verdict | Judges & jurists | Solomon, Ginsburg |
62
+ | `security` | audit, threat model | Guardians & sentinels | Argus, Heimdall |
63
+ | `design` | UI / UX / visual | Artists & designers | DaVinci, Rams |
64
+ | `data` | analysis, stats, ML | Mathematicians & statisticians | Gauss, Noether |
65
+ | `orchestrate` | plan, coordinate | Strategists & generals | SunTzu, Napoleon |
66
+ | `docs` | technical writing | Writers & authors | Orwell, Borges |
67
+ | `build` | infra / refactor / perf | Engineers & inventors | Tesla, Brunel |
68
+ | `default` | catch-all | Celestial (stars) | Orion, Vega |
69
+
70
+ Pools are deliberately diverse (Ibn Battuta, Zheng He, Ada Lovelace, Ramanujan,
71
+ Confucius, Hypatia, Murasaki, …) β€” good practice, and larger pools mean rarer
72
+ generation cycling.
73
+
74
+ ## Usage
75
+
76
+ ```python
77
+ from named_subagents import Registry, Ledger, plan_fanout
78
+
79
+ reg = Registry.load()
80
+ ledger = Ledger(".named-subagents-ledger.json") # non-repeat across runs
81
+
82
+ plan = plan_fanout(
83
+ ["map the auth module", "map the billing module", "map the search module"],
84
+ reg, ledger=ledger, role="Explore",
85
+ )
86
+ for a in plan:
87
+ # a.agent_kwargs() -> {subagent_type, description, prompt}, Agent-tool-ready
88
+ print(a.emoji, a.nickname, a.subagent_type, "β€”", a.bio)
89
+ ```
90
+
91
+ ```js
92
+ import { Registry, Ledger, planFanout } from "named-subagents";
93
+
94
+ const reg = Registry.load();
95
+ const ledger = new Ledger(".named-subagents-ledger.json");
96
+ const plan = planFanout(["map auth", "map billing", "map search"],
97
+ reg, { ledger, role: "Explore" });
98
+ ```
99
+
100
+ **Cross-language parity is CI-enforced**: same md5-seeded ordering, same
101
+ registry, same ledger format β€” identical inputs give byte-identical outputs,
102
+ and either language can continue a ledger the other wrote.
103
+
104
+ The generated `prompt` prepends a persona preamble telling the agent to begin
105
+ its report with `[Hudson]`, so parallel results come back **attributed by
106
+ nickname**. Add `with_bio=True` / `withBio: true` (CLI: `--bio-in-prompt`) and
107
+ each agent also learns who it's named after.
108
+
109
+ **Attribution never depended on the agent complying.** The nickname is already
110
+ in the dispatch metadata β€” it *is* the display label your runner shows β€” so it
111
+ is deterministic regardless of what the agent writes. The `[Hudson]` self-tag is
112
+ only for the case where you have the raw report *text* and nothing else; for
113
+ that path, `attribute(nickname, report)` / `attribute()` verifies the prefix and
114
+ repairs it (missing β†’ prepended, wrong nickname β†’ replaced; idempotent).
115
+
116
+ ### CLI
117
+
118
+ ```bash
119
+ named-subagents categories # the 14 themes
120
+ named-subagents resolve --task "audit auth for injection" # -> security
121
+ named-subagents resolve --task "audit auth" --explain # ...+ why (keywords, scores)
122
+ named-subagents allocate --category reflect --count 3
123
+ named-subagents assign --role Explore --task "map the router" \
124
+ --count 4 --ledger .ledger.json # Agent payloads
125
+ named-subagents bio Heimdall # who is this figure?
126
+ named-subagents stats --ledger .ledger.json # pool burn-down, generations
127
+ named-subagents doctor # self-checks (see below)
128
+ ```
129
+
130
+ > **Recording a demo?** `scripts/record-demo.sh` runs a short, narrated
131
+ > walkthrough suitable for `asciinema rec` (or pipe the cast to a GIF) β€” see its
132
+ > header for the exact commands.
133
+
134
+ ### Stable identities: pins
135
+
136
+ Always call the security agent **Argus**:
137
+
138
+ ```bash
139
+ named-subagents assign --task "audit the release" --category security --pin security=Argus
140
+ ```
141
+
142
+ Pinned names bypass the ledger (a stable identity *recurs* by design) and are
143
+ reserved out of normal draws, so nobody else can be issued `Argus`.
144
+
145
+ ### Recycle or burn names
146
+
147
+ ```bash
148
+ named-subagents release --category explore --name Hudson --ledger .ledger.json # recycle
149
+ named-subagents retire --category explore --name Columbus --ledger .ledger.json # never again
150
+ ```
151
+
152
+ `release` returns a short-lived agent's name to the pool; `retire` removes a
153
+ name permanently (every generation). If retire/pins empty a pool entirely you
154
+ get a clear `PoolExhaustedError` up front.
155
+
156
+ ### Custom themes & config
157
+
158
+ `--config PATH`, `$NAMED_SUBAGENTS_CONFIG`, or
159
+ `~/.config/named-subagents/config.json` (and, **opt-in**, a project-local
160
+ `./.named-subagents.json` β€” see the security note below):
161
+
162
+ ```json
163
+ { "pins": { "security": "Argus" },
164
+ "categories": { "starships": { "theme": "Star systems", "emoji": "πŸš€",
165
+ "keywords": ["fleet"], "names": ["Enterprise", "Rocinante"] } },
166
+ "extend": { "explore": { "names": ["Kupe"] } } }
167
+ ```
168
+
169
+ New categories are added, same-key categories replace the bundled one, `extend`
170
+ appends to an existing pool. Everything is re-validated on load β€” global
171
+ uniqueness and a strict name pattern (see [SECURITY.md](SECURITY.md); custom
172
+ names are untrusted input that ends up inside agent prompts).
173
+
174
+ Since 0.3 the project-local **`./.named-subagents.json` is opt-in** β€” it is the
175
+ one untrusted-input surface (a repo you cloned controls it), so it is *not*
176
+ auto-loaded unless you pass `--cwd-config` or set `NAMED_SUBAGENTS_CWD_CONFIG=1`.
177
+ `--no-cwd-config` (or `NAMED_SUBAGENTS_NO_CWD_CONFIG=1`) forces it off and wins
178
+ over any opt-in. Explicit `--config PATH`, `$NAMED_SUBAGENTS_CONFIG`, and the
179
+ home config are always honored (deliberate or user-owned).
180
+
181
+ ### Collision-avoidance against real agents
182
+
183
+ `--avoid-installed` (or `plan_fanout(..., avoid_installed=True)`) scans
184
+ `.claude/agents/` + `~/.claude/agents/` frontmatter and guarantees nicknames
185
+ are disjoint from your installed agent names β€” case-insensitive, at the base-name
186
+ level, enforced at draw time.
187
+
188
+ ### Orchestrator adapters
189
+
190
+ ```bash
191
+ named-subagents assign --task "…" --count 4 --format workflow # Workflow snippet
192
+ named-subagents assign --task "…" --count 4 --format swarm # swarm YAML fragment
193
+ named-subagents assign --task "…" --count 4 --format labels # generic JSON
194
+ ```
195
+
196
+ ### Doctor (self-awareness)
197
+
198
+ `named-subagents doctor` checks: registry integrity (uniqueness, sanitization,
199
+ bios coverage), ledger health, pin validity, installed-agent collisions,
200
+ version consistency across `__init__.py`/`pyproject.toml`/`package.json`, and β€”
201
+ when both runtimes are present β€” a live Python↔JS parity probe. Non-zero exit
202
+ on failure; `--json` for machines.
203
+
204
+ ### `/named-fanout` skill
205
+
206
+ A ready-made Claude Code skill wrapping the CLI lives in
207
+ [`skill/named-fanout/`](skill/named-fanout/SKILL.md):
208
+
209
+ ```bash
210
+ cp -r skill/named-fanout ~/.claude/skills/
211
+ ```
212
+
213
+ ## How non-repeat works
214
+
215
+ `allocate()` draws from the category pool in a deterministic md5-seeded order,
216
+ records used names in the **ledger**, and skips them next time. When a pool is
217
+ exhausted it advances a **generation** and suffixes names (`Magellan`,
218
+ `MagellanΒ·2`, …). A display name is never issued to two concurrently-live
219
+ holders, and is never reused at all *unless you explicitly `release` it*.
220
+ Allocation is deterministic given `(category, ledger-state)` β€” resume- and
221
+ re-run-safe (the same reason Claude Code Workflows ban `Math.random`).
222
+
223
+ ## Routing is best-effort
224
+
225
+ Category resolution is `explicit category > subagent_type match > task-keyword
226
+ match > default`. The keyword layer is a **heuristic, not a classifier** β€” for
227
+ guaranteed themes pass `category=` or `role=` explicitly.
228
+
229
+ ## Where this sits (community landscape)
230
+
231
+ [`COMMUNITY.md`](COMMUNITY.md) surveys 11 community Claude Code agent projects.
232
+ The whole ecosystem names agents by **functional role**; none provide
233
+ per-instance nicknames, task-themed names, or a non-repeating ledger. This is
234
+ an **identity layer that composes _under_** orchestrators like `claude-swarm`,
235
+ `metaswarm`, or `claude-flow` rather than competing with them β€” that's what the
236
+ `--format` adapters are for.
237
+
238
+ ## Tests
239
+
240
+ ```bash
241
+ python3 test_named_subagents.py # 266 checks incl. state-machine campaigns
242
+ node js/test_named_subagents.mjs # 279 checks (mirror suite)
243
+ scripts/parity_check.sh # cross-language gate (both runtimes)
244
+ ```
245
+
246
+ CI runs Python 3.8/3.12/3.13, Node 18/20/22, install smokes for both package
247
+ managers, and the parity gate.
248
+
249
+ ## Files
250
+
251
+ | Path | Role |
252
+ |---|---|
253
+ | `named_subagents/` | Python package (reference impl) + **canonical `registry.json`** |
254
+ | `js/` | JS/ESM npm package (twin port; `js/registry.json` is generated at pack time) |
255
+ | `skill/named-fanout/` | Claude Code skill wrapping the CLI |
256
+ | `FINDINGS.md` / `COMMUNITY.md` | research record + ecosystem survey |
257
+ | `SECURITY.md` / `CONTRIBUTING.md` | threat model / parity discipline |
258
+ | `ROADMAP.md` | candidate improvements for future releases |
259
+
260
+ ## Roadmap
261
+
262
+ 0.3.0 shipped most of the backlog β€” release automation with supply-chain
263
+ provenance, cwd-config opt-in, type-surface verification + `py.typed`,
264
+ attribution + ledger session/lock helpers, and `resolve --explain` backed by a
265
+ measured accuracy eval (see [`CHANGELOG.md`](CHANGELOG.md)). What's left β€”
266
+ adoption media, the actual npm/PyPI publish, lint/coverage CI, and the
267
+ probe-gated auto-namer β€” is tracked in [`ROADMAP.md`](ROADMAP.md). Contributions
268
+ welcome (see [`CONTRIBUTING.md`](CONTRIBUTING.md)).
269
+
270
+ ## License
271
+
272
+ [MIT](LICENSE)