Claude Code subagents and skills
Two related but distinct primitives let you extend Claude Code without modifying the core engine: subagents are specialized AI workers that handle focused subtasks in their own context window with their own system prompt and tool set; skills are reusable markdown procedures (formerly slash commands) that Claude can invoke when relevant or that you can call with /skill-name. They compose: a skill can be configured to run in a forked subagent (context: fork), and a subagent can preload skills as background knowledge (skills: [...]).
See also
- claude-code-cli — the
--agent/--agentsflags +claude agentscommand - claude-code-hooks-deep — hooks scoped to a specific subagent or skill
- claude-agent-sdk — same agent + skill model exposed programmatically
- agents-and-orchestration-patterns — broader orchestration playbook
- prompt-engineering-agent-systems — vendor-neutral background
1. Subagents
Per code.claude.com/docs/en/subagents. A subagent is a specialized AI worker with:
- Own context window (separate from main conversation)
- Own system prompt
- Specific tool access (subset of available tools)
- Independent permission mode
- Optionally: persistent memory, own model, own hooks
When Claude encounters a task matching a subagent’s description, it delegates via the Agent tool (formerly Task tool); subagent works independently, returns a summary.
Why use them:
- Preserve context — exploration / log analysis happens in subagent context, main thread sees only summary
- Enforce constraints — read-only research subagents can’t write
- Reuse configs — user-level subagents work across projects
- Specialize — focused system prompts for specific domains
- Control cost — route to Haiku for cheap tasks, Opus for hard tasks
1.1 Built-in subagents
| Name | Model | Tools | Purpose |
|---|---|---|---|
| Explore | Haiku (fast) | Read-only (denied Write/Edit) | File discovery, code search, codebase exploration. Skips CLAUDE.md and parent git status for speed. |
| Plan | Inherits | Read-only | Used in plan mode to gather context. Same skip. |
| General-purpose | Inherits | All | Multi-step tasks needing both exploration + action |
| statusline-setup | Sonnet | (specific) | Auto-invoked when you run /statusline |
| claude-code-guide | Haiku | (specific) | Auto-invoked when you ask about Claude Code features |
1.2 Subagent scopes (highest priority first)
| Location | Scope | Priority |
|---|---|---|
| Managed settings | Org-wide | 1 (highest) |
--agents CLI flag | Session | 2 |
.claude/agents/<name>.md | Project | 3 |
~/.claude/agents/<name>.md | User (all projects) | 4 |
<plugin>/agents/<name>.md | Where plugin enabled | 5 |
Plugins use namespacing: <plugin-name>:<agent-name> (or <plugin>:<subfolder>:<agent> for nested). No conflicts with other scopes.
.claude/agents/ is walked recursively. Project subagents are discovered by walking up from cwd. --add-dir does NOT scan for subagents (file access only).
Plugin subagents ignore hooks, mcpServers, and permissionMode frontmatter for security.
1.3 Subagent file format
.claude/agents/code-reviewer.md:
---
name: code-reviewer
description: Reviews code for quality and best practices
tools: Read, Glob, Grep
model: sonnet
color: blue
---
You are a code reviewer. When invoked, analyze the code and provide
specific, actionable feedback on quality, security, and best practices.Body becomes the subagent’s system prompt. Subagent receives only this prompt + basic environment details (cwd, etc.) — not the main Claude Code system prompt.
1.4 Supported frontmatter fields
| Field | Required | Description |
|---|---|---|
name | Yes | Unique ID, lowercase + hyphens. Hooks see this as agent_type. Filename doesn’t have to match. |
description | Yes | When Claude should delegate. The router uses this. |
tools | No | Allowlist (e.g. Read, Glob, Grep). Inherits all if omitted. |
disallowedTools | No | Denylist. Applied first, then tools resolved. |
model | No | sonnet, opus, haiku, full ID, or inherit (default). |
permissionMode | No | default, acceptEdits, auto, dontAsk, bypassPermissions, plan. Plugin-ignored. |
maxTurns | No | Cap agentic turns before stopping. |
skills | No | Skills preloaded into subagent context at startup (full content, not just description). |
mcpServers | No | MCP servers — by name (reuse session) or inline. Plugin-ignored. |
hooks | No | Lifecycle hooks scoped to this subagent. Plugin-ignored. |
memory | No | user, project, or local — enables persistent memory dir. |
background | No | true to always run as background task. |
effort | No | low/medium/high/xhigh/max for this subagent. |
isolation | No | worktree — run in temp git worktree branched from default branch. Auto-cleaned if no changes. |
color | No | red, blue, green, yellow, purple, orange, pink, cyan. UI hint. |
initialPrompt | No | Auto-submitted as first user turn when run via --agent or agent setting. |
1.5 Model resolution order
CLAUDE_CODE_SUBAGENT_MODELenv var- Per-invocation
modelparameter (when Claude invokes the subagent) - Subagent definition’s
modelfrontmatter - Main conversation’s model
1.6 Restricting which subagents can spawn other subagents
When an agent runs as main thread via claude --agent, it can spawn subagents using the Agent tool. Restrict with Agent(name1, name2) syntax in tools:
tools: Agent(worker, researcher), Read, BashThis is an allowlist. Omitting Agent entirely disables subagent spawning. Bare Agent (no parens) allows all.
Subagents themselves cannot spawn subagents — no nesting.
(Task was renamed to Agent in v2.1.63; Task(...) still works as an alias.)
1.7 Inline MCP servers per subagent
mcpServers:
- playwright:
type: stdio
command: npx
args: ["-y", "@playwright/mcp@latest"]
- github # reference an already-configured serverDefining inline here keeps the MCP tools out of the parent context entirely — useful for keeping context lean.
1.8 What loads at startup (per docs)
Every subagent receives:
- Its own frontmatter
prompt(markdown body) - Basic environment details (cwd)
- Plus, unless it’s
ExploreorPlan: CLAUDE.md + parent git status
The Explore + Plan agents deliberately skip CLAUDE.md and git status to keep their context small.
1.9 Forked subagents (context: fork on skills)
A skill can fork into a subagent. See §2.5 below.
1.10 Persistent memory (memory: field)
memory: user # `user`, `project`, or `local`Enables a persistent memory directory at ~/.claude/agent-memory/<name>/ (user scope) or .claude/agent-memory/<name>/ (project / local). Subagent accumulates insights across conversations.
1.11 Dispatching subagents
Three ways:
- Implicit — Claude reads descriptions, decides when to delegate
- Explicit by name — “Use the code-reviewer agent to …”
- Via
--agent <name>at session start — agent runs as the main thread - Via SDK
Task/Agenttool — programmatic
2. Skills
Per code.claude.com/docs/en/skills. A skill is a markdown file with YAML frontmatter that Claude can invoke automatically (when description matches) or you can invoke explicitly via /skill-name.
Skills follow the Agent Skills open standard. Claude Code extends it with invocation control, subagent execution, and dynamic shell injection.
Custom commands have been merged into skills. A file at .claude/commands/deploy.md and .claude/skills/deploy/SKILL.md both create /deploy with identical semantics. Skills add: directory for supporting files, frontmatter to control invocation, model-invocation.
2.1 Bundled skills (ship with Claude Code)
Listed in / menu:
| Skill | Purpose |
|---|---|
/run | Launch and drive your app to verify a change works |
/verify | Build + run app to confirm change without tests |
/run-skill-generator | Generate per-project /run and /verify skills |
/code-review | Code review skill |
/security-review | Security review |
/debug | Debugging skill |
/batch | Batch operations |
/loop | Repeat a prompt or command on an interval |
/claude-api | Build / migrate Claude API code |
Plus the built-in commands /help, /clear, /compact, etc. listed in claude-code-cli.
2.2 Skill scopes
| Location | Scope | Path |
|---|---|---|
| Managed | Org-wide | Per managed settings |
| Personal | All your projects | ~/.claude/skills/<name>/SKILL.md |
| Project | This project | .claude/skills/<name>/SKILL.md |
| Plugin | Where plugin enabled | <plugin>/skills/<name>/SKILL.md (namespaced <plugin>:<name>) |
Precedence: enterprise > personal > project. Skills override identically-named commands.
Live change detection: editing ~/.claude/skills/ or project .claude/skills/ is picked up within the session. Creating a top-level skills dir that didn’t exist at session start requires restart.
Discovery is recursive — .claude/skills/ walks up from cwd, plus nested ones when working in subdirectories of --add-dir’d paths (handy for monorepos).
2.3 Skill file structure
my-skill/
├── SKILL.md # Main instructions (required)
├── reference.md # Detailed reference loaded on demand
├── examples.md
└── scripts/
└── helper.py # Executable script
SKILL.md:
---
name: my-skill
description: What this skill does
disable-model-invocation: true
allowed-tools: Read Grep
---
Your skill instructions here...2.4 Frontmatter
| Field | Description |
|---|---|
name | Display name. Defaults to directory name. Lowercase + hyphens, ≤64 chars. |
description | When to use the skill. Claude uses this to decide automatic invocation. Combined description + when_to_use truncated at 1,536 chars in skill listing. |
when_to_use | Extra trigger phrases. Appended to description. |
argument-hint | Autocomplete hint, e.g. [issue-number]. |
arguments | Named positional args for $name substitution (space-sep string or YAML list). |
disable-model-invocation | true → only user can invoke via /name. Also prevents preloading into subagents. |
user-invocable | false → hide from / menu (Claude can still invoke). |
allowed-tools | Tools auto-approved while skill is active. |
model | Override model for this skill’s turn. Or inherit. |
effort | Override effort level. |
context | fork → run in forked subagent. |
agent | Which subagent type when context: fork (default general-purpose). |
hooks | Hooks scoped to this skill’s lifecycle. |
paths | Glob patterns — auto-load only when working with matching files. |
shell | bash (default) or powershell for !backtick` injection. |
2.5 String substitution
In the skill body:
| Variable | Resolves to |
|---|---|
$ARGUMENTS | Full argument string |
$ARGUMENTS[N] / $N | Specific argument by 0-based index |
$name | Named arg from arguments: |
${CLAUDE_SESSION_ID} | Current session UUID |
${CLAUDE_EFFORT} | low/medium/high/xhigh/max |
${CLAUDE_SKILL_DIR} | Directory containing this SKILL.md |
Indexed arguments use shell-style quoting: /my-skill "hello world" second → $0 = "hello world", $1 = "second". $ARGUMENTS always = full unquoted typed string.
2.6 Dynamic context injection (!backtick`)
---
name: pr-summary
description: Summarize a PR
context: fork
agent: Explore
allowed-tools: Bash(gh *)
---
## PR diff
!`gh pr diff`
## Comments
!`gh pr view --comments`
## Your task
Summarize.The !gh pr diff lines execute before the skill content is sent to Claude; output replaces the placeholder. Claude sees the rendered prompt with live data inline.
Multi-line form (fenced block opened with ```!):
## Environment
```!
node --version
npm --version
git status --short
```Substitution runs once — command output is plain text, not re-scanned for further ! placeholders.
Disable globally with disableSkillShellExecution: true in settings (replaces commands with [shell command execution disabled by policy]). Bundled and managed skills exempt.
2.7 Forking into a subagent
context: fork makes the skill run in an isolated subagent context. The skill body becomes the prompt; agent field picks which subagent type (default general-purpose).
---
name: deep-research
description: Research a topic thoroughly
context: fork
agent: Explore
---
Research $ARGUMENTS thoroughly:
1. Find relevant files
2. Read and analyze
3. Summarize with file referencesThe forked subagent inherits the agent type’s tools and model. Built-in Explore + Plan skip CLAUDE.md to keep small. Returns a summary to the main thread.
2.8 Pre-approving tools
allowed-tools grants permissions while skill is active:
---
name: commit
description: Stage and commit current changes
disable-model-invocation: true
allowed-tools: Bash(git add *) Bash(git commit *) Bash(git status *)
---Claude can run those without prompting. Doesn’t restrict — your permissions.deny rules still apply.
2.9 Controlling invocation
| Frontmatter | You invoke? | Claude invokes? | When loaded into context |
|---|---|---|---|
| (default) | Yes | Yes | Description always; full skill on invoke |
disable-model-invocation: true | Yes | No | Not loaded; full skill on user invoke |
user-invocable: false | No | Yes | Description always; full skill on Claude invoke |
2.10 Skill content lifecycle
When invoked, the rendered SKILL.md enters the conversation as a single message and stays for the session. Claude does NOT re-read on later turns — write standing instructions, not one-time steps.
Auto-compaction: re-attaches most recent invocation of each skill after summary (first 5,000 tokens). Re-attached skills share 25,000 token budget total — older skills can be dropped.
Skill description budget: defaults to 1 % of model’s context window. When overflowing, descriptions for least-used skills are dropped first. Tune with skillListingBudgetFraction setting (e.g. 0.02 = 2%) or SLASH_COMMAND_TOOL_CHAR_BUDGET env var. Per-skill max description: 1,536 chars (configurable via maxSkillDescriptionChars).
2.11 skillOverrides setting
Control visibility from settings without editing the SKILL.md:
{
"skillOverrides": {
"legacy-context": "name-only", // hide description
"deploy": "off", // hidden everywhere
"experimental": "user-invocable-only" // only via /
}
}Values: on, name-only, user-invocable-only, off. Set via /skills menu (Space cycles state, Enter saves to .claude/settings.local.json). Plugin skills not affected.
2.12 Restricting Claude’s skill access
Three layers:
- Disable all skills:
Skillin permissions.deny - Allowlist / denylist specific:
Skill(commit),Skill(review-pr *),Skill(deploy *)in permissions - Per-skill:
disable-model-invocation: truein frontmatter
A few built-in commands also flow through Skill tool: /init, /review, /security-review. Others like /compact do not.
3. The Task / Agent tool
In v2.1.63 the Task tool was renamed to Agent. Task(...) still works as alias. The tool’s responsibility: dispatch a subagent. Input shape:
{
"subagent_type": "general-purpose",
"description": "Brief 1-line task description",
"prompt": "Full task prompt for the subagent"
}Claude invokes this when delegating. Each subagent dispatch is a fresh context — subagent gets only its own system prompt + the prompt field, not the main conversation.
4. Composing subagents + skills
The two work in two directions:
| Approach | System prompt | Task | Also loads |
|---|---|---|---|
Skill with context: fork | From agent type | SKILL.md content | CLAUDE.md (unless Explore/Plan agent) |
Subagent with skills: field | Subagent’s markdown body | Claude’s delegation message | Preloaded skill content + CLAUDE.md |
Pattern: skill = task, subagent = worker config. A pr-review skill says “review this PR thoroughly using gh CLI”; a senior-reviewer subagent says “you are a senior reviewer with 20 years of experience, here are the tools you can use”. Combine.
5. Worked example: a code-review skill that forks into a senior-reviewer subagent
.claude/agents/senior-reviewer.md:
---
name: senior-reviewer
description: Senior code reviewer — looks for security, performance, design issues
tools: Read, Glob, Grep, Bash(gh *)
model: opus
color: red
---
You are a senior software engineer with 20 years of production experience...
[detailed system prompt].claude/skills/review-pr/SKILL.md:
---
description: Reviews a PR using the senior-reviewer agent
context: fork
agent: senior-reviewer
argument-hint: [pr-number]
allowed-tools: Bash(gh *)
---
# PR review
## Diff
```!
gh pr diff $1
```
## Description
```!
gh pr view $1 --json title,body,labels
```
## Task
Review the PR above. Cover:
1. Security issues
2. Performance hot paths
3. Design / architecture concerns
4. Test coverage gaps
Return a structured markdown report with severity per issue.Invocation: /review-pr 4521 → Claude renders the skill (executing gh pr diff 4521 first), forks into the senior-reviewer subagent with the rendered content as the prompt, subagent reviews, returns report.
6. Common gotchas
- Skill description too long — silently truncated at 1,536 chars; key keywords for routing get dropped. Put key use case first.
- Skill budget overflow — 1 % context budget; many skills → least-used dropped. Run
/doctor. - Subagent inherits no system prompt context — only body + env. Don’t assume CLAUDE.md is loaded (Explore/Plan skip; SDK respects setting_sources).
context: forkwith no task — subagent gets the body as prompt, but if body is just “here are conventions…”, subagent has nothing to do.- Plugin subagents drop
hooks,mcpServers,permissionMode— security. - Subagents can’t spawn subagents — no nesting. Use background sessions or agent teams for parallel work.
- Skill body stays in context for session — wasted tokens compound. Keep body lean; move detail to
reference.md/examples.md. Skill.mdis not re-read mid-session — if you change it, restart (or it’ll keep old content until next invocation).disable-model-invocation: trueremoves from Claude’s context — Claude can’t even know the skill exists. Use sparingly.- Invocation precedence: project subagent named
code-reviewershadows user-levelcode-reviewer. Watch out when sharing across projects.