← All guidesWorkflow

Claude Code plugins: how they are really built

A Claude Code plugin is a directory you can install, containing any mix of skills, agents, hooks, MCP servers and LSP servers. It is the shareable form of the things you already keep in .claude/. The format is simple, the traps are in the layout and in the manifest, and both are easy to check against what is actually published. Everything measured below comes from the official marketplace checkout on a machine running Claude Code 2.1.269. If you have not written a skill yet, start there: most plugins are mostly skills.

Plugin, or just a .claude directory?

Standalone .claude/Plugin
Skill name/hello/plugin-name:hello
Good forPersonal workflows, project-specific work, quick iterationSharing with a team, versioned releases, reuse across repos
DistributionCopy the files by hand/plugin install from a marketplace

Start standalone. Convert when you want someone else to have it.

The structure

Everything lives at the plugin root. Only the manifest goes inside .claude-plugin/:

my-plugin/
├── .claude-plugin/
│   └── plugin.json      # the manifest, and nothing else
├── skills/
│   └── code-review/
│       └── SKILL.md
├── agents/
├── hooks/
│   └── hooks.json
├── .mcp.json
└── README.md

The single most common mistake is putting skills/, commands/, agents/ or hooks/ inside .claude-plugin/. Only plugin.json belongs there. A plugin that ships exactly one skill can also drop a SKILL.md at the plugin root and skip the skills/ folder entirely.

Hooks move house on the way in: the hooks object that lived in your settings.json goes to hooks/hooks.json, same format. See hook events for what you can bind to.

What 295 published plugins actually ship

The official marketplace lists 295 plugins. Its repository carries 39 of them in its own tree, the rest pointing at external repositories. Of those 39:

ComponentPlugins shipping it
LICENSE39 (100%)
README.md37 (95%)
skills/15 (38%)
commands/13 (33%)
agents/8 (21%)
hooks/6 (15%)
.mcp.json1 (3%)

Two findings worth keeping. Most plugins are small: the largest ships seven skills, and the next largest three. And 14 of the 39 have no plugin.json at all, which is legal, because the manifest is optional when components sit in their default locations. The name then comes from the directory.

By declared category, across all 295 entries: development 121, productivity 54, database 38, monitoring 21, security 18, deployment 9, design 8.

The manifest

A real one, shipped by Anthropic, in full:

{
  "name": "agent-sdk-dev",
  "description": "Claude Agent SDK Development Plugin",
  "author": {
    "name": "Anthropic",
    "email": "support@anthropic.com"
  }
}

That is representative. Across the 25 manifests present in the checkout, name, description and author appear in 100 percent of them, and everything else is rare: version in 36 percent, homepage and license in 8 percent each, repository in 4 percent.

version deserves a decision rather than a default. When you set it, users only receive updates when you bump it. When you omit it, the version falls through to the next source, which means your users track your commits instead. Neither is wrong, but pick knowingly.

The marketplace entry is a separate object from the manifest, and it is where source and category live. Across the 295 entries: name, description and source on all of them, category and homepage on 95 percent, author on 72 percent.

Install, test, reload

Test without installing anything. The flag takes a directory, a folder of plugins, or a .zip:

claude --plugin-dir ./my-plugin

Then invoke your skill as /my-plugin:hello. Plugin skills are always namespaced, which is why installing two plugins with a review skill each is not a problem.

After editing files, /reload-plugins picks up the changes without restarting: skills, agents, hooks, MCP and LSP servers. In a session with no interactive terminal, MCP server changes wait for the next session instead.

To install from the community marketplace:

/plugin marketplace add anthropics/claude-plugins-community

On disk, that lands under ~/.claude/plugins/, which is worth knowing when something behaves oddly:

FileHolds
known_marketplaces.jsonEach marketplace, its GitHub source, install location and last update
installed_plugins.jsonWhat you have installed, under a version key for the file format itself
marketplaces/<name>/.claude-plugin/marketplace.jsonThe catalogue you browse
marketplaces/<name>/plugins/The plugin folders vendored by that marketplace

Before publishing, run claude plugin validate ./your-plugin. The community review pipeline runs the same check, and --strict turns warnings into errors.

When your plugin installs hooks

This is where a plugin stops being passive. A plugin with a hooks/hooks.json starts running commands on your machine on Claude Code events, which is exactly what makes plugins powerful and exactly why you should read one before installing it. The same applies to bin/, whose executables join the Bash tool's PATH while the plugin is enabled.

If a hook from a plugin misbehaves, the debugging path is the same as for your own: see why a hook is not firing, and remember that on Windows the shell is chosen for you, which breaks quoting in specific ways.

Distributing behaviour is not the same as seeing it

A plugin can register background monitors, spawn agents and fire hooks without you typing anything. That is the point of it, and it is also the reason a session running someone else's plugin is harder to read at a glance than one running your own commands.

Blooby works from the same hook events your plugins use, and turns them into something ambient: one mascot per Claude Code session on your taskbar, showing which session is working, which is blocked on a permission, and which is done, whoever wrote the code that got it there.

See it for yourself

download Get Blooby free