AI Agents

Claude Code Subagents Guide: Writing Agent Definitions That Work

How to write effective Claude Code subagent definitions in .claude/agents/ - frontmatter fields, description writing, tool scoping, model selection.

A Claude Code subagent that does not trigger when it should is useless. One that triggers when it should not is disruptive. The difference between the two is almost entirely in the description field - the single most important field in the agent definition, the one most developers write in 30 seconds and then wonder why their agent is not working. This guide covers the complete structure of a Claude Code agent definition, every field that matters, and the writing patterns that produce agents that trigger correctly and perform their intended role.

Claude Code subagent
A Claude Code subagent is a specialised agent defined in a .claude/agents/[name].md markdown file with YAML frontmatter specifying its name, description (routing trigger), model, and allowed tools - invoked by the Claude Code orchestrator when a user request matches the agent's description, and run in isolation with its own context and tool scope.

The agent definition file structure

Claude Code subagents live in .claude/agents/[name].md within your project, or in ~/.claude/agents/[name].md for user-level agents available across all projects. The file format is a YAML frontmatter block followed by the agent's instruction body:

---
name: code-reviewer
description: Performs code review on staged or modified files. Reviews for correctness, performance, security issues, and adherence to project conventions. Trigger when the user asks for a code review, asks to review changes, or uses phrases like "check my code", "review this", "LGTM?", or "does this look right".
model: claude-sonnet-5
tools:
  - Read
  - Bash
  - WebSearch
---

You are a senior code reviewer for this project. Your role is to identify correctness issues, security vulnerabilities, performance problems, and deviations from the project's conventions.

## Review process

1. Read the files the user mentions or the staged changes (use `git diff --staged` or `git diff HEAD`)
2. Identify issues by severity: Critical (security, data loss), High (correctness), Medium (performance, maintainability), Low (style, minor)
3. Report findings in a structured format with file:line references
4. Suggest specific fixes, not just problem descriptions

## Project conventions

[Add project-specific conventions here - naming patterns, test requirements, etc.]

The description field - the most important field

The description is the field Claude Code reads to decide whether to invoke your agent for a given user request. It is not documentation for you - it is a routing signal for the orchestrating model. There are two things the description must do: state the agent's purpose clearly, and enumerate the trigger conditions that should invoke it.

The trigger conditions are the part most developers skip. Without them, the orchestrator has to infer from the purpose description alone whether the agent should run - and it will often infer incorrectly. With explicit trigger examples, the match is reliable:

---
# Weak description - no trigger conditions
description: Helps with database queries and migrations.

# Strong description - purpose + explicit triggers
description: Executes and optimises database queries, writes migrations, and diagnoses slow queries. Trigger when the user asks to write a SQL query, run a migration, explain a query plan, optimise a slow query, or uses phrases like "add a column", "create a table", "why is this query slow", or "write a migration for".
---

The trigger phrases should include: the exact user phrasings that should invoke the agent, related synonyms, and common imperative forms ("add", "create", "fix", "check", "why is"). Include phrases that describe the outcome the user wants ("why is this slow") not just the technical operation ("optimise query").

The model field

The model field selects which Claude model runs this agent. It is optional - when omitted, the agent uses whatever model the parent Claude Code session is using. Specify it explicitly when:

  • The agent does a simple, high-frequency task where claude-haiku-4-5-20251001 is sufficient and faster
  • The agent does complex multi-step reasoning where claude-opus-5 produces meaningfully better results
  • You want the agent's model choice to be independent of the user's session model
---
# Fast agent for simple formatting/classification tasks
name: pr-title-formatter
model: claude-haiku-4-5-20251001
description: Formats pull request titles to match the conventional commit standard. Trigger when the user asks to format, fix, or write a PR title.
tools:
  - Bash
---

