Skills and Subagents
The two ways to extend Claude Code that people most often confuse. A skill is knowledge loaded when it is needed; a subagent is work handed to a separate context. Which to reach for, and every frontmatter field.
Chapter 10 | Skills and Subagents Written for: anyone whose CLAUDE.md has grown too long, who is starting to wonder what should be moved out of it and where
The distinction to hold on to before anything else
A skill is knowledge or a procedure, loaded when the moment for it arrives. A subagent is work handed to another context, which sends back a result.
| Skill | Subagent | |
|---|---|---|
| Lives at | .claude/skills/name/SKILL.md | .claude/agents/name.md |
| Required fields | None (description is recommended) | name and description |
| Invoked by | /name, or Claude choosing it from the description | @name, or Claude delegating |
| Context | Stays in the current conversation | Separate; it cannot see your conversation |
| Suits | Repeated procedures, reference knowledge | Work that parallelises, work you do not want filling the main context |
| Portable elsewhere? | Yes, under the Agent Skills spec | No; Claude Code only |
The quick test: if you want Claude to know something, write a skill. If you want Claude to go and do something and come back, use a subagent.
10.1 Skills
Where they live
| Location | Path | Applies to |
|---|---|---|
| Enterprise | Via managed settings | Everyone in your organisation |
| Personal | ~/.claude/skills/<name>/SKILL.md | All your projects |
| Project | .claude/skills/<name>/SKILL.md | This project only |
| Plugin | <plugin>/skills/<name>/SKILL.md | Wherever that plugin is enabled |
When names collide the order is Enterprise beats Personal beats Project.
The smallest thing that actually works
---
description: Review a PR against the team checklist. Use when asked to review a PR.
argument-hint: [pr-number]
allowed-tools: Read, Grep, Bash(gh pr view *)
---
Review PR number $ARGUMENTS in this order:
1. Check the diff size. Past 400 lines, say up front that it is too large to review properly.
2. Check whether the tests were written from the spec or from the implementation.
3. Check whether any file outside the declared scope was touched.
Every frontmatter field
No field is required, but description is recommended, because Claude uses it to decide when to reach for the skill. Omit it and the first paragraph of the body is used instead.
| Field | What it does |
|---|---|
name | The display name in listings. Defaults to the directory name |
description | What it does and when to use it. Put the main case first — the combined description and when_to_use text is truncated at 1,536 characters in the skill listing |
when_to_use | Extra context on when to invoke, such as trigger phrases. Counts toward the same 1,536-character cap |
argument-hint | An autocomplete hint, such as [issue-number] |
arguments | Named positional arguments, for $name substitution in the body |
disable-model-invocation | true stops Claude picking it up on its own; only /name triggers it |
user-invocable | false hides it from the / menu so only Claude can invoke it |
allowed-tools | Tools usable without asking permission, only during the turn that invoked the skill. The grant clears with your next message |
disallowed-tools | Tools removed from Claude’s pool while this skill is active |
model | The model to use while the skill is active; inherit keeps the current one. Not saved to settings — the next turn reverts |
effort | Effort level: low, medium, high, xhigh, max |
context | Set to fork to run in a subagent with its own context |
agent | Which subagent type to use when context: fork is set |
background | Only with context: fork. false waits for the result in the same turn. Default true |
hooks | Hooks registered on invocation, which keep running for the rest of the session |
paths | Glob patterns limiting which files activate the skill |
shell | Shell for inline commands: bash (default) or powershell |
metadata | A free-form YAML map for your own tooling; Claude Code does not act on its contents |
license | The skill’s licence, per the Agent Skills spec. Accepted but not acted on |
compatibility | Environment requirements, up to 500 characters |
To use a skill outside Claude Code — uploaded to claude.ai, or through the Skills API — only six fields are allowed:
name,description,license,compatibility,metadataandallowed-tools. Any other field makes packaging fail.
Substitutions available in the body
| Variable | What it gives you |
|---|---|
$ARGUMENTS | Everything passed in |
$ARGUMENTS[N] / $N | One argument by position, from 0 |
$name | An argument declared in the arguments field |
${CLAUDE_SESSION_ID} | The current session ID |
${CLAUDE_EFFORT} | The effort level in force |
${CLAUDE_SKILL_DIR} | The directory holding SKILL.md. Use it to reference bundled scripts regardless of the working directory |
${CLAUDE_PROJECT_DIR} | The project root, the same path hooks receive |
${CLAUDE_PLUGIN_ROOT} | The plugin’s install directory; plugin skills only |
${CLAUDE_PLUGIN_DATA} | The plugin’s persistent data directory, surviving updates |
${CLAUDE_SKILL_DIR} is the most valuable in practice, because it lets a skill carry its own scripts:
allowed-tools: Bash(${CLAUDE_SKILL_DIR}/scripts/render.sh *)
How to structure a skill once it grows
my-skill/
├── SKILL.md ← the overview; keep it under 500 lines
├── reference.md ← loaded when referenced
├── examples.md
└── scripts/
└── helper.py ← executed, not loaded into context
The principle is to make SKILL.md a table of contents rather than the whole textbook. Split the detail into files and link to them; Claude reads them when it genuinely needs them. This is what progressive disclosure means, and it is why a skill costs less context than cramming everything into CLAUDE.md.
/skill-doctor — finding skills that cost context and earn nothing
Type /skill-doctor for a report on how many tokens each skill costs, how often it is invoked, which have never been invoked at all, which plugins have gone unused, and where to turn things off.
Reach for it when sessions start slowly or context fills faster than it should.
10.2 Subagents
The shape of the file
---
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.
name must be lowercase and may contain hyphens, but no colons — it doubles as agent_type in hooks.
Where they live, in priority order
| Location | Scope |
|---|---|
| Managed settings | The whole organisation (highest) |
The --agents flag at launch | That session only |
.claude/agents/ | This project; commit it to the repo |
~/.claude/agents/ | All your projects |
A plugin’s agents/ | Wherever the plugin is enabled (lowest) |
Invoking one
Use the code-reviewer agent to look at my recent changes
Claude delegates on its own based on description. To guarantee a particular agent is used, @-mention it by name.
You can also make one the session default:
claude --agent code-reviewer
What a subagent sees and does not see — get this right
This is the single most common source of disappointment with subagents.
What it receives: its own system prompt (not Claude Code’s), the delegation message Claude wrote for it, CLAUDE.md files at every level, a git status snapshot, and any skills preloaded through the skills field.
What it does not receive: your conversation history, along with output style settings, auto memory and skills invoked earlier.
Which means: if you have been talking to Claude for ten rounds and then say “hand this to a subagent”, the subagent knows nothing about those ten rounds. It knows only what Claude chose to summarise for it. If it needs to know more, write it to a file.
The exception is a fork, which inherits everything — conversation history, system prompt, tools and model. The benefit of a fork is that only its final result comes back, so the main conversation stays uncluttered.
The frontmatter fields you will use
| Field | What it does |
|---|---|
name (required) | The identifier; lowercase, no colons |
description (required) | When Claude should delegate to this one |
tools | The tools it may use; inherits everything if omitted |
disallowedTools | Tools to remove |
model | sonnet, opus, haiku, fable, a full ID, or inherit to take the parent’s |
permissionMode | This agent’s permission mode |
maxTurns | Maximum turns before stopping; the output is marked partial |
skills | Skills to preload into its context |
hooks | Lifecycle hooks for this agent |
isolation | worktree to give it its own git worktree |
effort | Effort level |
color | Display colour in the task list |
Nesting and concurrency
By default subagents nest up to three layers below the main conversation, and up to 20 run concurrently. Both are adjustable through CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH and CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS.
To stop an agent spawning further agents, leave Agent out of its tools:
---
name: read-only-agent
tools: Read, Grep, Glob
---
Or restrict which types it may spawn:
tools: Agent(worker, researcher), Read, Bash
How a subagent’s model is chosen
The first match wins:
- A
modelpassed at the moment of invocation - The
modelfield in the subagent’s definition - The
CLAUDE_CODE_SUBAGENT_MODELenvironment variable - The main conversation’s model
The built-in subagents
| Name | Tools | Purpose |
|---|---|---|
| Explore | Read-only | Fast codebase search and analysis |
| Plan | Read-only | Research ahead of plan mode |
| General-purpose | Everything available | Complex multi-step work |
Disable them with a deny rule:
{ "permissions": { "deny": ["Agent(Explore)", "Agent(Plan)"] } }
10.3 Traps encountered in practice
Write description for Claude to read, not for a human to admire. Both skills and subagents are chosen from that field. “A helpful utility” will never get picked. Say when to use it, in the words a user would actually type.
Do not expect a subagent to know what you have been discussing. If the work depends on accumulated context, use a skill with context: fork, or write the context to a file first.
A skill’s allowed-tools expires sooner than you think. The grant lasts only for the turn that invoked it; your next message ends it.
A skill’s hooks do not expire. Unlike allowed-tools, hooks registered on invocation stay for the rest of the session. Be careful writing a skill that installs heavy ones.
A skill nobody uses still costs context, because the whole skill listing is put in front of Claude. That is what /skill-doctor is for.
Glossary for this chapter
| Term | Meaning |
|---|---|
| Skill | A procedure or body of knowledge in a SKILL.md, loaded when needed |
| Subagent | A separate context that takes on work and returns a result |
| Fork | A subagent inheriting the main conversation’s full context |
| Progressive disclosure | Keeping SKILL.md a table of contents and loading detail on demand |
${CLAUDE_SKILL_DIR} | The skill’s own directory, for referencing scripts bundled with it |