Agent Creator
Caution
Agents with vague descriptions trigger on the wrong requests — or never trigger at all. A bad description means Claude picks the wrong agent, spams irrelevant ones, or silently falls back to the main conversation. Most hand-written agents also leak CLAUDE.md rules into the body (already injected) or forget the Triggers: keyword list that drives auto-selection.
Tip
Describe what you want — the agent handles the rest. It runs parallel analysis of your codebase, drafts the frontmatter and system prompt, validates against Anthropic best practices, then optimizes with brewtools:text-optimize. Improvement and debugging of existing agents follow the same flow.
Quick reference
| Field | Value |
|---|---|
| Triggers | ”create agent”, “improve agent”, “scaffold agent” |
| Model | inherit — runs on the session’s model |
| Tools | Read, Write, Edit, Glob, Grep, Bash, Agent, WebFetch, WebSearch |
Scope guard
Agent Creator sizes the task before starting. One bounded unit = one deliverable, roughly 5 files, roughly 10 steps.
| Situation | What the agent does |
|---|---|
| Brief fits one bounded unit | Starts immediately |
| Brief exceeds ~5 files / ~10 steps, or bundles several independent deliverables | Stops before starting, returns a split proposal: 2-N bounded subtasks, each with scope and a suggested owner |
| Scope grows mid-flight | Stops at the next clean boundary, reports done / remaining / how to split |
| Brief is missing GOAL, SCOPE, CONTEXT, CONSUMER or acceptance | States the assumption explicitly in the report, or asks once — never invents scope |
“Create six agents for my team” gets a split proposal — one agent per subtask. The same rule that agent-creator applies to itself is the one it writes into every agent it generates.
Tip
Got a split proposal instead of an agent file? That is the guard working. Pick one agent from the proposal and re-send it, or spawn the subtasks as parallel agents in a single message.
Guardrails in every generated agent
Two blocks land in the body of every agent Agent Creator writes. They are part of the output contract, not advice. One of them is also called Return Contract — a separate thing from Agent Creator’s own return contract described later on this page: this one is what a generated agent hands back, that one is what Agent Creator itself hands back.
| Guardrail | Applies to | What it says |
|---|---|---|
| Return Contract | Every generated agent, unconditionally | Verdict first, <=30 lines, path:line. !=bodies/output/log/preamble. Unconditional — spend one step on what the MAIN SESSION needs and return only that. Bulk material — long logs, full diffs, dumps, long reports — goes into a file under .claude/reports/<YYYYMMDD-HHMMSS>_<name>/, and only the PATH comes back. Agents that dump everything burn the main session’s context. If the agent-return guard is installed, a return over ~1000 est-tokens (chars/4) is blocked for compression; over <=2500 it must file the detail and answer with path + verdict + <=3 lines. |
| Scope Fit | Only agents whose domain writes code, scripts, SQL, schemas, infra or config | Build for the actual scale and the problems that exist today, not imagined load or speculative abstraction — a 10-user app does not need hardening against DB lock contention. After finishing, one pass: can this be simpler — fewer files, less config, less indirection? |
Scope Fit is dropped for research, docs, and review-only agents; Return Contract never is. Both are validation-checklist items, so an agent missing the Return Contract block does not pass. Agent Creator applies Return Contract to itself: its report is agent paths plus a frontmatter / validation verdict, never the full agent bodies.
When to use
- New agent — you need a specialized subagent (reviewer, code-generator, security-scanner, etc.)
- Agent not triggering — the agent exists but Claude doesn’t auto-select it reliably
- Trigger collisions — two agents compete for the same request; need
<commentary>disambiguation - System prompt quality — existing agent body is vague prose instead of dense tables + checklists
- Post-update drift — agent worked before but a plugin update changed naming or available tools
Examples
"Create an agent for code review — reads only, outputs severity table"
"My reviewer agent doesn't trigger when I say 'check this PR'"
"Improve the description of my tester agent, it keeps clashing with developer"
# Natural language triggers — all route to agent-creator
"new agent for security scanning"
"agent isn't picking up my requests"
"fix agent description"
Flow
- Clarify intent
Asks 2-3 targeted questions: desired role, allowed tools, model tier (fable / opus / sonnet / haiku). For improvement requests, reads the existing agent file first.
- Parallel analysis
Launches multiple Explore subagents concurrently — codebase conventions, existing agents in scope, CLAUDE.md rules, stack details. Results are merged before writing.
- Synthesize
Extracts project-specific patterns, naming conventions, and anti-patterns. Determines description format: single-line, with
Triggers:list, or multi-line with<example>blocks (for ambiguous agents only). - Write
Produces a complete
.mdfile: frontmatter with all required and relevant optional fields, then a system prompt structured as Role → Context → Patterns → Commands → Checklist. Every generated agent also gets amaxTurnssized to its role plus a checkpointing instruction, so an abort stays recoverable. - Validate
Checks name format (
[a-z0-9-]+), description keyword density, tool minimality (least privilege), no duplicated CLAUDE.md rules in body, unique name in scope, theReturn Contractblock present, andScope Fitpresent exactly when the agent writes code. - Optimize
Runs
brewtools:text-optimizeon the output — converts prose to tables, removes filler, trims to dense LLM-readable format (~30% token savings typical).
Frontmatter reference — all fields
---
name: agent-name # REQ: lowercase-hyphens; no leading `-`, no `:` (reserved for plugin namespacing)
description: "..." # REQ: action verb + Triggers: keyword list
model: sonnet # OPT: fable|opus|sonnet|haiku|inherit (fable=claude-fable-5, Mythos-class, CC 2.1.170+)
effort: high # OPT: low|medium|high|xhigh|max (no auto, no bare integer)
maxTurns: 20 # OPT: integer, max turns before abort
tools: Read, Glob, Grep # OPT: omit = inherit all
disallowedTools: Write, Edit # OPT: explicit deny list
skills: skill1, skill2 # OPT: full content injected into context at startup
color: cyan # OPT: 8 valid values -- magenta is NOT one
memory: project # OPT: user|project|local -- auto-adds Read/Write/Edit
background: true # OPT: true keeps it backgrounded even when Claude wants the result (DEF unset, no `false` switch)
isolation: worktree # OPT: FM accepts `worktree` only -- LOW PRIORITY, see below (`remote` is invocation-level, never FM)
permissionMode: default # OPT: LOCAL-ONLY -- ignored + warn in plugin agents
mcpServers: [server1] # OPT: LOCAL-ONLY -- ignored + warn in plugin agents
initialPrompt: "..." # OPT: LOCAL-ONLY -- first prompt sent on start
observer: "reviewer" # OPT: LOCAL-ONLY -- observing agent
observerMessage: "watch for X" # OPT: LOCAL-ONLY -- brief for observer
observeSubagents: false # OPT: LOCAL-ONLY -- `false` disables observation
---Scope — verified against CC 2.1.233 (two separate parsers: local .claude/agents/ and plugin <plugin>/agents/**.md):
| Scope | Fields |
|---|---|
| Local + plugin — both parsers honor it | model, effort, maxTurns, tools, disallowedTools, skills, color, memory, background, isolation: worktree, initialPrompt |
| Local only — ignored for plugin agents | permissionMode, hooks, mcpServers (exactly these three) |
| Absent from the 2.1.233 field table — treat as internal/older, do not emit into a generated agent | observer, observerMessage, observeSubagents |
initialPrompt auto-submits as the first user turn only when this exact definition runs as the MAIN session (--agent <name> or the agent setting) — irrelevant on an ordinary subagent spawn, but honored for plugin agents too since origin isn’t the boundary, execution context is. Need permissionMode/hooks/mcpServers? Move the agent to .claude/agents/ — plugin agents ignore these three no matter how the frontmatter is written. isolation: remote is never a valid FM value anywhere — it is invocation-level only, reachable from an Agent(...) tool call.
Caution
isolation is low priority — don’t set it by default. Every spawn with isolation: worktree costs a git worktree setup plus disk, and there’s a known data-loss bug when it’s combined with permissionMode: bypassPermissions (#29110). Use it only when several agents write to the same files concurrently.
Caution
Do not set permissionMode: bypassPermissions by default. This is equivalent to running with --dangerously-skip-permissions — it silently skips all safety prompts. Only use it for fully-sandboxed CI environments where there is no interactive user. For local development, prefer permissionMode: default or permissionMode: acceptEdits. Also note: permissionMode is local-only — plugin agents ignore it entirely.
Description patterns by ambiguity level:
| Overlap | Format | Example |
|---|---|---|
| None — unique domain | Single-line action + Triggers | "Implements features, fixes bugs. Triggers: implement, fix bug, add feature" |
| Some — 1-2 other agents | Single-line + detailed Triggers | "Creates bash scripts. Triggers: create script, bash script, shell script" |
| High — creator/meta agents | Multi-line + 2-3 <example> blocks | See agent-creator.md source |
Subagent spawn note: CC allows nested subagent spawning, but prefer spawning from the main conversation so the orchestrator can integrate each agent’s result directly. Brewcode agents are stateless and resolve plugin paths via ${CLAUDE_PLUGIN_ROOT}.
Known active bugs: #29423 (subagents skip CLAUDE.md), #27736 (skills: in plugin agents), #31392 (global agents not discovered in v2.1.70+).
Subagent resource limits — turns, timeouts, checkpointing
Caution
There is no wall-clock timeout for a subagent. Not in frontmatter, not in settings.json, not as an environment variable. A subagent is bounded by turns, API-call timeouts, and token caps only. An agent stuck inside a single 25-minute Bash call is one turn — maxTurns will not touch it.
A turn = one model inference plus its tool calls; tool results return, then the next turn begins. Parallel tool calls in one assistant message count as ONE turn, so turns are usually fewer than tool calls. Observed in real transcripts from this repo: 12 turns / 19 tool calls, 21 / 33, 40 / 53, 51 / 55.
maxTurns sized by role — every generated agent gets an explicit value:
| Role | maxTurns |
|---|---|
| explorer / quick search | 40 |
| reviewer / architect / tester | 60 |
| docs / generator | 80 |
| developer / orchestrator | 120 |
Calibrated against real subagent transcripts (.claude/projects/*/subagents/agent-*.jsonl), not invented. At roughly 10-20 seconds per turn, 120 turns is a 20-30 minute ceiling. Rule of thumb: maxTurns ≈ 2-3x the role’s typical run.
maxTurns is an emergency anti-loop stop, not a budget. On exhaustion the binary emits Reached max turns limit (N) and the agent aborts — written files persist, but the final report is lost. That is why agent-creator also writes a checkpointing instruction into every generated agent body: record incremental progress to a report file after each milestone, and on resume read that file first and continue from the last checkpoint.
Relevant environment variables (set under env in settings.json):
| Variable | Bounds | Default |
|---|---|---|
CLAUDE_CODE_MAX_TURNS | Turn cap for ALL agents globally | unset |
API_TIMEOUT_MS | A single API call | 10 min |
CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MS | Background-agent stall; resets on streaming | 10 min |
CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS | Concurrent subagents | 20 |
CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH | Subagent nesting depth below main; 1 turns nesting off — verify the live cap, don’t hardcode a number | 3 |
CLAUDE_CODE_MAX_OUTPUT_TOKENS | Output tokens per response | model max |
MAX_MCP_OUTPUT_TOKENS | MCP result size | 25k |
BASH_DEFAULT_TIMEOUT_MS / BASH_MAX_TIMEOUT_MS | Bash tool only | 120s / 600s |
Tip
No total-per-session spawn cap exists. CLAUDE_CODE_MAX_SUBAGENTS_PER_SESSION (default 200, added in 2.1.212) was removed in 2.1.224 — concurrency and nesting depth are the only live spawn limits now.
Time-based control is only reachable through PreToolUse, which fires inside the subagent loop and carries agent_id and agent_type: warn at 80% of the budget, deny non-Write tools at 100%. SubagentStart and SubagentStop fire in the MAIN session, not inside the agent. No timer hook exists.
Recovering a partial result:
| Path / tool | Use |
|---|---|
.claude/projects/{project}/{sessionId}/subagents/agent-{agentId}.jsonl | Full subagent transcript (retention: cleanupPeriodDays) |
run_in_background: true + TaskOutput | Read partial output while it runs — from the MAIN session only; TaskOutput is filtered out of every subagent |
TaskStop | Kill a running subagent |
SendMessage | Resume a stopped subagent with context intact |
Return Contract
Verdict first, <=30 lines, path:line. No agent bodies, no pasted frontmatter, no analysis transcripts, no preamble. Per generated agent: file path, one-line role, model/maxTurns/tools on one line, validation verdict (pass, or the failing checklist item), text-optimizer run or skipped, and any assumption made about the brief. Longer material — analysis notes, generated bodies, full validation runs — goes to .claude/reports/<YYYYMMDD-HHMMSS>_agent-creator/; only the path comes back.
This is the same discipline Agent Creator bakes into every generated agent — see the Return Contract row in the Guardrails table above, a separate contract from this one. /brewtools:agent-return-setup enforces this at ~1000 / ~2500 est-tokens when installed; the contract itself ships unconditionally.
Skill Creator
Same design process for skills instead of agents.
Agent Deadline
Installs soft-deadline hooks for subagent runs — the practical continuation of the resource-limits section above.
GitHub source
Full frontmatter reference, description patterns, and system prompt templates.
Brewcode overview
All brewcode agents, skills, and hooks in one place.
Updating plugins
/brewtools:plugin-update to check and update the brewcode plugin suite in one command.
See the FAQ for details.