agent-builder — author a new subagent definition (extend-first)
Create — or, preferably, reuse — a .claude/agents/<name>.md custom subagent definition for a skill’s fan-out step. This is skill-builder’s counterpart for the other kind of file this repo ships: a persistent, harness-registered subagent persona, not a user-invocable workflow. The prime directive mirrors skill-builder’s: don’t scaffold a new agent until you’ve confirmed no existing agent should be reused instead, and a persistent agent file only earns its keep when a plain inline Agent() prompt in the calling skill isn’t enough.
When this fires
- “build an agent”, “create a subagent”, “make a new agent”, “add an agent”, “agent-builder”
- While authoring or extending a heavy, fan-out-shaped skill (see
when-to-orchestrate.md) and the per-item worker needs a fixed, narrower tool boundary than the calling skill itself has — e.g. a detection or audit pass that must not be able to mutate anything, even by accident. - Proactively, the same way
spot-skill-opportunitiesproposes a new skill: notice the pattern, propose scaffolding an agent, don’t build one unasked.
Step 0 — Reuse or extend before you create (do this FIRST, always)
List the existing agents and read their roles:
Each one pairs 1:1 with a skill (
dependency-auditor→check-dependency-updates,hallucination-detector→purge-hallucinations,community-demand-scout→opposition-research). Check whether an existing role already covers this concern under a different target — often the fix is parameterizing the calling skill’s prompt to the existing agent, not building a new persona.Ask whether this needs a persistent file at all. An inline
Agent()/agent()prompt (seeskill-builder’s “If the skill fans out to subagents” section) is enough unless: (a) more than one skill would spawn the same persona, or (b) the harness-enforced tool restriction is itself load-bearing — e.g. guaranteeing a detection pass can’t accidentally write, which an inline prompt can’t guarantee (the calling skill’s own tools still apply).Check open PRs too — another session may already have an in-progress draft agent that never landed as a local branch you’d see. See
check-open-prs-before-duplicating.State explicitly: reuse, extend, or new — and why — before writing a line.
Anatomy of an agent definition
.claude/agents/<name>.md
---
name: <name> # kebab-case, role-noun compound: <domain>-<role>
description: <what it audits/detects/scouts>, what it lacks (Edit/Write/Bash)
and why, and which skill spawns it as its fan-out worker
tools: Bash, Read, Grep, Glob, WebFetch # comma-separated STRING, not a
# YAML list (unlike skills'
# `allowed-tools:`)
---Body shape: an opening line “You are the <role> half of the <skill> skill.”, a numbered procedure for what to check/verify/mine, an explicit output-shape spec (what to return, in what order), and a closing reminder of exactly which mutating tools are absent and why avoiding shell-based writes with the tools it does have is instruction-level discipline, not harness-enforced. Match the tone and structure of the three existing agents — they read almost as a template.
Conventions (match the existing family)
- Naming:
<domain>-<role>compound noun (dependency-auditor,hallucination-detector,community-demand-scout) — not a verb phrase, not a generic name likehelperorworker. - Default to read-only. Omit
EditandWritefromtools:unless the agent’s entire purpose is to mutate files (rare — none of the three existing agents do). IfBashis present withoutEdit/Write, say explicitly in thedescriptionthatBashcould still write and that avoiding write-capable shell commands is instruction-level, not harness-enforced —dependency-auditorandhallucination-detectorboth carry this caveat (they haveBash).community-demand-scoutsidesteps the issue entirely by omittingBashfromtools:— prefer that when the agent’s job doesn’t need shell access at all. - Pair 1:1 with the skill that spawns it. Name that skill in the opening clause of
description(“Read-only audit pass for check-dependency-updates (cdu)”). - Write the prompt as if the calling skill’s
SKILL.mddoesn’t exist — a spawned agent never sees it. Restate every needed discipline (the exact query, source priorities, output shape) inside the agent file itself, the same ruleskill-builder’s subagent-fanning section states for inline prompts. - No registry to update. Agents are auto-discovered from
.claude/agents/(mirrors skills’ auto-discovery fromskills/) — adding the file is enough for the harness to expose it as asubagent_type. There is currently novalidate-skills.py-equivalent lint for.claude/agents/, so hand-check:name:matches the filename,tools:is a comma-separated string (not a YAML list), anddescriptionstates the role, its tool limits, and the calling skill.
Worker-role archetypes (beyond the read-only default)
The six existing agents are all one archetype — a scout: read-only, reports back to the calling session, no authority to act on its own findings. That’s still the right default (see Conventions above), but three other roles are legitimate reasons to deviate from it:
- Bounded worker — granted
Edit/Writeto perform one scoped implementation task, not just an investigation. Still rare (see Conventions), but when a task genuinely needs it: name the exact file(s) or path glob it may touch in thedescription, state what it must NOT touch, and have it report back what it changed — the same output-shape discipline a scout uses for findings. - Critic — reviews another agent’s (or the coordinator’s own) output instead of investigating the repo fresh.
adversarial-revieweris this repo’s one named critic, and it cleared the promotion bar below because every self-review routes to it —push,ardi, and the fallback review inself-review-fallback(adversarial-self-review). AWorkflowscript’spipeline()/parallel()verify stage (seewhen-to-orchestrate.md) is the other way this repo gets adversarial review — an inline prompt, not a named persona. Promote a new critic to a.claude/agents/*.mdfile only once more than one skill wants that same critic behavior — Step 0’s reuse-first rule applies here too. - Paranoid reviewer — a critic deliberately run at higher cost/effort (see
select-modelandwhen-to-orchestrate.md’s model/effort routing section) for consequential or subtle work, where a same-family second pass risks repeating the first pass’s own blind spot. For the highest-stakes case, run the critic on a genuinely different model family viadelegate-to-codexinstead of another Claude subagent — that skill’s “verify” step already covers reviewing Claude’s own prior output, not just fresh investigation.
None of this changes the tools: frontmatter schema (there is no model/effort field there, and there shouldn’t be — pin the model/effort choice in the calling skill’s agent()/Agent() invocation instead, so the same persona file stays reusable across tiers).
Can an agent build another agent?
Mechanically, yes: any subagent granted Edit/Write (the default general-purpose agent, or a custom agent you don’t restrict) can write a new .claude/agents/*.md file exactly like any other file — nothing in the harness singles out agent-definition files as unwritable. But this repo doesn’t delegate agent-authoring that way. Building an agent is an authoring task, and every authoring task in this corpus — including skill-builder itself — runs in the main session, not a spawned worker, so a human-in-the-loop stays on the naming, tool-scoping, and reuse-check decisions in Step 0. The fan-out workers this skill creates are deliberately read-only in part so they can’t self-modify or spawn siblings unsupervised. Keep authoring inline; reserve spawned agents for the narrow, read-only, single-purpose jobs the existing three model.
Register the new agent with its calling skill
There’s no central agent list to update (see above) — “registering” a new agent means updating the one skill that spawns it, via one of two mechanisms:
- Inline fan-out call, when the skill only needs the agent for one step and continues afterward in the calling session — add
Agent(subagent_type: "<name>", ...)in that step, or inside aWorkflowscript,agent(prompt, {agentType: "<name>"}). - Declarative
context: fork, when the agent’s own procedure covers the skill’s entire body end to end — addcontext: fork,agent: <name>, and (usually)background: falseto the skill’s own frontmatter, per the Run skills in a subagent docs section. Seeskill-audit/find-overlapfor the pattern.
The two are not interchangeable, and picking the wrong one silently breaks a write step. With context: fork, tool access comes from the agent: type, not the skill’s own allowed-tools — the whole skill body becomes the forked subagent’s task, so there is no way to fork only a sub-step. A skill whose procedure mixes a read-only detect phase with a main-session-only write/PR/interactive-confirmation follow-through (reproducibility-audit, purge-hallucinations, fact-check-prose, check-info-quality all do this — see #914) cannot use mechanism 2 without restructuring into two skills first: forking the whole thing to a read-only custom agent would strip the write access the follow-through needs, not replace it declaratively. Reach for mechanism 2 only when every step in the skill needs no more than the agent’s own tools: list — confirm this by reading the skill’s full procedure, not by assuming a skill that already pairs with a read-only agent is automatically eligible.
Either way:
- Name the
.claude/agents/<name>.mdpath explicitly in the skill body (grepcheck-dependency-updates,purge-hallucinations, oropposition-researchfor the inline pattern;skill-auditorfind-overlapfor the declarative one). - If the skill’s procedure names a GitHub MCP tool the agent will call, register it in
tool-mappings.ymlperskill-builder’s rule — the same possible-hallucination risk applies to agent-spawning skills.
Ship it
Agent files and skills both live in the ai-config repo — never local-only. Branch + PR + ARDI, the same flow as skill-builder.
In a worktree session, the same hazard applies as in
skill-builder’s ship-it: the repo toplevel below is the MAIN checkout, not your worktree.~/.claude/skillssymlinks into the mainai-configcheckout, sogit -C ~/.claude/skills/… rev-parse --show-toplevelreturns the main repo root — often on another session’s branch. Don’tcdthere and don’t pass that path to Write/Edit. Author.claude/agents/<name>.mdand the calling skill’sSKILL.mdin your worktree’s own checkout instead, and confirm withgit branch --show-currentbefore committing. Seeskill-builder’s ship-it section for the full explanation.
cd "$(git -C ~/.claude/skills/agent-builder rev-parse --show-toplevel)" # ai-config root — NOTE: the MAIN checkout, NOT your worktree (see caveat above)
git fetch origin main && git checkout -b add-<name>-agent origin/main # FETCH, CREATE_BRANCH
# write .claude/agents/<name>.md, and update the one calling skill's SKILL.md
# The `validate` CI job runs these four — run all four locally before pushing,
# same as skill-builder — since this also touches the calling skill's SKILL.md:
python3 scripts/validate-skills.py # sanity-checks skills/, not agents/ yet — still run it
python3 scripts/check-links.py # relative links in the updated calling skill
python3 scripts/check-vendored-drift.py
npx --yes markdownlint-cli2@0.22.1 # markdown style on the updated skill's SKILL.md
git add .claude/agents/<name>.md skills/<calling-skill>/SKILL.md # stage only what you touched
git commit -m "agents: add <name> — <summary>" # COMMIT
git push -u origin HEAD && gh pr create --fill # PUSH, CREATE_PRThen, as explicit steps:
- Request the reviewer:
gh pr edit --add-reviewer <reviewer>(EDIT_PR; seerequest-pr-review). - Drive to clean: run
ardion the new PR until the verdict has zero findings.
A second consumer: agent-team teammate roles
An agent definition has a use beyond the fan-out subagent it is built for: it also doubles as an agent-team teammate role. When a user asks a team lead to spawn a teammate “using the <name> agent type”, the definition’s tools allowlist and model apply and its body is appended to the teammate’s system prompt — but its skills and mcpServers frontmatter are not applied (a teammate loads those from project and user settings), and SendMessage plus the task-management tools are always available regardless of tools. So write the persona and tool boundary to stand on their own, and don’t rely on a definition’s skills reaching a teammate. See agent-teams for when a team is the right primitive at all — it is user-gated and experimental, so this is a reuse property of the file, never a thing this skill or its agents spawn.
Relationship to other skills
skill-builder— the skill-authoring sibling; this is its subagent-file counterpart. Useskill-builderwhen the new capability is a user-invocable workflow; use this one when it’s a read-only fan-out worker a skill spawns.spot-skill-opportunities— recognizes when a skill is needed; the same in-the-moment recognition applies to noticing a heavy skill’s fan-out step would benefit from a dedicated persona instead of an inline prompt — hand off here for that case.ums/record-learnings— when a session reveals that a fan-out step needs a tighter, reusable worker persona (not just a skill gap), route here instead of, or alongside,skill-builder.heal-skill— repairs a skill that misfired; if the root cause is actually the spawned agent’s prompt or tool-scoping (wrong persona, too-loose tools), fix the.claude/agents/*.mdfile via this skill’s conventions rather than editing the calling skill.link-skills— the cross-link auditor for skills, though it currently scans onlyskills/and doesn’t check.claude/agents/. Until it’s extended to cover agent files, manually verify that a skill naming a custom agent is named back in that agent’sdescription.config-ai— the broader router this skill is one destination for: when a request names a capability but not a mechanism,config-aidecides whether it’s a subagent (→ here), a skill, a memory, a hook, or aghacapability, then hands off accordingly.
Anti-patterns
- ❌ Creating a new agent when an existing persona, parameterized differently, would do.
- ❌ Not checking open PRs → building a second draft of an agent someone already pushed and opened a PR for, instead of redirecting to it.
- ❌ Giving a read-only fan-out worker
Edit/Write“just in case.” - ❌ Writing the agent’s system prompt assuming it inherits the calling skill’s text — restate every needed discipline explicitly.
- ❌
tools:written as a YAML list — agent frontmatter uses a plain comma-separated string, unlike skills’allowed-tools:. - ❌ Delegating the authoring itself to a spawned agent instead of doing it in the main session — naming, tool-scoping, and the reuse-check need a human-in-the-loop.
- ❌ Leaving the new agent unreferenced by any skill — an orphaned
.claude/agents/*.mdfile with nothing to spawn it. - ❌ Leaving the change local-only, or pushing straight to main.