Claude Code plugins vs skills: the same thing or two different things?
Published 2026-05-11 by Owner
The Claude Code docs use “plugin” and “skill” near each other often enough that the two terms blur. People who are new to the extension model frequently treat them as synonyms, and that misread causes real confusion: installing something that isn’t showing up, trying to version a thing that can’t be versioned directly, or building a distribution setup that doesn’t match how the system actually works.
They are not the same thing. The relationship is: a plugin is the package; a skill is what lives inside the package.
The npm analogy that actually holds
The closest mapping to something most developers already know: a plugin is to a skill what an npm package is to a module.
An npm package is the installable artifact. It has a name, a version, a manifest (package.json), and it can export one thing or fifty. When you run npm install, you get the whole package. The individual modules inside that package are what you actually import and use in code.
Claude Code’s extension model follows the same structure. A plugin is the distributable artifact — a directory that has its own manifest, a declared version, and can contain one skill or many. When you install a plugin, you get everything inside it. The individual skills are what Claude Code actually invokes.
You install plugins. You invoke skills. The plugin is never directly “run” any more than a package is directly “run” — its contents are.
This distinction matters the moment you start sharing work with others or managing versions. Plugins have versions; skills inherit them. If you publish a plugin at version 1.2.0 and someone installs it, they get every skill that plugin declares, all at version 1.2.0. There is no way to install only skill B from a plugin while leaving skill A at an older version. The plugin is the unit of distribution.
plugins.json — the manifest that makes a plugin a plugin
What separates a directory full of SKILL.md files from an actual installable plugin is the manifest. A plugins.json file at the plugin root declares the plugin’s identity and points to everything it contains.
The exact field names and shape are defined by the Claude Code plugin toolchain, so rather than inventing fields here, the useful description is what the manifest needs to accomplish:
- Identify the plugin by name and version (so the installer can track what’s installed and detect updates)
- Declare which skills the plugin provides and where their
SKILL.mdfiles live - Carry any metadata the marketplace needs to index and present the plugin (description, author, category)
When the Claude Code skills system sees a plugin directory, it reads the manifest first. From there it discovers the skills, registers their names, and makes their descriptions available for matching against user requests. Without the manifest, the directory is just a directory.
A minimal single-skill plugin looks like this on disk:
my-plugin/
├── plugins.json
└── skills/
└── pr-checklist/
└── SKILL.md
A plugin that ships a suite of related skills expands the same structure:
superpowers/
├── plugins.json
└── skills/
├── brainstorming/
│ └── SKILL.md
├── writing-plans/
│ └── SKILL.md
├── executing-plans/
│ └── SKILL.md
├── systematic-debugging/
│ └── SKILL.md
└── tdd/
└── SKILL.md
The skills-lock.json in a Claude Code project records the installed state — for each installed skill, it stores the source plugin, the path to the SKILL.md within that plugin, and a hash of the current content. The lock file operates at skill granularity because that’s what needs to be verified at load time. But the installation unit is still the plugin: when you install superpowers, all of its skills appear in skills-lock.json together.
One skill or many — the tradeoff
Whether to build a plugin with a single skill or a suite is a real design question with costs on both sides.
The single-skill plugin is tightly focused. The plugin’s identity and the skill’s identity are almost the same thing. Versioning is straightforward: a breaking change to the skill is a breaking change to the plugin, full stop. Users know exactly what they’re getting and can reason about what an upgrade might change.
The cost: if you build five related single-skill plugins, users install five separate things, track five versions, and face five separate update decisions. For skill authors publishing to a marketplace, five small plugins may have lower adoption than one coherent suite, because the discovery surface is fragmented.
The multi-skill plugin (a suite) solves that distribution problem. Superpowers is the canonical example in the Claude Code ecosystem: one plugin install brings in brainstorming, plan writing, plan execution, debugging, TDD, and more. Users get a coherent workflow system in one step.
The cost: the plugin version now carries many skills. A breaking change to any skill in the suite forces a plugin version bump that users see even if the skill they care about didn’t change. More importantly, there’s no way to pin skill A at an older behavior while upgrading skill B — the plugin moves as a unit.
The key signal is whether the skills share a conceptual domain and a version contract. If skill A and skill B need to be updated together when your workflow changes — because they pass context to each other, or because upgrading one without the other would break your process — they belong in the same plugin. If they could be installed or uninstalled independently without the other becoming less useful, they likely belong in separate plugins.
The practical heuristic: skills that are designed to be used together belong in the same plugin. Skills that are independent and might be useful to entirely different audiences should be separate plugins. Superpowers skills reference each other in their descriptions and hand off between each other in practice — they belong together. A pr-checklist skill and an invoice-extractor skill share nothing; bundling them creates a plugin that no single user actually needs as a whole.
Versioning: where breaking changes live
Versioning in the plugin model works at one level: the plugin. Skills don’t have independent versions. They inherit the plugin version.
This has a specific consequence for how breaking changes propagate. If a plugin ships five skills and version 2.0 changes the trigger description of one of them, that version bump applies to the whole plugin. Users who upgrade to 2.0 get the updated trigger behavior whether or not the other four skills changed at all.
This is the same semantics as npm packages: the package version is the unit of compatibility, not any individual export.
For plugin authors, skill design stability matters at the plugin level. Skills still being iterated should stay in a pre-1.0 plugin until their trigger descriptions and body contracts stabilize. Once a skill is in a published plugin that others depend on, changing its description is a breaking change — the skill may fire in new places or stop firing where users expected it.
For users, the implication is that pinning matters. The skills-lock.json file is analogous to package-lock.json: it records the exact content hash of each skill at the time of install. If you depend on a specific skill behavior, the lock file is what preserves it. Upgrades are opt-in via an explicit update command, not silent.
Getting a useful skill from your machine to the team
The path from “I wrote a skill that helps me” to “the team uses this skill” has a few steps, and where you are on that path determines which mechanism fits.
Local only, just you. A local plugin directory that you point Claude Code at. The plugin isn’t checked into anything; it lives on your machine. Fast to iterate but nothing is shared.
Team sharing via git. Create a git repo for your team’s plugins. Structure it as a proper plugin with plugins.json, add the skills under skills/, and push. Everyone on the team installs the plugin from the git URL. When you update a skill and push, teammates run the plugin update command and get the new version.
This is the most common pattern for teams today. The git repo effectively is the plugin registry for the team. Semantic versioning the plugin repo is good practice once the skills are stable — it lets teams pin to a version and upgrade deliberately.
Vendoring into the project repo. For cases where you want the skills to travel with the codebase itself, you can vendor the plugin directory directly into the project (typically under .agents/ or a similar path). The skills-lock.json in the project root records the installed state. When someone clones the project and installs plugins from the lock file, they get the exact skill versions the project expects. This is the right pattern when the skills are tightly coupled to the project’s specific workflows — a deploy runbook that references the project’s exact infrastructure, or a PR checklist that knows the project’s specific test commands.
Marketplace. The Claude Code plugin marketplace distributes plugins publicly. For work that’s genuinely reusable across many teams and projects, publishing to the marketplace is the distribution mechanism that makes the skill discoverable to people who don’t know you exist. Marketplace plugins still follow the same plugins.json + SKILL.md structure — the marketplace is a discovery and install layer, not a different plugin format.
The path from local to team to marketplace is incremental. A skill that starts as a local plugin can become a team plugin without changing its structure. A team plugin can be published to the marketplace without changing its structure. The format is consistent; only the distribution channel changes.
One practical note on git-based team sharing: treat the plugin repo’s main branch as always-installable. A broken skill pushed to main means everyone who updates gets the breakage. Feature branches and a version bump in plugins.json for breaking changes are the minimal discipline that makes “update your plugins” a safe command.
The confusion that trips people up most
Two things that seem related but aren’t:
Installing a plugin does not activate its skills. It makes them available. A skill only loads into context when either the model’s description-matching decides it’s relevant, or you invoke it explicitly via /skill-name. Installing Superpowers and then asking Claude Code to “refactor this function” does not mean the refactoring skill runs — it means Claude Code evaluates whether any Superpowers skill has a description that matches “refactor this function.” If none do, the skills stay quiet. The right mental check when a skill isn’t firing: look at its description and ask whether your prompt would reasonably match that description. Almost always the answer to “why isn’t this skill triggering” is “because the description doesn’t match how I’m phrasing the request.”
The skill directory structure and the plugin structure are different things. The SKILL.md file defines a skill. The plugins.json and the parent directory define the plugin. When browsing a plugin’s source, you’re looking at the plugin layer. When Claude Code loads a skill at task time, it’s working with the skill layer. These are the same files, but viewed from different perspectives for different purposes.
A third misconception worth naming: “I should write a plugin.” Almost never. The plugin is plumbing. The thing worth designing is the skill — its trigger description, its body, its scope. Write the skill first; the plugin structure falls into place in minutes once the skill is solid.
What this means for building your own extensions
If you’re writing your first skill, you’re necessarily also creating your first plugin — even if it’s a trivial one. The plugin is the container that makes the skill installable.
The practical starting point: create a directory, add a plugins.json that declares your plugin’s name and version and points to one skill, then write the SKILL.md for that skill. Install the directory as a local plugin and test the skill in practice. Iterate on the trigger description until the auto-loading behavior is reliable.
Once the skill is stable, promote the plugin to a git repo. Add more skills to the same plugin if they’re related and would naturally be installed together. Keep them in separate plugins if they serve different audiences or have unrelated concerns.
The version number on the plugin is the commitment you make to users about stability. A plugin at 0.x is explicitly in flux; users who install it should expect breaking changes. A plugin at 1.0 carries the implicit promise that description-matching behavior and skill contracts are stable, and that version bumps beyond 1.x will be intentional signals about compatibility.
The ecosystem is still early. Plugin management tooling is minimal, the marketplace is not large, and most team-level sharing happens through git repos rather than published packages. But the underlying model — plugin as package, skill as module, version at plugin level, lock file for reproducibility — is designed to scale the same way npm scaled. Getting the concepts right now means the distribution story you build today will translate directly into the marketplace story as the ecosystem matures.
The first step is the same regardless of scale: write the SKILL.md, wrap it in a plugins.json, install it locally, and see whether the skill fires when you expect it to. Everything else is infrastructure around that core loop.
One observation from watching teams build their first plugins: the skills that get used are the ones with descriptions written to match how people actually phrase tasks, not how the skill author thinks about their own tool. A skill named deployment-runbook with the description “handles deployments” will be ignored; the same skill with “use before deploying to staging or production — verifies the checklist, confirms rollback plan, and prompts for smoke test sign-off” will activate reliably. The investment is in the description. The plugin is just the box it ships in.