Subagents & Custom Agents
|
This content was generated with the assistance of AI and should be verified against the official documentation of each tool and framework before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
This page is written against the Claude Code CLI 2.1.283, VS Code 1.139 with the GitHub Copilot Chat
extension, and the GitHub Copilot CLI 1.0.88, all re-verified as current as of 2026-09-28; re-check the
linked docs before relying on an exact field name, since both products change these surfaces often. The
ai-catalog examples are excerpted from this account’s ai-catalog
repository, pinned to commit
58fb709
(58fb70954404f9d539031a02ac6d4413f03745be).
A subagent is a delegated worker that runs a task in its own context window and hands back a result, instead
of that work accumulating in the calling conversation. Both Claude Code and GitHub Copilot ship this idea; the
sections below cover each tool’s mechanism, then how to choose between a subagent, a
context: fork skill, and an agent team.
Claude Code subagents
Built-in subagents
Claude Code ships several built-in subagent types, verified against Claude Code — Subagents:
| Type | What it is |
|---|---|
|
A fast, read-only agent for searching and analyzing a codebase. Inherits the main conversation’s model (capped at Opus on the Claude API) and has only read-only tools. |
|
The research agent Claude Code uses in plan mode to gather context before presenting a plan. Also inherits the main conversation’s model and is read-only. |
|
A capable agent with every tool available to subagents, for complex, multi-step tasks that need both
exploration and action. It is the default for a |
|
A catch-all agent with every available tool, used when a task doesn’t fit a more specialized agent. |
|
Runs on Sonnet; used when |
|
Runs on Haiku; answers questions about Claude Code’s own features. |
Explore and Plan are the ones most relevant to everyday delegation; both skip CLAUDE.md and the git status
snapshot to keep their context small. general-purpose is the usual target for anything broader. A built-in is
used by naming it, either in a prompt or as a forked skill’s agent:
> Use the Explore agent to find every place DocsController maps a ProblemDetail
To stop Claude from delegating to a particular built-in, deny it in settings:
.claude/settings.json{
"permissions": {
"deny": ["Agent(Explore)"]
}
}
See Claude Code — Subagents ("Built-in subagents" and "Disable specific subagents").
Custom subagents: .claude/agents/*.md
A custom subagent is a Markdown file with YAML frontmatter, one file per agent, at .claude/agents/<name>.md
(project scope, checked into version control), ~/.claude/agents/<name>.md (user scope, across all projects),
under a plugin’s agents/ directory, or under a managed-settings directory for an organization-wide agent.
Project subagents take precedence over user subagents, which take precedence over plugin agents; see
the Subagents reference for the full precedence order, including
managed settings and the session-only --agents CLI flag.
The table below covers every frontmatter key currently documented, verified against the same reference:
| Key | Type | Default | What it does |
|---|---|---|---|
|
string |
required |
The agent’s unique identifier; cannot contain |
|
string |
required |
When Claude should delegate to this subagent, matched the same way a skill’s |
|
string or list |
every available tool |
An allowlist of tools the subagent may use, e.g. |
|
string or list |
none |
Tools removed from the inherited or specified |
|
string |
falls back through a precedence chain |
|
|
string |
none |
A display color for the agent in the terminal UI: |
|
string |
inherits the main session’s mode |
|
|
list |
none |
Skill names to preload into the subagent’s context at startup — the full |
|
list or map |
none |
MCP servers available to the subagent: entries name a server already configured elsewhere, or define one inline. Ignored for plugin subagents. See Configuring MCP Servers. |
|
integer |
unlimited |
Maximum agentic turns before the subagent stops; its output is then marked partial and Claude can resume it. |
|
map |
none |
Hooks scoped to this subagent while it is active. Any hook event is accepted; the most common are
|
|
string |
none |
A persistent memory scope for cross-session learning: |
|
boolean |
|
When |
|
boolean |
|
When |
|
string |
inherits the session’s effort |
Overrides the reasoning-effort level for this subagent: |
|
string |
none |
Set to |
|
string |
none |
A prompt auto-submitted as the agent’s first turn when it runs as the main session agent (via |
|
map |
none |
Experimental options. Its |
.claude/agents/code-reviewer.md---
name: code-reviewer
description: Reviews code for quality and best practices. Use proactively after code changes.
tools: Read, Glob, Grep, Bash
model: sonnet
permissionMode: default
color: cyan
---
You are a senior code reviewer. When invoked, analyze the changed files and provide specific, actionable
feedback on quality, security and best practices. Report findings only -- never edit files yourself.
Context isolation
Every subagent invocation starts with its own context window: its own system prompt (the agent’s Markdown
body plus environment details, not Claude Code’s own system prompt), a task message summarizing what the caller
wants done, CLAUDE.md at every level (skipped by the built-in Explore and Plan agents, and by any agent that sets
omitClaudeMd: true), a git status snapshot, and, if listed, its preloaded skills.
What it does not inherit is the calling conversation’s history, output-style settings, or auto memory. When
the subagent finishes, it returns a single result to the caller — the parent conversation never sees the
subagent’s own tool calls or intermediate reasoning, only the summary it chooses to report back. This is the
same isolation mechanism a context: fork skill uses (see
Skills) and the reason
Optimizing Skills & Agents treats it as a first-class optimization
technique: verbose tool output never has to flow back into the orchestrator’s own context.
Invocation is by natural language (Claude decides whether to delegate), by an explicit @agent-<name> mention
(which guarantees delegation), or session-wide via claude --agent <name> or an "agent" key in
.claude/settings.json:
> Use the code-reviewer subagent to look at my recent changes
> @agent-code-reviewer look at the auth changes
$ claude --agent code-reviewer
Copilot custom agents
.github/agents/*.agent.md
GitHub Copilot’s custom agents are Markdown files with the .agent.md extension ("agent profiles"), verified
against
GitHub’s
custom-agents-for-CLI docs:
| Location | Scope |
|---|---|
|
Project scope, checked into the repository |
|
Personal scope, across all projects — takes precedence over a same-named project agent |
Documented frontmatter keys: name (identifies the agent), description (its expertise and when Copilot
should reach for it), tools (an allowlist; defaults to every tool when omitted), and
include-custom-instructions (when true, the repository’s custom instructions also apply while the agent runs as
a subagent; an agent you select yourself already follows them). In the Copilot CLI you invoke a custom agent by
choosing it from /agent, by naming it in the prompt, by letting Copilot infer it from its description, or
programmatically:
$ copilot --agent security-auditor --prompt "Check /src/app/validator.go"
Here security-auditor is the agent file’s name without the .agent.md extension.
VS Code custom agents (formerly chat modes)
VS Code’s custom agents were previously called custom chat modes; the mechanism is unchanged, only the
terminology and the file extension moved — an existing .chatmode.md file should be renamed to .agent.md.
Verified against VS Code — Custom
agents:
| Location | Scope |
|---|---|
|
Workspace scope (the same files GitHub Copilot’s own agent surfaces read) |
|
User scope |
VS Code also reads .claude/agents/.md (workspace) and ~/.claude/agents/.md (user) as custom agents in the
Claude format, and treats any .md file in .github/agents/ as a custom agent, so a Claude Code subagent file and a Copilot/VS Code custom agent file can share the same
.claude/agents/ directory without duplication — the practical basis for
Copilot & Claude Code Equivalents.
VS Code’s frontmatter adds several fields beyond Copilot’s CLI schema: argument-hint, model (a single model
name, or a prioritized array), agents (the agents this one may call as subagents, * for all or [] for none;
the agent tool must then be in tools), user-invocable (whether it shows in the agent picker dropdown),
disable-model-invocation (stops other agents calling it as a subagent), target (vscode or github-copilot),
mcp-servers, handoffs, and hooks (local hook commands, marked Preview). The older infer key is
deprecated in favour of user-invocable and disable-model-invocation.
Handoffs
A handoff is a workflow button VS Code shows after a custom agent’s response completes, letting the person
switch straight into another named agent with a pre-filled prompt — for example, reviewing a plan and then
handing off to an implementation agent. Each entry in the handoffs array carries:
| Key | What it does |
|---|---|
|
The button’s display text. |
|
The target agent’s identifier to switch into. |
|
Text pre-filled into the next conversation with that agent. |
|
Optional; when |
|
Optional; the model to use when the handoff runs, as a qualified name such as |
See VS Code — Custom agents ("Handoffs").
.github/agents/reviewer.agent.md---
name: reviewer
description: Reviews a proposed change and reports findings without editing files. Use for a second opinion before implementation.
tools: ["search", "read"]
model: GPT-6 Sol
handoffs:
- label: "Implement the fix"
agent: implementer
prompt: "Apply the reviewer's findings above."
send: false
---
Review the changes in the current diff. Report findings by severity; do not edit any file.
In a VS Code custom agent, model: takes the model’s display name as it appears in the model picker (GPT-6 Sol),
not an API id such as gpt-6-sol; a handoff’s model: uses the same name qualified with its vendor
(GPT-6 Sol (copilot)). See
VS Code — Custom agents ("Header").
Examples from ai-catalog
iru-gate-runner.md (description abridged)iru-gate-runner is a narrow-purpose subagent restricted to exactly the tools it needs to dispatch to a named
skill and read its report, keeping the broader Edit/Write tool set out of reach entirely:
---
name: iru-gate-runner
description: Runs a single verification/quality-gate skill — tests (…), coverage (…), code-quality/lint (…), license-header checks, doc-comment audits (…), security scans (check-security), or a full project build — in an isolated context, optionally diffs the result against a baseline given in the prompt, and reports back only a compact, structured summary. Never dumps the raw generated report (…) into the caller's context. …
tools: Skill, Bash, Read
---
Its body’s "What you report back" section spells out exactly what a caller gets: a pass/fail run states only the failing names and reasons, never the full log of everything that passed; a coverage check reports only the requested percentage, not per-line detail. This is the context-isolation technique in its most concrete form — Optimizing Skills & Agents measures its effect. See Gate Runner for the full, generated page.
iru-isolated-skill-executor.mdiru-isolated-skill-executor runs a single named skill end to end with no memory of the caller’s prior
conversation, so an earlier exploration or planning transcript cannot bias the run:
---
name: iru-isolated-skill-executor
description: Runs a single named skill end-to-end in a completely fresh context — no memory of the caller's prior conversation — so an earlier exploration/planning transcript can't bias the run, while the caller keeps executing afterward (e.g. to open a PR once the delegated skill finishes). Reports back only a concise structured outcome (completed/blocked/hard-stop, files touched, and any named gate condition the caller asked about) — never a full step-by-step transcript. Used by `iru-issue` to hand off the entire `iru-code` skill run for a ticket.
tools: "*"
---
Unlike iru-gate-runner’s narrow allowlist, this agent’s `tools: "" grants everything. The "" wildcard isn’t
part of the documented tools schema (Claude Code resolves it to every tool today); omitting tools is the
documented way to inherit every tool. Everything is granted because its job is to
run an arbitrary named skill to completion, not to execute one fixed command — the isolation here is about a
fresh context, not a restricted tool set. The broad grant has a cost: whatever skill it is told to run gets
every tool the session allows, so it inherits the full risk of that skill’s instructions and is only as safe as the
permission rules around it. It reports back a short structured outcome (completed / blocked / hard-stop, files
touched, and any named gate condition), never a step-by-step transcript. See
Isolated Skill Executor for the full, generated page.
A generalised reviewer agent, in both tools
---
name: pr-reviewer
description: Reviews the current diff for correctness and style issues and reports findings without editing files. Use before opening a pull request instead of self-reviewing.
tools: Read, Grep, Glob, Bash
model: sonnet
permissionMode: default
color: yellow
---
Review the current diff. Report findings by severity (blocking / suggestion). Never edit a file yourself --
report only.
---
name: pr-reviewer
description: Reviews the current diff for correctness and style issues. Use before opening a pull request instead of self-reviewing.
tools: ["search", "read"]
model: GPT-6 Sol
user-invocable: true
---
Review the current diff. Report findings by severity (blocking / suggestion). Never edit a file yourself --
report only.
Both versions leave out the edit tools, because the point of a review agent is a report, not a fix. The Claude
Code version keeps Bash so it can run git diff, and Bash is not read-only: the "never edit" rule for shell
commands is only an instruction. To enforce it, drop Bash and keep Read, Grep and Glob. A deny rule such as
Bash(git commit *) in permissions.deny also works, but settings rules apply to the whole session — the main
conversation and every subagent — not to this one agent. To block commands only while the reviewer runs, put a
PreToolUse hook in its own frontmatter; Claude Code runs frontmatter hooks only while that subagent is active:
.claude/agents/pr-reviewer.md (frontmatter excerpt)tools: Read, Grep, Glob, Bash
hooks:
PreToolUse:
- matcher: "Bash"
hooks:
- type: command
command: "./scripts/block-git-writes.sh"
The script reads the hook’s JSON input on stdin and exits with code 2 to block a command such as git commit. See
Claude Code — Define hooks for subagents.
Writing Effective Skills covers the same discipline for skill descriptions.
Context isolation, visually
The main context never sees Work — only Result. That gap is the whole point: a subagent can read a
thousand-line test log or a raw SARIF report without any of it landing in the conversation the person is
reading.
Subagent vs. context: fork skill vs. agent team
All three isolate work in a separate context, but they differ in reusability, lifecycle and cost. Claude Code’s experimental agent teams feature is verified against Claude Code — Agent teams:
Subagent (.claude/agents/*.md) |
context: fork skill |
Agent team | |
|---|---|---|---|
Context |
Its own context window; result returns to the caller |
Its own context window (the skill runs as a forked subagent); result returns to the caller |
Its own context window; fully independent, no automatic return |
Communication |
Returns a result; named subagents can message each other |
Returns a result, exactly like a subagent |
Teammates message each other and the lead directly, each through its own mailbox |
Coordination |
The caller decides when to delegate and reads the result |
The skill’s own body decides to fork ( |
Self-coordination through messages plus a shared task list, for agents with the Task tools |
Reusability |
A named, reusable role ( |
Tied to one skill’s own steps; not a standalone reusable role |
Ad hoc, spawned by a natural-language request; roles can reuse a subagent definition |
Token cost |
Lower — one result summarized back |
Lower — one result summarized back |
Higher — each teammate is a full, separate session |
Best for |
A focused, reusable worker that reports back ( |
A single skill that needs isolation for one run (`iru-isolated-skill-executor’s job, but declared inline on a skill rather than as a caller-invoked agent) |
Parallel exploration, review or debugging that benefits from teammates challenging each other’s findings |
Agent teams are disabled by default and require setting CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1. Turning them on
also changes ordinary delegation: a subagent that Claude names while teams are enabled launches as a teammate, so a
team can form even when you didn’t ask for one.
.claude/settings.json{
"env": {
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
}
}
Reach for a subagent when you want a focused worker with a name you can reuse across sessions and skills.
Reach for context: fork when the isolation belongs to one skill’s own execution, not to a standalone role.
Reach for an agent team only when the work genuinely benefits from several independent perspectives talking to
each other — a competing-hypotheses debugging session or a multi-angle review — since it costs meaningfully
more tokens than either alternative. See Agents for how ai-catalog’s three
agents (iru-gate-runner, iru-isolated-skill-executor, iru-change-summarizer) apply this choice in
practice; the general theory of agent architectures — multi-agent topologies, planner/executor patterns and
tool-selection strategies beyond what any one tool’s docs describe — belongs to the planned AI Agents
sub-section, out of scope here.