What a subagent is
A markdown file in .claude/agents/ that defines a separate execution
context. Unlike memory, rules and skills, which modify your conversation, a
subagent gets:
- its own context window
- its own system prompt (the file body replaces the default)
- its own tool allowlist
- its own model
- its own permission mode
It does its work in isolation and returns only a summary to your conversation. That isolation is the entire point.
graph TD
subgraph MAIN["Main conversation — your context window"]
U["Your prompt"] --> C["Claude"]
C --> D{"Delegate?"}
D -->|"No"| R1["Direct answer"]
D -->|"Yes"| SPAWN["Spawn subagent"]
SUM["Summary returns<br/><i>~200 tokens</i>"] --> C2["Claude continues"]
end
subgraph SUB["Subagent — separate context window"]
SPAWN --> SP["Own system prompt"]
SP --> W["Reads 40 files<br/>runs test suite<br/><i>~80,000 tokens</i>"]
W --> COND["Condense to findings"]
end
COND --> SUM
The 80,000 tokens never enter your conversation. That is why subagents are the right answer for log triage, test-output analysis, and codebase archaeology.
Anatomy
---
name: log-triage
description: Parses large log dumps and reports only the relevant failures. Use when investigating a test failure or a production incident with more than ~200 lines of logs.
tools: Read, Grep, Glob, Bash
model: haiku
---
You triage logs. Read the indicated files, find the first error in causal
order — not downstream noise — and report:
- The failing component and the root error
- Stack frames belonging to our code, not framework frames
- The three log lines immediately preceding the failure
Do not summarise healthy log lines. Do not speculate about fixes.
Output at most 30 lines.
model: haiku is doing real work here: high-volume, low-judgement grep work at a
fraction of the cost, and none of it touches your main context.
Tool restriction is a real boundary
The tools: list is enforced outside the model. An agent without Write and
Edit cannot modify code, no matter what it concludes it should do. This is
the difference between asking for a read-only review and having one.
---
name: security-reviewer
description: Reviews a diff for security defects. Use before merging anything touching auth, input parsing, or outbound requests.
tools: Read, Grep, Glob, Bash(git diff *), Bash(git log *)
model: opus
---
You review diffs for security defects only. You cannot edit files, and you
should not propose a patch as a diff; describe the fix in prose.
Report only findings you can point at with a `file:line`. For each:
- **What** an attacker can do
- **How** they reach the code path from an untrusted input
- **Confidence**: certain / likely / speculative
Rank by exploitability, not by how interesting the bug is. If you find nothing,
say so in one line rather than padding the report with observations.
Note the Bash(git diff *) scoping: the agent can read the diff but cannot run
arbitrary shell commands. Giving a subagent broad Bash “just in case” quietly
defeats the isolation you set it up for.
More agents worth having
---
name: test-analyst
description: Runs the test suite and reports the failures that share a root cause. Use after a refactor, or when a CI run has more than a handful of failures.
tools: Read, Grep, Glob, Bash
model: sonnet
---
Run the suite, then group the failures by *cause*, not by file.
For each group: the shared root cause, the number of tests it explains, and one
representative failure with its assertion. Order groups by how many tests they
explain. Explicitly list any failure you could not attribute to a group.
Never edit code. Never re-run a single test to "confirm" — one full run is
enough.
---
name: dependency-archaeologist
description: Traces every caller and every implementation of a symbol across the repository. Use before renaming, deleting, or changing the signature of anything shared.
tools: Read, Grep, Glob
model: haiku
---
Given a symbol, produce a complete call map:
- Direct callers, with `file:line`
- Indirect reach: anything that wraps a direct caller and is itself exported
- Test-only callers, listed separately
- Any dynamic reference — reflection, string lookup, generated code, config —
that a grep for the identifier would find but a compiler would not
State explicitly whether the change is safe to make mechanically. Read only.
Three ways to run an agent definition
The same file can occupy three different positions. This is the distinction between “agent” and “subagent” that trips people up: they are not different artifacts, they are different placements.
graph TD
DEF["Agent definition<br/>.claude/agents/reviewer.md"]
DEF --> S["SUBAGENT<br/>Claude delegates via the Agent tool,<br/>or you @-mention it"]
DEF --> M["MAIN-SESSION AGENT<br/>claude --agent reviewer<br/>or agent: in settings.json"]
DEF --> F["FORK<br/>/subtask <task>"]
S --> S1["Fresh context<br/>Own system prompt<br/>Returns a summary"]
M --> M1["Entire session adopts it<br/>Default Claude Code<br/>system prompt is replaced"]
F --> F1["Inherits your full conversation<br/>Same prompt, tools, model<br/>Reuses the prompt cache"]
| Mode | Start it with | Context | Use when |
|---|---|---|---|
| Subagent | Claude delegates, or @reviewer |
Fresh, empty | A side task that would flood your context, or one needing hard tool restrictions |
| Main-session agent | claude --agent reviewer, or "agent": "reviewer" in settings |
Yours, but with a replaced system prompt | You want every turn this session to behave a certain way |
| Fork | /subtask <task> |
Inherits everything so far | The task needs the conversation you’ve already had, but its output shouldn’t clutter your transcript |
Concrete guidance:
- Subagent: “run the full test suite and tell me what failed”, “trace every
caller of this function across the repo”, “audit
internal/for directtime.Now()calls”. Also: a reviewer agent whosetools:list omits Write and Edit, so it cannot modify code even if it decides it should. - Main-session agent: launching
claude --agent security-reviewerfor a dedicated review session, or pinning a repository’s default posture insettings.json. - Fork: “now write the tests for what we just built” while you keep going on the implementation. Cheaper than a fresh subagent because it reuses the parent’s prompt cache.
Related but distinct: subagents all live inside a single session. For genuinely parallel long-running work you want separate sessions, not subagents.
Choosing between a subagent and a fork
flowchart TD
Q["A side task needs doing"] --> A{"Does it need the<br/>conversation so far?"}
A -->|"No"| B{"Will it read a lot,<br/>or need restricted tools?"}
B -->|"Yes"| SUB["Subagent"]
B -->|"No"| INLINE["Just do it inline"]
A -->|"Yes"| C{"Should its output stay<br/>out of the transcript?"}
C -->|"Yes"| FORK["Fork — /subtask"]
C -->|"No"| INLINE
The mistake in both directions is common: spawning a subagent for a task that needs the last twenty minutes of conversation (it starts cold and re-derives everything), or doing an 80,000-token log read inline because it felt simpler than delegating.
Where agents live, and their precedence
| Priority | Location |
|---|---|
| 1, highest | Enterprise managed settings |
| 2 | --agents CLI flag (session-only JSON) |
| 3 | .claude/agents/, project |
| 4 | ~/.claude/agents/, user |
| 5, lowest | Plugin agents/ directory |
This runs opposite to skills. For agents, project beats user. For skills, user beats project. There is no mnemonic; you simply have to know it. See skills vs agents.
Verify with /agents, which lists each available agent and the file it came
from.
Built-in subagents
Explore and Plan ship with Claude Code. Both skip your CLAUDE.md files and
the parent session’s git status to keep research fast and cheap. Every other
built-in and every custom subagent loads both.
Practical consequence: if Explore seems to ignore a project convention, that is
by design. Put anything Explore must respect into the prompt you give it, not
into CLAUDE.md.