Claude Code skills, plugins, MCP servers and subagents are all described as ways to extend Claude Code, which is why the same question turns up on Reddit three times a month in three different wordings. The names do not tell you which one you need. Worse, three of the four can produce results that look identical from the outside, so picking wrong does not fail loudly. It just costs you a weekend.
The confusion has one cause, and naming it fixes most of the problem: these are not four options on one list. Three of them are things Claude uses, and the fourth is the box you put the others in.
Why these four get mixed up
They get mixed up because two of them are markdown files with YAML frontmatter that tell Claude how to do something, and from the outside a skill and a subagent both look like "a file that does a task". The real difference is invisible in the file: it is where the work happens and what comes back.
Here is the map I wish someone had handed me.
If you remember one sentence from this post, make it this one: a skill spends your context, a subagent protects it, an MCP server extends what Claude can touch, and a plugin is how any of it reaches another machine.
What is a Claude Code skill?
A skill is a SKILL.md file with instructions in it. Claude loads it when it is relevant, or you invoke it directly with /skill-name. Its body costs nothing until it is used, which is what makes it the right home for a long procedure that would otherwise bloat your claude(.)md.
Anthropic's skills documentation is blunt about when to write one: create a skill when you keep pasting the same instructions into chat, or when a section of claude(.)md has grown into a procedure rather than a fact.
The 2026 change most people missed
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 behave the same way. Existing commands/ files keep working, and the plugin structure table now says outright to use skills/ for new plugins.
So "should this be a slash command or a skill?" is no longer a real question. It is a skill either way. What the skill layout adds is a directory for supporting files, and frontmatter that controls who is allowed to invoke it:
---
description: Deploy the current branch to staging
disable-model-invocation: true
allowed-tools: Bash(git push *) Bash(gh workflow run *)
---
disable-model-invocation: true means only you can fire it. That is the setting you want on anything with side effects, because you do not want Claude deciding your code looks ready to deploy.
The part that surprises people
When a skill is invoked, its rendered content enters the conversation as a message and stays there. Claude does not re-read the file on later turns, so write standing instructions rather than one-time steps, and remember that a very long skill is context you are now carrying.
It does not persist unconditionally, though, and this is the part I had wrong until I read the lifecycle section properly. Auto-compaction re-attaches only the most recent invocation of each skill, keeps only its first 5,000 tokens, and gives all re-attached skills a combined 25,000-token budget filled newest-first. Invoke enough skills in one session and the early ones are dropped entirely. If a skill seems to stop working after a compaction, re-invoke it.
How is a subagent different from a skill?
A subagent gets its own context window. That is the whole distinction, and everything else follows from it.
A subagent is also a markdown file with frontmatter, living in .claude/agents/ or ~/.claude/agents/. But when Claude delegates to it, the subagent starts fresh: it does not see your conversation history, the files already read, or the skills already invoked. It does its work, and returns only a summary to your conversation. The search results, the logs and the file dumps stay in its context and never reach yours.
- -Runs in your current conversation
- -Its full text stays in your context
- -Everything it produces lands in front of you
- -Right when the work needs the conversation
- +Runs in a fresh, isolated context window
- +Sees no history, unless it is a fork - see below
- +Returns a summary, keeps the noise
- +Right when the work would flood your context
There is one exception you should know before you rely on the isolation: a fork. A forked subagent inherits the entire conversation instead of starting fresh. So "sees no history" describes the ordinary subagent, not every subagent.
Read the next part carefully, because the exception is not only something you opt into. Fork mode is on by default in interactive sessions from v2.1.232, and while it is on, Claude can spawn a fork itself by requesting the fork subagent type. You force one deliberately with /subtask, which needs v2.1.212 or later and agent view enabled; with agent view off the command is /fork instead. Either way you are not the only one who can start one. In -p and in the Agent SDK it is off by default, so the same setup behaves differently depending on how the session was launched.
Claude only gets a fork when it explicitly asks for that type. Anything spawned from a definition, an Explore or a custom agent of your own, is still an ordinary isolated subagent. But if your reason for reaching for a subagent was context isolation specifically, that default is worth knowing rather than discovering. Two controls:
CLAUDE_CODE_FORK_SUBAGENT=0 # fork mode off in every session
{ "permissions": { "deny": ["Agent(fork)"] } }
The first switches fork mode off entirely. The second leaves it on but stops Claude spawning forks, which is usually the one you actually want. One side effect to expect either way: while fork mode is on, Claude Code runs spawned subagents in the background, forks and ordinary subagents alike.
The practical test is one question: do I want to read everything this produces? If yes, skill. If the useful output is one paragraph sitting on top of two thousand lines of grep results, subagent. That is also the rule behind my scored delegation setup, which decides automatically rather than leaving it to a judgement call every time.
A subagent's frontmatter can restrict its tools, pin its model, cap its turns, and preload specific skills into it. Do not skip the description field: it is what Claude reads to decide whether to delegate at all.
This lives in primeline-ai/evolving-lite - the self-evolving Claude Code plugin. Free, MIT, no build step.
What does an MCP server actually add?
An MCP server adds reach. Skills and subagents change how Claude works with what it already has. An MCP server gives Claude access to something it otherwise could not touch: an issue tracker, a database, a monitoring dashboard, a design file.
The Model Context Protocol is an open standard, so this is not a Claude-specific plugin format. Connect a server when you notice yourself copying data into chat from another tool. Adding one is a single command:
# an HTTP server
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp
# a local stdio server, with an environment variable
claude mcp add my-server -e API_KEY=xxx -- npx my-mcp-server
The thing to keep straight is that an MCP server is not instructions. It does not tell Claude what to do or when. It hands Claude a set of tools and lets Claude decide. If the problem is "Claude does not know your deployment procedure", an MCP server is the wrong answer and a skill is the right one. If the problem is "Claude cannot see your Jira tickets", it is the other way round.
There is a context cost, and it is smaller than it used to be. Tool search is on by default now: Claude Code loads each server's tool names and instructions at session start and defers the parameter schemas until a task actually needs one. I am writing this in a session that works exactly that way, with schemas fetched on demand rather than loaded up front. So the baseline still grows with every server you connect, just far more slowly than when full schemas loaded for everything. Tiering servers is now about keeping your own setup legible rather than heading off an emergency, which is what my post on organising MCP servers by tier covers.
A plugin is a box, not a capability
A plugin does nothing on its own. It is a directory that bundles the other things into one installable, versioned, shareable unit.
Note what is not required: the .claude-plugin/plugin.json manifest is optional. Leave it out and Claude Code auto-discovers components in their default locations and takes the plugin name from the directory. Add one when you need metadata or custom paths. I had this wrong for a while and it matters, because "no manifest" is a perfectly valid plugin rather than a broken one.
One exception, and it is the case most people meet first: a directory under ~/.claude/skills/ needs the manifest to be adopted as a plugin. Without it the directory still loads as a plain skill, it just cannot carry commands, agents or hooks, and it will not appear in claude plugin list.
The plugins reference lists thirteen default locations, and knowing the range is most of what you need to judge whether something should be a plugin at all:
| Location | What it holds |
|---|---|
.claude-plugin/plugin.json | Manifest with metadata and custom paths. Optional |
skills/ | Skills as name/SKILL.md directories |
commands/ | Skills as flat markdown files. The docs say to use skills/ for new plugins |
agents/ | Subagent definitions |
workflows/ | Workflow script files |
output-styles/ | Output style definitions |
themes/ | Colour theme definitions |
hooks/hooks.json | Event handlers |
.mcp.json | MCP server definitions |
.lsp.json | Language server configurations |
monitors/monitors.json | Background monitors that watch logs or files |
bin/ | Executables added to the Bash tool's PATH while enabled |
settings.json | Default settings applied when enabled, agent and subagentStatusLine only |
One warning worth repeating because it is the most common structural mistake: only plugin.json goes inside .claude-plugin/. Every other directory sits at the plugin root. And the plugin root is the plugin's own directory, never ~/.claude/.
Plugin skills are namespaced, so a hello skill in a plugin called my-tool is /my-tool:hello, and installing a plugin cannot silently shadow a skill you already had. The bare name is registered too, unless something already uses it. One wrinkle: a plugin skill's frontmatter name overrides the directory name, so the command is not always what the folder is called.
If you want the full build walkthrough rather than the decision, I wrote how to build a Claude Code plugin as a step-by-step. The plugin I ship, primeline-ai/evolving-lite, is a working example of the bundle: skills, agents and hooks in one directory.
Which one do I need?
Start from the problem, not the feature. Every row here is a real thing I have wanted at some point.
| What you actually want | Reach for | Why not the others |
|---|---|---|
| Claude to follow a procedure you keep re-explaining | Skill | A plugin is overkill for one file; an MCP server carries no instructions |
| A long reference doc available but not always loaded | Skill | Putting it in claude(.)md pays the cost on every turn |
| A noisy investigation kept out of your conversation | Subagent | A skill would dump all of it in front of you |
| A specialist with restricted tools and its own model | Subagent | Skills inherit your tools and your context |
| Claude to read your issue tracker or database | MCP server | No amount of instruction gives Claude access it does not have |
| To hand your whole setup to a teammate | Plugin | The others are files on your machine until something packages them |
| The same setup across several of your own projects | Plugin | Copying .claude/ between repos is the drift you are trying to avoid |
| Long work running while you do something else | Background session | Not on this list at all, and covered in parallel Claude Code sessions |
Note that the last question is a different kind of question. You never choose a plugin instead of a skill. You choose a skill, then decide whether it travels.
Where they overlap on purpose
The four are not sealed off from each other, and the deliberate overlaps are where the remaining confusion lives.
A skill can run in a subagent. Setting context: fork in a skill's frontmatter runs it in its own subagent context. So "skill or subagent" is sometimes "a skill, executed the subagent way".
A subagent can preload skills. The skills field in a subagent's frontmatter loads specific skills into it at startup. A skill with disable-model-invocation: true is excluded from that preloading, which is easy to trip over.
A plugin can ship an MCP server. Put .mcp.json at the plugin root and installing the plugin configures the server. This is how a team ships a working integration rather than a README telling everyone to run claude mcp add.
Hooks are the fifth thing, and they are not on this list. A hook fires on an event rather than being invoked, which puts it in a different category from all four. It ships inside a plugin like the rest.
Four traps that cost me time
All four were measured against Claude Code v2.1.233, not read off a blog post.
claude plugin add does not exist
It is the command everyone types, including a page on this site until recently. The real subcommand list is details, disable, enable, eval, help, init, install, list, marketplace, prune, tag, uninstall, update and validate.
I nearly published a second error on top of this one. I had a note claiming the list grew by four entries between v2.1.232 and v2.1.233, so I checked instead of repeating it. Both versions were still on disk, and both return the same fourteen subcommands:
~/.local/share/claude/versions/2.1.232 plugin --help # 14 subcommands
claude plugin --help # the same 14
The earlier note had simply recorded an incomplete reading and I had turned that into a version delta. Run claude plugin --help on your own install rather than trusting any published list, this one included.
pluginDirectories in settings.json does nothing
This one is worth checking on your own machine, because it fails in silence. Unknown settings keys are ignored, so you get no plugin and no error.
strings ~/.local/share/claude/versions/2.1.233 | grep -ic pluginDirectories # 0
strings ~/.local/share/claude/versions/2.1.233 | grep -ic skills-dir # 37
strings ~/.local/share/claude/versions/2.1.233 | grep -ic enabledPlugins # 35
Zero hits for a key alongside dozens for its working siblings is strong evidence nothing reads it. A live test agreed: a settings entry produced No plugins installed.
This is the general version and it generalises well past plugins. Verifying that a key is present in your settings verifies an action. Whether the loader honours it is the outcome, and only the second one matters. Checking the first and reporting the second is how a wrong instruction survives in a README for months.
marketplace add fails on a plain plugin repository
claude plugin marketplace add owner/repo is the canonical flow, and it is structurally inapplicable to a repository that ships only a plugin. It needs .claude-plugin/marketplace.json, and a bare plugin repo has .claude-plugin/plugin.json instead. The error arrives at your terminal, not in any documentation you would have read first.
What actually works
Three paths, all of which I have run end to end:
# persistent: clone or symlink into your skills directory
git clone https://github.com/primeline-ai/evolving-lite.git ~/.claude/skills/evolving-lite
# session only, ideal while developing
claude --plugin-dir ./my-plugin
# scaffold a new one that auto-loads next session
claude plugin init my-tool
claude plugin init creates ~/.claude/skills/my-tool/ with a manifest and a starter SKILL.md, and it loads as my-tool@skills-dir with no marketplace step. Anything in that directory with a .claude-plugin/plugin.json is picked up the same way. A directory holding only a SKILL.md and no manifest is not adopted as a plugin, which is a distinction I got wrong before someone made me test the negative case.
Honest scope
Everything above was checked against the current documentation and, where a command was involved, run on Claude Code v2.1.233 on macOS on 2026-08-15. I have not exercised fork mode myself; the defaults and the two controls above come from the subagents documentation. The strings counts are from that exact binary and will differ on your version.
I have not used the workflows, output-styles, themes, LSP or monitors locations at all. They are in the table because the plugins reference lists them, and I am saying so rather than implying coverage I do not have. What I have built and run is the skills, agents, hooks and MCP combination.
Four claims in an earlier draft were wrong and an external model review caught all four: I described the manifest as required when it is optional, called the plugin commands/ row "legacy" when the documentation only says to prefer skills/, stated that skill content persists for a whole session without the compaction limits, and presented subagent isolation without the fork exception. A fifth, a claimed version delta in the plugin subcommands, I killed myself by running both binaries. All are corrected above. Re-read claude plugin --help and the skills page before building on any specific claim here.

![How to Build a Claude Code Plugin: Real Example [2026]](/_next/image?url=%2Fblog%2Fclaude-code-plugins-hero.webp&w=3840&q=75)

