How to Create Claude Code Subagents (File Format + Examples)
Create Claude Code subagents as Markdown files: frontmatter fields, tools and model settings, example agents, and why a subagent file gets skipped.
A Claude Code subagent is a Markdown file with YAML frontmatter. The frontmatter holds its configuration, and the body becomes its system prompt. Save it in .claude/agents/ for one project or ~/.claude/agents/ for every project on your machine, and Claude delegates to it when the task matches its description.
Only name and description are required. Everything else, including tools and model, is optional. The quickest start is to ask Claude to write the file for you, then read what it produced and tighten it.
How Claude Code subagents work#
A subagent gets its own system prompt, which is the body of its file. It receives that prompt plus basic environment details like the working directory. It does not get the Claude Code system prompt.
Claude decides when to delegate by reading each subagent's description. That makes the description the routing rule. A vague one like "helps with code" gives Claude nothing to match on. A specific one like "Reviews code for quality and best practices" does.
You can also ask directly:
Use the code-improver agent to suggest improvements in this project
In the transcript, a delegation shows up as a tool call row with the subagent's name and a short task description, such as code-improver(Suggest code improvements). That's how you see which subagent ran.
When to use a subagent#
I'd reach for one when a task is narrow enough to describe in a paragraph and you want to restrict what it can touch. Code review with read-only tools is the obvious case. The official docs give the same advice:
- Design focused subagents. Each one should excel at one specific task.
- Write descriptions that single out one subagent. Keep the combined set within the 15,000-token description budget.
- Limit tool access. Grant only the permissions the job needs.
- Check project subagents into version control so your team shares them.
If you find yourself writing a subagent whose description says "does many things," split it.
How to create a subagent file#
This is the smallest useful example. Save it as .claude/agents/code-reviewer.md:
---
name: code-reviewer
description: Reviews code for quality and best practices
tools: Read, Glob, Grep
model: sonnet
---
You are a code reviewer. When invoked, analyze the code and provide
specific, actionable feedback on quality, security, and best practices.
The filename doesn't have to match name. Claude Code watches both agents directories, so adding or editing a file is picked up within a few seconds, with no restart.
Three cases still need a restart:
- You created the first agent file in an
agentsdirectory that didn't exist when the session started. - You added or edited a subagent under a directory added with
--add-diror/add-dir. - The session was started with
--disable-slash-commands.
For the user-level version, the docs' quickstart prompt is a good template:
Create a personal code-improver subagent in ~/.claude/agents/ that scans
files and suggests improvements for readability, performance, and best
practices. It should explain each issue, show the current code, and
provide an improved version. Make it read-only and have it use Sonnet.
Claude writes a file like this:
---
name: code-improver
description: Scans files and suggests improvements for readability, performance, and best practices. Use after writing or modifying code.
tools: Read, Grep, Glob
model: sonnet
---
You are a code improvement specialist. For each issue you find, explain
the problem, show the current code, and provide an improved version.
Note the second sentence in that description: "Use after writing or modifying code." Telling Claude when to delegate is exactly what the field is for.
Frontmatter fields: tools, model and the rest#
Field names are case-sensitive and multi-word names use camelCase. Claude Code ignores a field it doesn't recognize without reporting an error, so a typo like max_turns silently does nothing.
| Field | Required | What it does |
|---|---|---|
name |
Yes | Unique identifier, at most 256 characters. Hooks receive it as agent_type. Can't contain : |
description |
Yes | When Claude should delegate to this subagent |
tools |
No | Allowed tools, as a comma-separated string or YAML list. Inherits every tool available to subagents if omitted |
disallowedTools |
No | Tools removed from the inherited or specified list |
model |
No | sonnet, opus, haiku, fable, a full model ID such as claude-opus-5-5, or inherit |
permissionMode |
No | default, acceptEdits, auto, dontAsk, bypassPermissions, plan, or manual (alias for default) |
maxTurns |
No | Maximum agentic turns before the subagent stops |
skills |
No | Skills preloaded into context at startup, with full content injected |
mcpServers |
No | MCP servers available to this subagent, by name or inline definition |
hooks |
No | Lifecycle hooks scoped to this subagent |
memory |
No | Persistent memory scope: user, project, or local |
background |
No | true keeps it in the background even if Claude asks for the foreground |
effort |
No | low, medium, high, xhigh, or max; available levels depend on the model |
isolation |
No | worktree runs it in a temporary git worktree |
color |
No | red, blue, green, yellow, purple, orange, pink, or cyan |
omitClaudeMd |
No | true starts it without user, project, and local CLAUDE.md files (v2.1.271 or later) |
A few details that matter in practice:
- Tools. Omitting
toolsmeans the subagent inherits everything available to subagents. For a read-only reviewer, list the tools explicitly. If no entry in your list resolves to a tool, the subagent usually fails to launch with an error naming the entries. - disallowedTools. An entry with a specifier, such as
Bash(git push *), still removes the whole tool. Don't count on it as a fine-grained rule. - Skills. To preload skills, use the
skillsfield rather than listingSkillundertools. - Model. If you omit
model, Claude Code picks one using its subagent model order. If you want a predictable result, set it.inherituses the parent's model. - Plugin subagents.
permissionMode,mcpServers, andhooksare ignored for plugin subagents. - Max turns. When a subagent hits
maxTurns, Claude Code returns its output marked as partial and Claude can resume it. The partial marking requires v2.1.246 or later.
More example agents#
These build on the same format. They're starting points, not official templates.
A reviewer that can never edit files, with a lower effort level:
---
name: diff-reviewer
description: Reviews a diff for bugs and risky changes. Use before committing.
tools: Read, Grep, Glob
model: haiku
effort: low
---
Review the changes you are pointed at. Report only real problems, each with
the file, the line, and a one-sentence reason.
A subagent that inherits all tools except one, and works in an isolated copy of the repo:
---
name: refactor-worker
description: Performs a mechanical refactor in an isolated worktree
disallowedTools: WebFetch
model: inherit
isolation: worktree
maxTurns: 30
color: orange
---
Apply the requested refactor. Keep each change small and explain what you
changed when you finish.
With isolation: worktree, the subagent's worktree is cleaned up automatically if it makes no changes. The branch point is your default branch, not the parent session's HEAD.
Tools can be a YAML list too:
tools:
- Read
- Grep
- Glob
Check your frontmatter before Claude skips it#
Claude Code skips some files without telling you in the session. The rules from the docs:
- No
name: treated as documentation kept beside your agents. - The opening
---isn't the first line: read as having no frontmatter. namestarts with-, contains:, or exceeds 256 characters: skipped, error in the debug log.- A
namebut nodescription: skipped, reason in the debug log. - YAML that doesn't parse: no fields read, skipped, parse error in the debug log.
This script mirrors those rules on in-memory samples. It's a simplified check (it reads key: value lines only), so treat the real YAML parser as the authority.
function check(text) {
const lines = text.split("\n");
if (lines[0] !== "---") return "skipped: no frontmatter, treated as documentation";
const end = lines.indexOf("---", 1);
if (end === -1) return "skipped: frontmatter never closes";
const fm = {};
for (const line of lines.slice(1, end)) {
const i = line.indexOf(":");
if (i > 0) fm[line.slice(0, i).trim()] = line.slice(i + 1).trim();
}
if (!fm.name) return "skipped: no name, treated as documentation";
if (fm.name.startsWith("-") || fm.name.includes(":") || fm.name.length > 256)
return "skipped: invalid name";
if (!fm.description) return "skipped: no description";
return "loads as '" + fm.name + "'";
}
const samples = {
good: ["---", "name: code-reviewer", "description: Reviews code", "tools: Read, Grep", "---", "Prompt."],
noDescription: ["---", "name: helper", "---", "Prompt."],
colonInName: ["---", "name: my:reviewer", "description: x", "---", "Prompt."],
blankFirstLine: ["", "---", "name: late", "description: x", "---", "Prompt."],
};
for (const [label, lines] of Object.entries(samples)) {
console.log(label.padEnd(15), check(lines.join("\n")));
}
To run the real check on a directory, use claude plugin validate .claude/agents. It finds files whose frontmatter doesn't parse, but it won't flag a file that parses and simply has no name. It needs v2.1.233 or later. To see the debug log reasons, start Claude Code with --debug.
Common mistakes and gotchas#
Claude can't find the new subagent. If ~/.claude/agents/ didn't exist before the session started, a running session won't detect the new directory. Restart Claude Code.
The subagent never gets picked. Check the description first. If several subagents have overlapping descriptions, Claude has no basis to choose. Also remember the combined descriptions share a 15,000-token budget.
A field has no effect. Unknown fields are ignored silently. Compare your spelling against the table: maxTurns, disallowedTools, permissionMode.
The subagent has more power than you meant. Omitting tools inherits every tool available to subagents. Set tools explicitly on anything that should be read-only.
Working directory surprises. A subagent starts in the main conversation's current working directory, and cd in its Bash or PowerShell calls doesn't persist between calls or affect the main conversation. If you need real separation, use isolation: worktree.
Using /agents and finding no wizard. On current versions, /agents prints a reminder to ask Claude or edit the agents directories directly. The interactive wizard with Running and Library tabs exists on Claude Code v2.1.197 and earlier.
Quick reference#
- Project scope:
.claude/agents/name.md. User scope:~/.claude/agents/name.md. - Required:
nameanddescription. Everything else is optional. - Set
toolsexplicitly for read-only agents; omit it only if inheriting all tools is what you want. - Set
modelif you care which model runs. Options:sonnet,opus,haiku,fable, a full ID, orinherit. - Write the description as a routing rule: what the agent does and when to use it.
- Edits are picked up in a few seconds, except in new directories,
--add-dirdirectories, and--disable-slash-commandssessions. - Debug a skipped file with
--debug, or validate a directory withclaude plugin validate. - Full field list and details: the subagents documentation.
Quick answers
How do I invoke a Claude Code subagent?
Ask for it by name, for example "Use the code-improver agent to suggest improvements in this project". Claude can also delegate on its own when your request matches the subagent's description.
How do I choose the model for a subagent?
Set the model field to sonnet, opus, haiku, fable, a full model ID such as claude-opus-5-5, or inherit. If you omit it, Claude Code picks one using its subagent model order.
Why is my Claude Code subagent not working?
Most often the file was skipped: no name, no description, a name containing :, or YAML that doesn't parse. Run Claude Code with --debug to see the reason, and restart if the agents directory was newly created.
How do I give a subagent preloaded skills?
Use the skills field in the frontmatter, which injects the full skill content at startup. Don't list Skill under tools for that purpose.
Did this solve it?
One tap. No account.
Sorry about that. What was missing?
from 0 readers
Saved you an hour? Send a tip.
USDC or ETH on Base. Keeps the notes free and the examples running.

0x9dFD2Ee86182f92464b50809C6702B999a0Cd54f
On a computer? Scan the code with your phone wallet, or copy the address.
USDC or ETH on Base works best. Other tokens on Base, Ethereum or Arbitrum also reach this address. Tips are optional and unlock nothing; every guide stays free.
Discussion
Start the discussion
Next note