Your First Subagent
A skill is a saved prompt. A subagent is a separate worker: it gets its own context window, its own instructions and its own list of allowed tools, does the job, and hands back a summary. This chapter builds two read-only reviewers for the bookshelf project, runs both for real, and then checks what they claimed against the code.
A Worker With Its Own Desk
Anthropic describes subagents as specialised assistants that run in their own context window with a custom system prompt, specific tool access and independent permissions, and that return a summary to the main conversation, so that noisy work such as searches or logs stays out of it (Source 1). The picture to keep in mind is a colleague you hand a brief to: they work at their own desk, you do not watch every page they read, and you receive their note.
Two consequences follow, and the rest of the chapter keeps returning to them:
- It does not know what you know. A subagent does not see your conversation, your invoked skills or the files you already read. It receives its own prompt, the task message Claude writes for it, and a few environment items such as project CLAUDE.md files (Source 1). A brief that says "check the thing we discussed" is useless to it.
- You only see the summary. That keeps your main context small, and it means you must verify claims yourself. The runs below do exactly that.
Claude Code ships built-in subagents. The ones you meet first:
| Built-in | What it is for | Notes from the docs |
|---|---|---|
Explore | Fast, read-only search and analysis of code | Write and Edit are denied. Skips CLAUDE.md and the git status snapshot. One-shot: cannot be resumed |
Plan | Read-only research used in plan mode | Inherits the main model; skips CLAUDE.md and git status |
general-purpose | Anything that needs every tool | All tools available to subagents |
The skill you wrote in Chapter 18 with agent: Explore was already using the first of these. A custom subagent is the same mechanism with your own prompt and tool list.
The Agent File
A subagent is a Markdown file with YAML frontmatter. The body becomes its system prompt. Only name and description are required, and unrecognised fields are silently ignored, so a misspelled key fails quietly (Source 1).
| Field | What it does |
|---|---|
name, description | Identifier, and the text Claude reads to decide when to delegate |
tools | Allowlist. Omit it and the agent inherits every tool a subagent can have |
disallowedTools | Denylist removed from the inherited or listed tools |
model | sonnet, opus, haiku, fable, a full model ID, or inherit |
permissionMode | default, acceptEdits, auto, dontAsk, bypassPermissions, plan |
maxTurns | Cap on agentic turns; output is marked partial if it hits the cap |
skills | Skills whose full content is injected at start-up (preloading, not access control) |
mcpServers, hooks | MCP servers and lifecycle hooks scoped to this agent |
memory | Persistent memory scope: user, project or local |
background | Keep it in the background even when Claude would wait |
effort | low to max |
isolation | worktree runs it in a temporary git worktree |
color, initialPrompt | Display colour; an auto-submitted first turn when the agent runs as the main session |
Two more are documented separately: omitClaudeMd (skip CLAUDE.md files) and autoCompactWindow. Where the file lives decides who gets it, and higher entries win when names collide:
- Managed settings (organisation-wide)
- The
--agentscommand-line flag (JSON, this session only) .claude/agents/in the project (commit it; teammates get it)~/.claude/agents/(all your projects)- A plugin's
agents/directory
sql-reviewer: Delegating by Description
This file was written in Chapter 12 and already sits in the bookshelf project. It is deliberately small: three read-only tools and a prompt that says what to report and what to skip.
The bookshelf project has a test, BookQueryCountTest, that says listing books must run exactly one SQL statement. The question for the reviewer is the next one over: can listing books, or any neighbouring path, run more? The prompt names the agent but does not paste any code, so the subagent has to go and read it:
Real run AG-01: prompt, every step, and the answer (Checked)
| # | Who | Event | Content (shortened) |
|---|---|---|---|
| 1 | Main session | Agent call | subagent_type=sql-reviewer |
| 2 | Subagent | Brief it received | In the bookshelf project (Spring Boot, JPA, H2), check whether listing books in BookService can run more than one SQL statement (e.g. N+1 on… |
| 3 | Subagent | Glob call | {"pattern": "src/**/*.java", "path": "<project>"} |
| 4 | Subagent | Read call | {"file_path": "<project>/src/main/java/com/example/bookshelf/BookService.java"} |
| 5 | Subagent | Read call | {"file_path": "<project>/src/main/java/com/example/bookshelf/Book.java"} |
| 6 | Subagent | Read call | {"file_path": "<project>/src/main/java/com/example/bookshelf/Author.java"} |
| 7 | Subagent | Read call | {"file_path": "<project>/src/main/java/com/example/bookshelf/BookRepository.java"} |
| 8 | Subagent | Read call | {"file_path": "<project>/src/main/java/com/example/bookshelf/BookDto.java"} |
| 9 | Subagent | Read call | {"file_path": "<project>/src/test/java/com/example/bookshelf/BookQueryCountTest.java"} |
| 10 | Main session | Text | Listing books in `BookService` runs exactly 1 SQL statement, so there is no N+1 problem. The `sql-reviewer` subagent reached this by reading… |
Open the step table. The rows marked Subagent are the reviewer's own tool calls, a Glob and six Read calls. They happened in its own context. The main session shows one Agent call out and one result back, which is the whole boundary from the diagram above.
findById costs two SQL statements, one for the book and one for its author, because only the list methods use an entity graph. A reviewer can be confidently wrong, so I measured it: a temporary Hibernate-statistics test (deleted afterwards) printed 2. The claim was right, and it also pointed at a gap no existing test covers.api-reviewer: The Tool List Is the Guardrail
The second agent reviews the HTTP layer. Its body says it is read-only, but the sentence that matters is in the frontmatter: tools: Read, Grep, Glob. There is no Edit, no Write and no Bash for it to misuse, whatever its prompt says.
To test the guardrail I ran it as the whole session with --agent api-reviewer, and asked for exactly what it must not do, a fix. I also passed Edit and Write in --allowedTools, so the session itself would have permitted them:
Real run AG-02: prompt, every step, and the answer (Checked)
| # | Who | Event | Content (shortened) |
|---|---|---|---|
| 1 | Main session | Glob call | {"pattern": "**/*.java"} |
| 2 | Main session | Read call | {"file_path": "<project>/src/main/java/com/example/bookshelf/BookController.java"} |
| 3 | Main session | Read call | {"file_path": "<project>/src/main/java/com/example/bookshelf/ApiExceptionHandler.java"} |
| 4 | Main session | Read call | {"file_path": "<project>/src/main/java/com/example/bookshelf/CreateBookRequest.java"} |
| 5 | Main session | Text | I can't edit files in this session, so I haven't changed `BookController`. I read `BookController.java`, `ApiExceptionHandler.java` and `Cre… |
- No edit happened. The agent said it could not edit, and
git statusin the project shows no changed tracked files. No permission denial was recorded in the log. That fits the tool never being offered rather than being refused, but I did not capture the tool list, so treat that as an inference. - The review was real. I probed the HTTP layer with a temporary MockMvc test: a POST without
year, a search withouttitleandGET /api/books/abceach returned 400 with noapplication/problem+jsonbody, while the handled 404 returned one. The convention in the project's CLAUDE.md says all errors should be ProblemDetail, so this is a genuine gap. - Model: not what the file says. The agent file says
model: haiku. The log lists onlyclaude-sonnet-5-5, and my runner script passes--model sonnet. I did not test which one wins, so thehaikuline was not exercised in this run.
tools beats a polite prompt. A sentence like "never edit files" is a request. An allowlist is a mechanism. Use the sentence to explain intent and the allowlist to enforce it. The same reasoning is why Chapter 19's skills carry narrow allowed-tools.Five Ways to Start One
| Way | How | Used here? |
|---|---|---|
| Automatic | Claude matches your request to a subagent's description; wording such as "use proactively" encourages it | No (I named the agent in the prompt) |
| By name in words | "Use the sql-reviewer subagent to ..." | Yes, AG-01 |
| @-mention | Your whole message still goes to Claude, which writes the subagent's prompt | No |
| Whole session | claude --agent name, or the agent key in project settings | Yes, AG-02 |
| Fork | A subagent that inherits the whole conversation so far; /subtask starts one by hand | No |
Subagents run in the foreground (they block you; permission prompts reach you) or in the background (they run alongside, and prompts surface in your main session). Background agents get a smaller built-in tool set. In an interactive session, fork mode is on by default in current versions, which affects how Claude waits for helpers (Source 1). Chapter 17 shows how to read what happened afterwards.
A fork deserves a sentence of its own. A normal subagent starts fresh and costs you the effort of briefing it. A fork starts with everything the main session knows, shares its prompt cache and therefore costs less for context-heavy side tasks, but loses the isolation that was the point of a subagent. Use a fork when the briefing would be longer than the task.
Subagent, Skill, Fork or Just Ask?
| You want | Reach for | Because |
|---|---|---|
| A quick change, or lots of back and forth | The main conversation | Phases share context and latency matters (Source 1) |
| A reusable procedure that runs where you are | A skill | It loads into the current context |
| Lots of reading, only the conclusion matters | A subagent | Verbose output stays out of your context |
| A hard tool restriction | A subagent with tools | An allowlist is enforced, a prompt is a request |
| A side task that needs everything you know | A fork | It inherits the conversation, and shares its cache |
| Several workers that must talk to each other | An agent team | Chapter 21 |
Where First Agents Go Wrong
- A vague description routes badly. Claude chooses by description. Write one that singles the agent out ("reviews REST controllers and exception handling for contract problems"), not "helps with code". The combined descriptions of your custom agents should stay under 15,000 tokens or Claude Code warns at start-up (Source 1).
- A thin brief. The subagent starts from zero. In AG-01 the main session wrote a full prompt for it (row 2 of the table shows the brief the reviewer received); a one-line brief would have produced a worse review. When you delegate by hand, include the file names and the question.
- Results flow back into your context. Many subagents returning long reports can fill the window anyway. Ask for a short, structured summary in the agent's body.
- Unverified summaries. Both runs above ended with "I read the code and ran nothing". That is the honest answer, and it is also your cue to check.
- Nesting and concurrency have limits. By default subagents can spawn subagents up to three layers deep and up to 20 can run at once; both limits can be changed with environment variables. To stop one agent from spawning others, leave
Agentout of itstools. - Cost. Each subagent uses its own tokens against the same limits as your main conversation. The two runs above cost about $0.13 and $0.06 by the log's own estimate; they were small on purpose.
One agent file in the examples repository was not run: test-writer, which edits files and sets isolation: worktree so that its changes land in a temporary copy of the repository. It is a good second step once you trust a read-only agent, but I did not spend on it.
Key Takeaways, Exercises and Sources
- A subagent is a separate context: it starts without your history and returns a summary.
- The file is Markdown plus frontmatter. Only
nameanddescriptionare required; unknown keys are ignored silently. - Enforce with
tools, explain with the body. An allowlist is a mechanism; a sentence is a request. - Brief it completely. It cannot see what you saw.
- Check the summary. Both real runs here were verified against the code, and one claim was confirmed with a measurement.
Exercise 1 Beginner
Create .claude/agents/changelog-reader.md with tools: Read, Grep, Glob and a one-paragraph prompt. Ask Claude by name to use it on a file in your own project. Open the transcript and find the boundary: which calls were the subagent's, and what did the main session receive?
Learning outcome: see the isolation boundary in a real log.
Exercise 2 Intermediate
Give your agent a deliberately dangerous request ("delete the old tests"). Confirm that nothing changed, then add Edit to tools and repeat on a throwaway branch. Which behaviour came from the prompt and which from the allowlist?
Learning outcome: separate requests from mechanisms.
Exercise 3 Advanced
Write two agents with overlapping descriptions and watch which one Claude picks for five prompts. Rewrite the descriptions until routing is predictable. Check that the combined description text stays well under the documented budget.
Learning outcome: treat descriptions as a routing table.
- Anthropic, Create custom subagents — built-ins, frontmatter fields, scopes and priority, invocation, context isolation, foreground and background, resuming, forks, cost notes and the example agents. The page was read in full.
AG-01 and AG-02 were executed on 2026-10-31; their checks (a Hibernate statement count and a MockMvc probe) used temporary tests that were deleted afterwards. The test-writer agent, memory, agent hooks and background mode were not run. The comparison table in section 06 combines Anthropic's guidance with the author's judgement. Agent files are in the examples repository under agents/.