Skip to content
agentscamp
Guide · Skills

Skills vs Agents vs Commands

How Claude Code's two extension mechanisms — subagents and skills — differ across three invocation patterns, with a decision table for choosing the right one.

10 min readAgentsCamp
Updated Jun 3, 2026

Claude Code really has two extension mechanisms, and they get conflated constantly because all three patterns are Markdown-based with YAML frontmatter (a skill is a folder whose SKILL.md carries the frontmatter, and can bundle supporting scripts and templates alongside it). But they answer three different questions. A subagent answers "who should Claude hand this off to?" A skill answers "what does Claude need to know to do this well?" A skill invoked as a slash command answers "what do I want to type to kick this off?" Pick the wrong one and you end up fighting the tool — a skill that never loads, an agent that never gets delegated to, a command nobody remembers exists.

NOTE

Custom commands have been merged into skills. .claude/commands/*.md files still work as a legacy path, but .claude/skills/<name>/SKILL.md is now canonical. Invoke any skill with /<name>; set disable-model-invocation: true to prevent Claude from auto-loading it. So when this guide talks about a "slash command," it means a skill you trigger by name rather than a separate file type.

This guide draws the lines clearly, gives you a decision table, and walks through real "I want to..." cases so you reach for the right one on the first try.

Two mechanisms, three invocation patterns

Everything lives under .claude/ (project-local) or ~/.claude/ (personal, follows you everywhere). There are two real mechanisms — subagents and skills — and the third "slash command" pattern is just a skill you trigger by name.

.claude/
├── agents/                  # subagents — isolated delegates Claude calls on its own
│   └── code-reviewer.md
├── skills/                  # skills — auto-loaded knowledge OR user-invoked /commands
│   ├── changelog/SKILL.md   # auto-loads when relevant
│   └── ship/SKILL.md        # disable-model-invocation: true → only fires on /ship
└── commands/                # legacy slash commands — still work, but skills are canonical
    └── ship.md

The crucial difference is who pulls the trigger and where the work runs.

  • A subagent is a delegate. Claude decides, mid-task, that a chunk of work belongs to a specialist and hands it off. The subagent runs in its own context window with its own toolset and returns a summary. You don't invoke it directly; Claude routes to it based on its description.
  • A skill is reusable expertise. It sits dormant until Claude notices the current task matches it, then loads its instructions into the main context to inform how Claude does the work. It's knowledge-on-demand, not a separate worker.
  • A skill invoked as a slash command is that same mechanism, flipped to manual. Typing /ship expands a skill into the conversation as if you'd pasted it. It runs in your main context. The only difference from an auto-loaded skill is disable-model-invocation: true, which stops Claude from firing it on its own — so the trigger is always you.

NOTE

"Skill" overloads two meanings. There are first-party Claude Code skills and Agent Skills (SKILL.md packages with optional scripts and resources). In both cases the defining trait is the same: Claude loads them on demand when relevant, rather than you invoking them or Claude spawning them as a separate worker.

The decision table

Who invokes itOwn context windowRestricted toolsTypical use
SubagentClaude (auto-delegated)Yes — isolatedYes (tools: field)Hand off a self-contained job: review a diff, investigate a failing test, audit a file
SkillClaude (loaded on match)No (by default) — runs in main contextOptional (allowed-tools:)Reusable procedure or domain knowledge: write a changelog, follow a house migration recipe
Slash command (a skill)You (typed by name)No (by default) — runs in main contextOptional (allowed-tools:)A skill you run often and want by keystroke: /ship, /review-pr, /scaffold

Read the table top to bottom on a single axis at a time. The invocation column is the fastest filter: if you want to be the one to press the button, it's a command. The context column is the next: only subagents get isolation, which is what makes them the right tool when a task would otherwise flood your main window with noise.

When to reach for a subagent

Choose a subagent when the work is a self-contained job with a noisy middle and a clean summary — and you want Claude to decide when to run it.

The isolated context window is the whole point. A subagent that runs the test suite can churn through hundreds of lines of failing output, then hand back just "three tests fail, all from the same null-check in parseDate()." Your main thread never sees the logs. That's also why subagents are right for parallel fan-out: Claude can dispatch several at once without their transcripts colliding.

---
name: test-runner
description: Runs the test suite and summarizes failures with root causes. Use after code changes or when a test is reported failing.
model: sonnet
tools: Read, Grep, Glob, Bash
---
 
You run the project's tests, read failing output, and report each
failure as: file, failing assertion, and most likely cause.
Do not fix code unless explicitly asked.

The description is the routing signal — it's how Claude decides to delegate, so write it in terms of when to use this agent with concrete triggers. Scope tools to the minimum the job needs; a read-only reviewer physically cannot edit your code.

TIP

If a task would dump a lot of intermediate output you don't care about — build logs, grep sweeps, large file scans — that's the tell for a subagent. The isolation keeps your main context lean for the work that matters.

When to reach for a skill

Choose a skill when there's a repeatable procedure or body of knowledge that should shape how Claude works, but only when the task actually calls for it.

The defining trait is on-demand loading. A skill's instructions don't sit in your context burning tokens every session — Claude pulls them in only when the current task matches the skill's description. That makes skills the right home for "the way we do X here" recipes: generating a release changelog, scaffolding a component to house conventions, following a specific data-migration playbook.

---
name: changelog
description: Generate a release changelog from merged PRs since the last tag, grouped by type, following our house format.
allowed-tools: Bash, Read
---
 
When asked to write a changelog:
1. Find the last release tag with `git describe --tags --abbrev=0`.
2. List merged PRs since that tag.
3. Group entries under Added / Changed / Fixed and link each PR.

A skill differs from a subagent in two ways that decide between them: it runs in your main context (no isolation — Claude uses the loaded steps directly), and it's knowledge, not a worker. If you don't need a separate context window and you're really just teaching Claude a procedure, it's a skill.

A skill can opt into isolation with context: fork in its frontmatter, which executes it in a forked subagent — useful when a skill's work would otherwise flood your main thread. That blurs the line a little, but the default and common case is main-context execution; reach for a full subagent when isolation is the point, not an afterthought.

NOTE

Skills can ship more than text — an Agent Skill can bundle scripts and resource files alongside SKILL.md. Reach for that when the procedure needs deterministic helpers (a formatter, a generator) rather than instructions alone.

When to reach for a slash command

Choose this pattern — a skill you only ever trigger by name — when you want to be the one who pulls the trigger, and it's a prompt you'd otherwise retype.

There's no autonomy and no isolation here — it's a saved prompt that happens to live in a skill. Typing /ship drops the skill's contents into the conversation. That's exactly what you want for deliberate, you-initiated workflows: the multi-step sequence you run before every PR, the scaffolding prompt you fire at the start of a feature, the review checklist you want on demand rather than whenever Claude guesses you want it. The one frontmatter flag that makes it user-only is disable-model-invocation: true.

---
description: Open a PR — summarize the diff, draft a title and body, push and create it.
argument-hint: [base-branch]
allowed-tools: Bash, Read
disable-model-invocation: true
---
 
1. Run `git diff $0...HEAD` and summarize the changes.
2. Draft a PR title (imperative) and a body with a Summary and Test plan.
3. Push the branch and open the PR with `gh pr create`.

Skills accept arguments ($0 for the first argument, $1 for the second, or $ARGUMENTS for all arguments as a single string) and an argument-hint, which makes them feel like CLI subcommands for your repo. Note the substitution is 0-indexed: $0 is the first argument, so a single-argument argument-hint: [base-branch] lands in $0, not $1. The decision between a user-triggered command and an auto-loaded skill comes down to invocation: if you want to type the name yourself, set disable-model-invocation: true; if you want Claude to reach for it automatically when the task fits, leave it off.

NOTE

Add disable-model-invocation: true to any skill you only want to run on your explicit trigger — otherwise Claude may auto-invoke it when it judges the task relevant, and the "saved prompt I fire myself" behavior won't hold.

TIP

Same procedure, different trigger? You can have both. Encode the steps once as a skill so Claude applies them when relevant, and add a thin slash command that says "run the changelog skill now" for when you want to force it.

Worked examples: "I want to..."

"I want Claude to review every diff for bugs before I merge — without me asking each time." That's a subagent. The work is a self-contained job, it benefits from isolation (the review reasoning stays out of your main thread), and you want Claude to delegate to it automatically when a diff appears. Give it a sharp description with trigger examples and a read-only toolset.

"I want changelogs to always follow our exact house format, whenever one gets written." That's a skill. It's a reusable procedure that should shape how Claude works when the task comes up — no separate context needed, and you don't want to type a command every time. Claude loads it on demand whenever a changelog is in play.

"I want to type one thing before every PR that summarizes the diff, drafts the description, and opens the PR." That's a slash command — i.e. a skill with disable-model-invocation: true. You are the trigger, it runs in your main context, and it's a fixed prompt you fire repeatedly. /create-pr [base] and you're done.

WARNING

The classic mistake is building a subagent for something you always invoke yourself. If you're the one deciding when it runs every single time, the isolation buys you nothing and the auto-delegation never fires — you wanted a slash command. Conversely, don't cram a noisy, self-contained investigation into a command; without its own context window it floods your main thread.

Putting it together

Map the request to the question it answers. Who pulls the trigger — you (command) or Claude (agent/skill)? Does it need its own context window — yes (agent) or no (skill/command)? Is it knowledge that shapes the work, or a worker that goes off and does the work — skill or agent?

The three compose well. A slash command can lay out a sequence that delegates a noisy step to a subagent and leans on a skill for house conventions along the way. Start with the one that fixes your most repeated friction — usually a slash command for a workflow you retype, or a subagent for a task that keeps drowning your context — then layer the others as your setup matures.

Related