# Capable agent for architectural decisions
name: architecture-advisor
model: claude-opus-5
description: Reviews architectural decisions, evaluates trade-offs, and proposes designs for complex system problems. Trigger when the user asks about system design, architecture, or "how should I structure" a feature.
tools:
  - Read
  - WebSearch
---

The tools field - scoping correctly

The tools field is a list of Claude Code built-in tool names the agent is allowed to use. Restricting tools to those the agent actually needs serves two purposes: it prevents the agent from taking actions outside its intended scope, and it reduces the set of options the model has to consider at each step, improving focus.

Available built-in tools: Read, Write, Edit, Bash, WebSearch, WebFetch, TodoWrite, NotebookEdit. MCP server tools are also available when registered.

---
# Read-only research agent - no write access
name: dependency-auditor
description: Audits project dependencies for security vulnerabilities and outdated packages. Checks package.json, lock files, and known CVE databases. Trigger when the user asks to audit dependencies, check for vulnerabilities, or "are my packages up to date".
tools:
  - Read
  - Bash
  - WebSearch
# Note: no Write or Edit - this agent never modifies files

---
# Write-capable migration agent
name: migration-writer
description: Writes database migration files for schema changes. Reads existing migrations to understand conventions, then generates new migration files. Trigger when the user asks to create a migration, add a column, create a table, or change a schema.
tools:
  - Read
  - Write
  - Bash
---

The instruction body - writing the agent's behaviour

The body of the markdown file is the system prompt that defines the agent's behaviour. Unlike generic system prompts, agent instruction bodies should be highly specific to the agent's domain and project context. Structure the body with:

  • Role declaration - One sentence stating what this agent is and what it does. Specific, not generic ("You are a TypeScript migration specialist for this codebase" not "You are a helpful assistant").
  • Process steps - An ordered list of what the agent should do. Numbered steps produce more consistent and auditable behaviour than open-ended instructions.
  • Project-specific context - File paths, naming conventions, test requirements, architectural constraints that the agent needs to do its job correctly. This is information Claude Code cannot infer from the codebase alone.
  • Output format - What the agent should produce and in what format. If it writes files, which files and where. If it reports findings, what structure.

Testing your agent definitions

An agent definition is not working correctly until you have verified it triggers for the right inputs and does not trigger for the wrong ones. Test procedure:

  1. Open Claude Code in a project where the agent is registered
  2. Use each of your trigger phrases verbatim and confirm the agent is selected
  3. Use requests that should NOT trigger the agent and confirm it is not selected
  4. Run the agent against a representative task and verify output quality
  5. Run against an edge case (empty input, malformed input, out-of-scope request) and verify it fails gracefully

If the agent does not trigger reliably: expand the trigger phrases in the description to include more variants. If the agent triggers when it should not: make the trigger conditions more specific (add domain constraints: "only for this project's database schema" rather than "for any SQL").

Composing agents - calling agents from agents

Claude Code agents can invoke other agents by name within their instruction body, creating an orchestrator-worker composition. The orchestrator agent's instruction body explicitly delegates to worker agents:

---
name: full-feature-pipeline
description: Orchestrates the full feature development pipeline: writes code, then tests, then documentation. Trigger when the user asks to "implement a feature end to end" or "build and test" something.
model: claude-sonnet-5
tools:
  - Read
  - Bash
---

You coordinate a three-stage feature pipeline:

1. Invoke the `code-writer` agent to implement the feature
2. Invoke the `test-writer` agent to write tests for the implementation
3. Invoke the `doc-writer` agent to write documentation

Each agent receives the feature specification and the relevant file paths. You synthesise their outputs and report the overall result.

The agent name in the instruction body must exactly match the name: field in the target agent's frontmatter. The orchestrator does not need to list the worker agents' tools - each worker runs with its own tool set defined in its own definition file.

Subagent composition in Claude Code mirrors the agent supervisor pattern - an orchestrator agent routes to workers, each with narrow scope. For managing the cost of multiple subagent runs in a pipeline, see agent cost management strategies.