Explainer
Skills vs plugins vs MCP vs subagents in Claude Code: how to choose
Claude Code has six extension points, and they are not six siblings. Three of them are genuinely different kinds of thing: a skill is prose the model loads when it matches, a subagent is a second context window, an MCP server is a process that speaks a wire protocol. Plugins and marketplaces are not a fourth kind — they are packaging and distribution for the first three. And slash commands have stopped being a separate mechanism at all: Anthropic's own docs now say custom commands have been merged into skills.
That last sentence is why "should this be a skill or a slash command?" gets mushy answers. Half the
write-ups on the internet are describing a taxonomy that no longer exists. Everything below was
checked against Claude Code 2.1.221 and the current reference pages at
code.claude.com/docs in August 2026, with the CLI commands run on a real machine.
Where the docs and the folklore disagree, the folklore is called out.
The decision table
Start here. If you know what you are trying to accomplish, this settles it in one row.
| You want to… | Reach for | Not, because |
|---|---|---|
| Teach the agent a procedure — a checklist, a house convention, a multi-step workflow | Skill | An MCP server adds capability, not behaviour. A subagent would run the procedure somewhere you can't see. |
| Trigger that procedure yourself, by name, on demand | Skill (or a legacy .claude/commands/*.md file) | Same mechanism now. Add disable-model-invocation: true if only you should start it. |
| Reach a system Claude can't reach — an API, a database, a SaaS product | MCP server | A skill has no credentials and no code path of its own; it can only tell Claude to use tools it already has. |
| Keep a long, noisy sub-task out of your main conversation | Subagent | A skill's body lands in your context and stays there for the session. |
| Make something happen on a lifecycle event, whether or not the model cooperates | Hook | Skills and MCP tools are model-invoked. A hook is not — it fires deterministically. |
| Ship a bundle of the above to your team, versioned | Plugin | Loose files in .claude/ can't be versioned, namespaced or installed. |
| Let people discover and install that bundle | Marketplace | A marketplace is a catalogue file. It holds no behaviour of its own. |
What each one actually is
| Mechanism | Lives at | Who starts it | Runs code? |
|---|---|---|---|
| Skill | ~/.claude/skills/<name>/SKILL.md, .claude/skills/<name>/SKILL.md | You (/name) or the model, by matching the description | No — it is text that can instruct Claude to run a bundled script with its own tools |
| Subagent | .claude/agents/*.md, ~/.claude/agents/*.md | The model, via the Agent tool, routed on the description | Yes — it has its own tools, permissions and model |
| MCP server | .mcp.json (project) or ~/.claude.json (local / user) | The model, by calling mcp__server__tool | Yes — a separate process or a remote endpoint, with its own auth |
| Hook | settings.json, keyed by event name | Claude Code itself, on a lifecycle event | Yes — and the model has no say in whether it fires |
| Plugin | A directory with .claude-plugin/plugin.json, cached under ~/.claude/plugins/ | Nothing — it contributes the four above | Only through what it bundles |
| Marketplace | .claude-plugin/marketplace.json in a git repo | Nothing — it is a catalogue | No |
The axis that actually separates them: when it enters your context
Almost every practical difference between a skill, an MCP server and a subagent comes down to what is in the model's context at session start, and what only arrives when it's needed. Get that picture right and the rest follows.
The change that broke everyone's mental model: commands are skills
The skills reference carries a note that most write-ups predate. Quoting it directly:
"Custom commands have been merged into skills. A file at .claude/commands/deploy.md
and a skill at .claude/skills/deploy/SKILL.md both create /deploy and work
the same way." Existing .claude/commands/ files keep working; if a skill and a
command share a name, the skill takes precedence.
So the two trees still exist on disk, but they are no longer two mechanisms. What the folder form
buys you is real, though, and it is worth migrating for: a directory to put supporting files in,
frontmatter that controls whether you or the model can invoke it, and — the big one — the model
loading it automatically when your request matches the description. A file in
.claude/commands/ supports the same frontmatter; it just can't carry a bundled script or
a reference doc next to itself. If you're still mapping the command surface, our
guide to the slash commands that matter covers the
built-ins this doesn't touch.
Skills: prose that loads when it matches
A skill is a folder containing SKILL.md. Personal skills live in
~/.claude/skills/<name>/ and follow you across projects; project skills live in
<repo>/.claude/skills/<name>/ and travel with the repo. A minimal one is two
lines of frontmatter and a body:
---
description: Review a PR diff for correctness bugs first, then style. Use before opening a PR.
---
Read the diff. Flag real correctness bugs before anything cosmetic.
Name the inputs that produce the wrong outcome, or it is a note, not a blocker. Three things about that frontmatter surprise people, and all three are documented:
- Every field is optional. Only
descriptionis recommended. If you omit it, Claude Code uses the first paragraph of the markdown body instead. -
nameis not the command name — not for personal or project skills. It is a display label. The command you type comes from the directory name:.claude/skills/deploy-staging/SKILL.mdgives you/deploy-stagingwhatever the frontmatter says. Only in plugin skills doesnameset the last segment of the command. - The description is the routing signal, and it is on a budget. Claude Code loads a
listing of every skill's name and description so the model knows what exists, and that listing is
capped at roughly 1% of the model's context window. When it overflows, descriptions get dropped
starting with the skills you invoke least. Each entry's combined
descriptionandwhen_to_usetext is truncated at 1,536 characters regardless. Run/doctorfor an estimate of what your listing is costing you.
That is the mechanism people mean by progressive disclosure: descriptions always in context, body only on invocation. One consequence rarely mentioned: once a skill is invoked, its rendered body enters the conversation as a single message and stays there for the rest of the session. Claude Code does not re-read the file on later turns. Write standing instructions, not one-time steps.
Beyond the body, a skill folder can carry templates, reference docs and scripts. Reference them from
SKILL.md using ${CLAUDE_SKILL_DIR} so the path resolves wherever the skill is
installed. allowed-tools pre-approves specific tools for the turn that invokes the skill
— the grant clears on your next message, which is a good deal more conservative than it first sounds.
Two precedence rules worth memorising. Across levels, enterprise overrides personal, and
personal overrides project — note the direction, because subagents resolve the opposite way.
And nested .claude/skills/ directories below your working directory load lazily: the
first time Claude reads or edits a file under apps/web/, that package's skills become
available, appearing as /apps/web:deploy if the name clashes with a root-level one.
What a skill cannot do is the useful half of the definition. It has no code path of its own. It cannot add a tool, hold a credential, open a socket, or fire on an event. It can tell Claude to run a bundled script — but the running is the Bash tool, under your permission rules, exactly as if you had typed the instruction yourself.
Subagents: a second context window with its own permissions
A subagent is a markdown file with YAML frontmatter in .claude/agents/ (project) or
~/.claude/agents/ (personal). Unlike skills, name and
description are both required here. The body is the subagent's system prompt —
and only that, plus basic environment details. It does not inherit your conversation or the full
Claude Code system prompt.
Delegation is description-routed, same as skill selection: the model reads descriptions and picks.
The mechanism is the Agent tool, which means you can switch delegation off entirely by
denying Agent in your permission rules. The frontmatter is where subagents pull ahead of
skills: tools and disallowedTools scope what it can touch,
model routes cheap work to a cheaper model, permissionMode and
maxTurns bound it, isolation: worktree gives it its own checkout, and
memory gives it a directory that survives across conversations.
The precedence trap: for subagents the order runs managed settings → the
--agents CLI flag → .claude/agents/ → ~/.claude/agents/ →
plugin agents, so a project definition beats your personal one. For skills it is the reverse.
If you keep a personal code-reviewer in both trees and wonder which one ran, that is why.
We go deeper on isolation and fan-out in
Claude Code subagents explained.
MCP servers: a process, not a prompt
An MCP server is the only mechanism here that is not a markdown file. It is a program — local over stdio, or remote over HTTP, SSE or WebSocket — that advertises tools, resources and prompts over the Model Context Protocol. Configuration lives at one of three scopes:
| Scope | Loads in | Stored in | Shared with the team |
|---|---|---|---|
| Local (default) | The current project only | ~/.claude.json, under that project's path | No |
| Project | The current project only | .mcp.json in the repo root | Yes, via version control |
| User | All your projects | ~/.claude.json | No |
claude mcp add --transport http notion https://mcp.notion.com/mcp
claude mcp add --transport http shared-server --scope project https://example.com/mcp
claude mcp add --env AIRTABLE_API_KEY=YOUR_KEY --transport stdio airtable -- npx -y airtable-mcp-server
Tools arrive namespaced as mcp__<server>__<tool>. There is a trap worth
knowing if you also write hooks: a server bundled inside a plugin registers its tools as
mcp__plugin_<plugin-name>_<server-name>__<tool-name>, so a hook matcher
written against the bare server key never fires for it. MCP also gives you two things people forget
exist — resources you pull into a prompt with @server:protocol://path, and server-side
prompts that show up in your / menu as /mcp__server__prompt.
Now the correction. The received wisdom is that skills are cheap because only the description loads, while MCP tool schemas are always in context and eat your window. That is out of date. Claude Code ships MCP tool search, enabled by default: tool definitions are deferred, only tool names and each server's instructions load at session start, and Claude searches for the schemas it needs. In the docs' words, "adding more MCP servers has minimal impact on your context window." Two consequences: the context-cost argument is no longer the tiebreaker between a skill and an MCP server, and if you are writing a server, its instructions field now does the same job a skill's description does — with a 2 KB truncation limit on both tool descriptions and server instructions.
The real line is capability, not cost. An MCP server can hold an OAuth token, paginate a result set, and return typed structured data. A skill cannot. For the setup path end to end, see Claude Code MCP servers.
The one that isn't in the list: hooks
Skills, MCP tools and subagents are all model-invoked. The model decides, and the model can
decide not to. If your requirement is "this must happen every time, whether or not the agent is in the
mood", none of them is the answer — you want a hook. Hooks register in settings.json
against a lifecycle event, get a JSON payload on stdin, and for some events their exit code changes
what the agent does next. Formatting on every write, blocking a command pattern, notifying you when a
turn ends: those are hooks, not skills. The full event list and the exit-code semantics are in
Claude Code hooks explained.
Plugins: packaging, not a capability
"Skill vs plugin" is a category error, and it is the most common one. A plugin does not compete with a
skill — it contains skills, alongside everything else. A plugin is a directory,
optionally with a .claude-plugin/plugin.json manifest, and the components sit at the
plugin root:
| Path in the plugin | What it contributes |
|---|---|
.claude-plugin/plugin.json | The manifest — name (which becomes the namespace), description, version |
skills/<name>/SKILL.md | Skills, invoked as /plugin-name:name |
commands/*.md | Skills in the flat legacy form |
agents/*.md | Subagent definitions |
hooks/hooks.json | Event handlers |
.mcp.json | MCP server configurations |
.lsp.json | Language servers, for real code intelligence |
monitors/monitors.json | Background watchers that push notifications into the session |
bin/ | Executables added to the Bash tool's PATH while enabled |
The docs flag one mistake specifically, because everybody makes it: do not put
skills/, agents/, commands/ or hooks/ inside
.claude-plugin/. Only the manifest goes in there. Everything else sits at the
plugin root.
Anthropic's own guidance on when to bother is refreshingly blunt. Standalone .claude/
configuration is for personal workflows, project-specific customisation and quick experiments, and it
buys you short names like /deploy. Plugins are for sharing with teammates, distributing to
a community, versioned releases and reuse across projects — and the price is namespaced invocation
like /my-plugin:deploy. Start standalone, convert when you're ready to share. Test a
plugin without installing it with claude --plugin-dir ./my-plugin, and
/reload-plugins after edits.
The boundary is genuinely blurring, though, and it's worth knowing before you draw a hard line.
claude plugin init my-tool scaffolds a plugin inside your skills directory — it
creates ~/.claude/skills/my-tool/ with a manifest and a starter SKILL.md, and
it loads on the next session as my-tool@skills-dir with no marketplace and no install
step. Drop a .claude-plugin/plugin.json into any skill folder and it becomes a plugin that
can bundle agents, hooks and MCP servers. So "is it a skill or a plugin" can now be answered "yes".
Marketplaces: the catalogue — and what's really in it
A marketplace is a git repo with a .claude-plugin/marketplace.json listing plugins and
their sources. You register one and install from it:
claude plugin marketplace add anthropics/claude-plugins-official
claude plugin marketplace list
claude plugin install <plugin-name>@<marketplace>
claude plugin list --available --json
Anthropic runs two public ones. claude-plugins-official is curated and registers itself
automatically the first time you launch Claude Code interactively — there is no application process;
Anthropic decides what goes in. claude-community is the reviewed community catalogue, and
you add it yourself from anthropics/claude-plugins-community.
Here is the part that changes how you should think about the marketplace, and it takes ten seconds to
check for yourself. Running claude plugin list --available --json in August 2026 returned
278 plugins, every single one of them from claude-plugins-official. The
manifest's own category counts: development 116, productivity 49, database 36, monitoring 20, security
17, deployment 8, design 7. And the names, in alphabetical order, tell the story faster than the
counts do — Airtable, AlloyDB, Adobe, Aikido, Amplitude, Apollo, Appwrite, Asana, Atlassian, Auth0,
Box, Canva, ClickHouse.
The plugin marketplace is a connector directory. It is where vendors ship an
integration with their product, and it is very good at that. It is not a library of craft — "how we
review a PR here", "the checklist before a migration", "our house TypeScript conventions". Mostly it
can't be: that knowledge is repo-specific and belongs in your .claude/skills/. If you
went to the marketplace looking for taste and came back disappointed, nothing was wrong with your
search.
The second ecosystem, which most write-ups miss
There is a whole parallel distribution system for skills that has nothing to do with plugins or marketplaces. Skill repos are plain git repos full of skill folders, installed with a separate CLI:
npx skills add vercel-labs/agent-skills
The CLI comes from vercel-labs/skills, with a registry at skills.sh. What
makes it interesting is where it puts things. It installs a canonical copy and symlinks each
agent's directory at it, so one skill can serve several tools. On this machine, five of the entries in
~/.claude/skills/ are symlinks:
$ ls -l ~/.claude/skills/ # abridged
drwxr-xr-x council
drwxr-xr-x wrangler
lrwxr-xr-x clean-code -> ../../.agents/skills/clean-code
lrwxr-xr-x find-skills -> /Users/me/.agents/skills/find-skills
lrwxr-xr-x frontend-design -> ../../.agents/skills/frontend-design
lrwxr-xr-x typescript-expert -> ../../.agents/skills/typescript-expert
lrwxr-xr-x vercel-react-best-practices -> /Users/me/.agents/skills/vercel-react-best-practices
The ~/.agents/ path is the point: it is deliberately vendor-neutral, so the same folder
can serve Claude Code, Cursor, Cline and the rest — the CLI claims detection for 75+ coding agents,
on the basis that skills follow a shared Agent Skills specification rather than a Claude-specific one.
And this is not a hack Claude Code merely tolerates: the skills reference explicitly says a skill
entry "can be a symlink to a directory elsewhere on disk", that Claude Code follows it, and that a
target reachable from two places is loaded once.
So there are two shipping lanes, and they are good at different things. Plugins and marketplaces are
Claude-only, versioned, and can carry hooks, MCP servers and executables. Skill repos are cross-agent,
prose-only, and install in one line without a manifest. If you are publishing a coding convention,
the second lane reaches more agents. If you are publishing an integration, only the first lane can
carry it. Anthropic maintains a skills repo of its own at anthropics/skills, which is
also where the packaging script lives for uploading skills to claude.ai.
One catch if you publish that way: outside Claude Code, only six frontmatter fields are legal —
name, description, license, compatibility,
metadata and allowed-tools. Everything else in Claude Code's frontmatter
table is a Claude Code extension, and including one makes packaging or upload fail with a hard error
rather than a warning.
Where two of these genuinely overlap
The decision table covers the clean cases. These are the ones where two mechanisms really do both work, and pretending otherwise is how you end up with a bad answer.
A skill that shells out vs an MCP server
You want Claude to query your Postgres. You could write an MCP server, or you could write a skill that
says "use psql, here is the connection string variable, here are the three tables you'll
actually need". The skill is legitimate and it is cheaper: no process to run, no schema to maintain,
and it works today if psql and the credentials are already in the environment. It stops
being legitimate the moment you want typed results instead of parsed text, pagination, OAuth rather
than an env var, or an install path a non-developer can follow. The tiebreaker is who holds
the credential and who parses the result — not context cost, which tool search has taken off
the table.
A skill vs a subagent — the docs call them the same system
This overlap is real and it is bidirectional. A skill can set context: fork and
agent: Explore, which runs the skill body as a forked subagent's prompt in an isolated
context. A subagent can list skills: in its frontmatter, which injects the full skill
content into its context at startup rather than just the description. The reference is explicit that
these are "the same underlying system", inverted. So choose by ownership: if the procedure is
the point and you want it available to whatever agent is running, write a skill. If the
worker is the point — its tools, its model, its permission mode — write a subagent and hang
skills off it.
A skill vs a line in CLAUDE.md
The docs give a good trigger for this one: write a skill "when a section of CLAUDE.md has grown into a
procedure rather than a fact". CLAUDE.md is always in context, so every line you add is
rent you pay on every turn; a skill's body costs nothing until it is used. Facts about the repo — the
package manager, the test command, the branch convention — stay in CLAUDE.md. Multi-step
procedures move to a skill. If you're also deciding what belongs in the cross-tool file instead, we
compare them in CLAUDE.md vs AGENTS.md.
A bare skill vs a plugin holding one skill
Genuinely a coin flip until one of three things is true: you need a version other people can pin to,
you need a hook or an MCP server travelling with the prose, or you need it installable rather than
copy-pasteable. Any of those, make it a plugin and accept the /my-plugin:name prefix.
None of them, leave it in .claude/skills/ and keep the short name.
Frequently asked questions
Should this be a skill or an MCP server?
A skill is prose: it changes how Claude behaves using tools it already has. An MCP server is a process: it gives Claude a tool it did not have, with its own credentials, its own wire protocol and typed results. If the capability needs auth, pagination, or code running outside Claude's tool set, it is an MCP server. If it needs Claude to follow your procedure with the Bash, Read and Edit tools it already has, it is a skill. The old tiebreaker — "MCP servers cost context, skills do not" — no longer holds: MCP tool search is on by default and tool schemas are deferred until Claude searches for them.
What is the difference between a skill and a plugin?
They are not alternatives. A plugin is a package that can contain skills, subagents, hooks, MCP servers, LSP servers and executables in one versioned, namespaced unit. Skills are one of the things a plugin ships. You write a skill; you distribute it in a plugin. Use a bare skill in .claude/skills/ for personal or single-project work, and a plugin the moment you need version pinning, a marketplace, or a hook and an MCP server travelling alongside the prose.
Are slash commands still separate from skills?
No. The skills reference states that custom commands have been merged into skills: a file at .claude/commands/deploy.md and a skill at .claude/skills/deploy/SKILL.md both create /deploy and work the same way. Existing .claude/commands/ files keep working, and if a skill and a command share a name, the skill wins. The folder form adds supporting files, frontmatter controlling who can invoke it, and automatic loading when it matches your request.
Where do skills live on disk?
Personal: ~/.claude/skills/<name>/SKILL.md, in every project. Project: <repo>/.claude/skills/<name>/SKILL.md. Plugin: <plugin>/skills/<name>/SKILL.md, namespaced as /plugin-name:skill-name. On a clash, enterprise overrides personal and personal overrides project — the opposite direction from subagents, where the project definition wins over the personal one.
What is actually in the plugin marketplace?
Vendor integrations, overwhelmingly. claude plugin list --available --json returned 278 plugins, every one from claude-plugins-official: Airtable, AlloyDB, Adobe, Aikido, Amplitude, Asana, Auth0, Box, Canva, ClickHouse. It is a connector directory, not a library of craft skills. Anthropic also runs a reviewed community marketplace, claude-community, which you add yourself from anthropics/claude-plugins-community.
Where Backgrind fits
Backgrind doesn't extend Claude Code — it runs your real CLI in an always-on-top
overlay with a tab per session, and pings you only when one of them needs a decision. The one place it
touches this topic: its skills browser reads what you actually have installed, across both ecosystems
at once. Global and project skills, legacy .claude/commands/ files, and the entries that
are really symlinks into ~/.agents/skills/ — flagged as links, so removing one takes the
link and never the shared target — plus your installed plugins and the marketplace catalogue behind
them. After reading this far you know how many places that inventory is scattered across. Seeing it in
one list is the point. Watch the loop in the live demo.
Verified August 2026 against Claude Code 2.1.221 and the current reference pages:
skills
(the commands-merged-into-skills note, the frontmatter table, scope precedence, the listing budget
and the 1,536-character cap, symlink support, context: fork),
plugins
(component directories, the .claude-plugin/ warning, standalone-vs-plugin guidance,
claude plugin init, both public marketplaces),
subagents
(scope priority, required name and description, the frontmatter fields,
skills: preloading, isolation: worktree) and
MCP
(the three scopes, transports, plugin tool naming, tool search on by default). Plugin counts and
category breakdown from claude plugin list --available --json and the official
marketplace manifest; the symlink listing from ls -l ~/.claude/skills/ on the author's
machine. Second-ecosystem details from
vercel-labs/skills and
skills.sh. This surface moves fast — the
commands-into-skills merge and tool-search-by-default are both recent, and several frontmatter
fields carry explicit minimum versions. Check the reference before you build on a specific field.