Claude Code Plugins, Explained
A Claude Code plugin is one folder that bundles skills, agents, hooks, and MCP servers behind a single install. How /plugin marketplace add and /plugin install work, and how plugin scope differs from your own .claude/ files.
Want the framework behind these builds?
Get the Claude Code system we use to plan, build, test, and ship production software.
A Claude Code plugin is one directory that bundles skills, subagents, hooks, MCP servers, and settings behind a single install. It is not a new kind of capability. It is a packaging format for capabilities you can already write yourself in .claude/, plus a distribution system so other people can install them in one line.
That is the whole idea. Everything else is mechanism: where the files go, how the catalog resolves, which settings file records the install, and what the naming changes to once a skill lives inside a plugin.
What a plugin actually is on disk
A plugin is a folder. Inside that folder, components sit in conventional directories at the root, and an optional manifest at .claude-plugin/plugin.json describes the package.
my-plugin/
├── .claude-plugin/
│ └── plugin.json ← manifest (optional)
├── skills/
│ └── code-review/
│ └── SKILL.md
├── agents/
│ └── reviewer.md
├── hooks/
│ └── hooks.json
└── .mcp.jsonThe manifest is optional. If you leave it out, Claude Code auto-discovers components in the default locations and derives the plugin name from the directory name. When you do include one, name is the only required field:
{
"name": "my-plugin",
"description": "Review helpers for our monorepo",
"version": "1.0.0"
}If you compare that to a normal .claude/ directory, the shape is familiar. skills/ holds skill folders exactly as it does in your project. agents/ holds subagent Markdown files. The differences are that hooks move out of settings.json into hooks/hooks.json, and MCP servers live in a .mcp.json at the plugin root rather than in your project config.
The components a plugin can bundle
This is the part most explanations undersell. A plugin is not just "a bag of slash commands." Per the plugins reference, these are the component slots and their default locations:
| Component | Default location | What it adds |
|---|---|---|
| Skills | skills/<name>/SKILL.md | Invocable and model-invoked capabilities |
| Commands | commands/*.md | Skills as flat Markdown files (legacy form) |
| Agents | agents/*.md | Subagents Claude can delegate to |
| Hooks | hooks/hooks.json | Event handlers on the session lifecycle |
| MCP servers | .mcp.json | External tool connections, started automatically |
| LSP servers | .lsp.json | Language server diagnostics and code navigation |
| Monitors | monitors/monitors.json | Background watchers that push events to Claude |
| Output styles | output-styles/ | Alternative response formats |
| Themes | themes/ | Color themes |
| Workflows | workflows/ | Workflow script files |
| Executables | bin/ | Binaries added to the Bash tool's PATH while enabled |
| Settings | settings.json | Defaults applied when the plugin is enabled |
Two of those rows deserve a pause. The bin/ directory means an enabled plugin can put arbitrary executables on the Bash tool's path, invokable as bare commands. And the plugin-level settings.json supports an agent key, which activates one of the plugin's own subagents as the main thread, replacing the system prompt, tool restrictions, and model for your whole session. A plugin is not a passive add-on. It can change what Claude Code fundamentally is for that session.
There is one structural rule that trips up nearly every first-time author. Only plugin.json goes inside .claude-plugin/. Every other directory sits at the plugin root. Put skills/ inside .claude-plugin/ and nothing loads, with no obvious error.
Installing one: the two-step you cannot skip
Installing is deliberately two moves, and conflating them is the most common source of "plugin not found."
Step one, register a catalog. A marketplace is a marketplace.json file listing plugins and where to fetch each one. Adding it does not install anything. This example registers Anthropic's demo catalog, which ships inside the claude-code repo:
/plugin marketplace add anthropics/claude-codeThe owner/repo shorthand resolves to GitHub. You can also point at a full git URL from any host, a local directory, a direct path to a marketplace.json file, or a hosted URL:
/plugin marketplace add https://gitlab.com/company/plugins.git
/plugin marketplace add https://gitlab.com/company/plugins.git#v1.0.0
/plugin marketplace add ./my-marketplace
/plugin marketplace add https://example.com/marketplace.jsonStep two, install a plugin from it. Identify the plugin as name@marketplace:
/plugin install commit-commands@claude-code-pluginsNote that the marketplace name is not the repo path. anthropics/claude-code registers a catalog that names itself claude-code-plugins, and anthropics/claude-plugins-community registers one that names itself claude-community. The name comes from the catalog's own marketplace.json, so check the Marketplaces tab if an install cannot find the catalog you just added.
Then reload. Installing mid-session does not activate anything until you run /reload-plugins, which reloads plugins, skills, agents, hooks, plugin MCP servers, and plugin LSP servers without a restart. One quirk to know: the summary counts skills from each plugin's commands/ directory only, so it can report 0 skills while the skills you just installed loaded correctly.
/plugin on its own opens an interactive panel with four tabs: Discover for browsing every registered marketplace, Installed for enable, disable and uninstall, Marketplaces for adding and refreshing catalogs, and Errors for load failures. When a plugin fails silently, the Errors tab is the first place to look, not the transcript.
For scripting, the shell equivalents skip the panel entirely:
claude plugin install formatter@my-marketplace --scope project
claude plugin list
claude plugin details commit-commands
claude plugin uninstall formatter@my-marketplace --scope projectOfficial, community, and everything else
Past the demo catalog above, Anthropic runs two real public marketplaces, and they are not the same thing.
claude-plugins-official is curated by Anthropic and registers itself automatically the first time you launch Claude Code interactively. Nothing to add. If your network blocked the initial fetch, add it manually with /plugin marketplace add anthropics/claude-plugins-official. Per the install docs, it carries the language-server plugins (typescript-lsp, pyright-lsp, rust-analyzer-lsp, gopls-lsp and others), pre-wired MCP integrations (github, gitlab, linear, notion, figma, sentry, slack, supabase, vercel, firebase), the security-guidance reviewer, and workflow bundles like commit-commands, pr-review-toolkit, and plugin-dev. Inclusion is at Anthropic's discretion and there is no application process.
claude-plugins-community is the third-party catalog. Submissions pass automated validation and safety screening, and each approved plugin is pinned to a specific commit SHA. You add it manually and install from it under the name claude-community:
/plugin marketplace add anthropics/claude-plugins-community
/plugin install some-plugin@claude-communityAnything else is a marketplace someone hosts themselves, which is just a git repo with a .claude-plugin/marketplace.json at its root. That is the mechanism your company would use for internal tooling, and it is also the reason plugin trust is a real question rather than a theoretical one.
Scope: four places an install can be recorded
When you install, you pick a scope, and the scope is really just a choice of which settings file gets the record.
| Scope | Settings file | Who gets it |
|---|---|---|
user | ~/.claude/settings.json | You, in every project (the default) |
project | .claude/settings.json | Everyone who clones the repo |
local | .claude/settings.local.json | You, in this repo only, not shared |
managed | Managed settings | Pushed by an administrator, read-only |
This is the same scope ladder that governs the rest of your Claude Code config, so it behaves the way CLAUDE.md and the rules directory already behave. Nothing new to learn.
What is worth knowing is that you can declare plugins in settings directly instead of installing interactively. A repo can pre-register its marketplace and pre-enable plugins so collaborators are prompted on first trust:
{
"extraKnownMarketplaces": {
"company-tools": {
"source": {
"source": "github",
"repo": "your-org/claude-plugins"
}
}
},
"enabledPlugins": {
"code-formatter@company-tools": true,
"deployment-tools@company-tools": true
}
}Two gotchas here. First, enabledPlugins only enables a plugin, it does not fetch it. A plugin from an external source that only the project's .claude/settings.json enables will not load until each collaborator actually installs it, and Claude Code will report it as not installed with the claude plugin install command to run. Second, marketplace registration is stored once per user in ~/.claude/plugins/known_marketplaces.json, not per project, so all your git worktrees share the same marketplace state.
Uninstalling a project-enabled plugin asks which you mean: disable it for yourself, which writes an override into .claude/settings.local.json, or remove it from the shared .claude/settings.json for everyone.
The naming change, and why it exists
Here is the practical difference between a standalone skill and the same skill inside a plugin.
A skill at .claude/skills/deploy/SKILL.md gives you /deploy. The same skill inside a plugin named my-tools gives you /my-tools:deploy. Plugin components are always namespaced by the plugin name, which is why the manifest name field matters beyond cosmetics.
The same applies to subagents. A plugin agent shows up in the @-mention typeahead as my-plugin:code-reviewer rather than code-reviewer. And MCP tools from a bundled server take a scoped name of the form mcp__plugin_<plugin-name>_<server-name>__<tool>, which matters if you write hook matchers against them, because a matcher written against the bare server key never fires.
Namespacing exists because two plugins from two authors will eventually both ship a skill called review. The cost is verbosity. The benefit is that installing a stranger's plugin cannot shadow your own commands.
This is also why the official guidance is to prototype standalone and package later. Iterate in .claude/skills/ where the names are short, then convert to a plugin when you want to share it. If you have not written a skill yet, start with what Claude skills are and building your first one.
How this relates to what you already run
If you already have a .claude/ directory full of skills, subagents, and custom slash commands, plugins do not replace any of it. Here is the honest comparison:
Standalone .claude/ | Plugin | |
|---|---|---|
| Invocation | /deploy | /my-plugin:deploy |
| Hooks live in | settings.json | hooks/hooks.json |
| Sharing | Copy files by hand | /plugin install |
| Versioning | Your repo's git history | Manifest version or commit SHA |
| Reach | This project (or your home dir) | Any project, any machine |
| Best for | Personal workflows, fast iteration | Team distribution, community release |
Migration is mechanical. Create a plugin directory, add a manifest, copy commands/, agents/, and skills/ across, and move the hooks object out of your settings.json into hooks/hooks.json (the format is identical). Then delete the originals, because project and user .claude/agents/ definitions override same-named plugin agents, so the plugin version stays inert until the original is gone. Skills behave differently: the namespace prevents collision, so both /deploy and /my-plugin:deploy remain available.
There is a middle path too. Any folder in a skills directory containing a .claude-plugin/plugin.json loads automatically as <name>@skills-dir, with no marketplace and no install step, and claude plugin init my-tool scaffolds one at ~/.claude/skills/my-tool/. You get plugin structure (bundled agents, hooks, MCP) without publishing anything. Project-scope versions load only after you accept the workspace trust dialog, only from the .claude/skills/ of the directory you launched from.
What a plugin costs you
Every enabled plugin has a standing context cost, because its skill descriptions, agent descriptions, and command names are listed to the model on every turn whether or not anything fires.
claude plugin details <name> breaks this into two numbers. Always-on is what the plugin adds to every session just by being enabled. On-invoke is what a specific component costs when it actually runs, shown per component rather than as a total, because a typical session fires only a subset. The always-on figure is computed with the token counting API for your active model.
The /plugin Installed tab helps you prune. It groups marketplace plugins you have not used in at least two weeks across at least ten sessions under a Not used recently header, with a Last used line in the detail view. Theme, output style, monitor, and workflow plugins are exempt, since they deliver value without an invocation to track.
Reloading is not free either. When a plugin provides MCP servers whose tools are not deferred by tool search, /reload-plugins invalidates the prompt cache and the next request re-reads the entire conversation, so Claude Code warns and declines to apply it unless you pass --force. If token spend is a live concern, see cutting Claude Code token costs.
Failure modes worth memorizing
Components inside .claude-plugin/. Only plugin.json belongs there. Everything else goes at the plugin root. This is the single most common structural mistake and it fails quietly.
Forgetting /reload-plugins. Install, enable, and disable do not take effect mid-session on their own. And a skill count of 0 in the reload summary is a reporting quirk, not a failure, because that count covers commands/ only.
The version pinning trap. Claude Code uses the plugin version as the cache key. If you set "version" in plugin.json, users get updates only when you bump that string. Pushing new commits without bumping it does nothing, and /plugin update reports that they are already on the latest version. Omit version from both plugin.json and the marketplace entry and the git commit SHA is used instead, so every commit ships. Explicit versions are right for published plugins, commit-SHA versioning is right for a team plugin under active development.
Paths that escape the plugin root. Marketplace plugins are copied into a versioned cache at ~/.claude/plugins/cache, not run in place. Anything referenced as ../shared-utils is not copied and will not resolve after install. Reference bundled files through ${CLAUDE_PLUGIN_ROOT} instead, and remember that its value changes on every update, so it is not a place to write state. To share files between plugins in the same marketplace, use a symlink, which gets dereferenced into the cache. Symlinks pointing outside the marketplace are skipped for security.
Removing a marketplace uninstalls its plugins. /plugin marketplace remove is not just a deregistration. Anything you installed from it goes with it.
Two names for one plugin. A marketplace entry can list a plugin under a different name than its own plugin.json uses. The marketplace entry name is the one enabledPlugins keys and the one /plugin install, /plugin enable, and /plugin disable expect.
LSP plugins need the binary. Installing typescript-lsp does not install typescript-language-server. A missing binary shows up as Executable not found in $PATH in the /plugin Errors tab, not as a crash.
Stale cache. When skills refuse to appear after everything else checks out, clear it with rm -rf ~/.claude/plugins/cache, restart, and reinstall.
Building and testing one without publishing
You do not need a marketplace to run a plugin. The --plugin-dir flag loads a directory for the session:
claude --plugin-dir ./my-pluginRepeat the flag to load several. It also accepts a .zip archive, and --plugin-url fetches a hosted archive at startup for that session only. When a --plugin-dir plugin shares a name with an installed one, the local copy wins for that session, which is how you test changes to something already installed.
Before you distribute, validate:
claude plugin validate ./my-pluginThis checks plugin.json, skill, agent, and command frontmatter, and hooks/hooks.json for syntax and schema errors. Pass --strict to treat warnings as errors. The community review pipeline runs the same check, so a clean local run saves a rejection round trip. When something still misbehaves, claude --debug prints which plugins loaded, manifest errors, component registration, and MCP initialization.
The security question, answered plainly
Plugins and marketplaces execute arbitrary code on your machine with your user privileges. A plugin can register hooks that fire on every tool call, start MCP servers that talk to the network, and drop executables onto the Bash tool's PATH. Anthropic explicitly does not control what third-party plugins contain and cannot verify they work as intended.
The practical defenses are ordinary dependency hygiene. Read what the details pane lists under Will install before confirming, which enumerates commands, agents, skills, hooks, and MCP and LSP servers. Prefer plugins pinned to a commit SHA, which is what the community catalog does. In an organization, admins can restrict which marketplaces users may add at all through strictKnownMarketplaces in managed settings, checked before any network or filesystem operation.
Plugins are worth using. They are also the highest-trust extension point Claude Code has.
Frequently asked questions
What is a Claude Code plugin?
A plugin is a self-contained directory that bundles skills, subagents, hooks, MCP servers, LSP servers, and optional executables, installed as one unit. It is the same material you already put in .claude/, packaged so it can be versioned, shared, and installed by other people.
How do I install a Claude Code plugin?
It is two steps. Register a catalog with /plugin marketplace add owner/repo, then install from it with /plugin install plugin-name@marketplace-name. The official Anthropic marketplace registers itself the first time you launch Claude Code, so plugins like github and commit-commands need only the install step. Run /reload-plugins afterwards to activate without restarting.
What is the difference between a plugin and a skill?
A skill is one capability, a folder with a SKILL.md file. A plugin is a distribution wrapper that can contain many skills plus agents, hooks, and MCP servers. The visible trade-off is naming: a standalone skill is invoked as /deploy, while the same skill inside a plugin is invoked as /plugin-name:deploy, which prevents collisions between plugins.
Do plugins install per project or globally?
You choose at install time. User scope writes to ~/.claude/settings.json and follows you across every project. Project scope writes to .claude/settings.json and ships to everyone who clones the repo. Local scope writes to .claude/settings.local.json, so it applies only to you in that one repo. Managed scope is set by an administrator and is read-only.
Are Claude Code plugins safe to install?
Treat them like any dependency that runs on your machine. A plugin can register hooks, start MCP servers, and add executables to the Bash tool's PATH, all with your user privileges. Anthropic does not control what third-party plugins contain. Read the manifest, check what the details pane lists under Will install, and only add marketplaces you trust.
Posted by @speedy_devv
Want the framework behind these builds?
Get the Claude Code system we use to plan, build, test, and ship production software.

