Plugins and Marketplace
Slash commands, skills, subagents, and hooks covered in previous articles live in the .claude/ directory of a project or user — they are personal and tied to a specific location. This works well for experimentation, but poorly for sharing: to give a colleague the same set of tools, you have to copy files manually. A plugin solves exactly this problem — it packages all components into a single versioned, installable, and distributable unit.
What a Plugin Is
A plugin is a regular directory with a defined structure. It can contain skills, subagents, hooks, MCP servers, LSP servers, background monitors, and binaries. Everything installs together with a single command and is removed just as easily. The key difference from a standalone configuration is intentional.
| Criterion | Standalone (.claude/) | Plugin |
|---|---|---|
| Scope | Single project | Multiple projects, team |
| Skills | /hello | /my-plugin:hello |
| Distribution | Manual | Via marketplace |
| Versioning | None | version in the manifest |
If you're still iterating — stay in .claude/. Once the configuration has stabilized and you want to share it with others — package it as a plugin.
The Manifest: .claude-plugin/plugin.json
The only required file in a plugin is the manifest. It lives strictly inside the .claude-plugin/ subdirectory (not at the root!) and describes the plugin's identity:
{
"name": "code-quality",
"description": "Автоформат, линт и проверка типов для TypeScript-проектов",
"version": "1.2.0",
"author": {
"name": "Ваша команда"
},
"homepage": "https://github.com/your-org/code-quality-plugin",
"repository": "https://github.com/your-org/code-quality-plugin",
"license": "MIT"
}The name field serves as both a unique identifier and a namespace prefix. A skill named review inside the code-quality plugin is invoked as /code-quality:review. This is by design — intentional namespacing prevents conflicts between plugins that have skills with identical names.
The version field is optional but important for update management: when set, users receive an update only when you increment it. Without it, every git commit is treated as a new version.
Plugin Directory Structure
code-quality/
├── .claude-plugin/
│ └── plugin.json ← only here, nothing else
├── skills/
│ └── review/
│ └── SKILL.md
├── agents/
│ └── strict-reviewer.md
├── hooks/
│ └── hooks.json ← hooks live here inside a plugin
├── .mcp.json ← MCP servers
├── settings.json ← default settings
└── bin/
└── my-linter ← added to PATHCommon mistake: placing skills/, agents/, or hooks/ inside .claude-plugin/. Only plugin.json belongs there. All working directories go at the plugin root.
Difference from standalone configuration: hooks are no longer described in settings.json — they live in hooks/hooks.json using the same JSON format. This lets you keep them inside the plugin itself without touching global settings.
flowchart TD
ROOT["code-quality/ (plugin root)"]
MANIFEST[".claude-plugin/\nplugin.json"]
SKILLS["skills/\nreview/SKILL.md"]
AGENTS["agents/\nstrict-reviewer.md"]
HOOKS["hooks/\nhooks.json"]
MCP[".mcp.json"]
SETTINGS["settings.json"]
BIN["bin/\nmy-linter"]
ROOT --> MANIFEST
ROOT --> SKILLS
ROOT --> AGENTS
ROOT --> HOOKS
ROOT --> MCP
ROOT --> SETTINGS
ROOT --> BIN
MANIFEST --> |"name, version, description, author"| NOTE1["Identity and namespace"]
HOOKS --> NOTE2["Format as in settings.json"]
MCP --> NOTE3["Connected on installation"]
SETTINGS --> NOTE4["Only agent and subagentStatusLine"]Creating a Plugin: From Scratch to Working State
The fastest path is claude plugin init:
claude plugin init my-toolThis command creates ~/.claude/skills/my-tool/ with a ready-made manifest and a starter SKILL.md. The plugin loads automatically on the next launch under the name my-tool@skills-dir — no marketplace or installation required.
For a more controlled approach — build the structure manually and test it using the --plugin-dir flag:
# Launch Claude Code with a local plugin
claude --plugin-dir ./code-quality
# You can attach multiple at once
claude --plugin-dir ./plugin-one --plugin-dir ./plugin-two
# Or test a zip archive (v2.1.128+)
claude --plugin-dir ./code-quality.zipWhile a plugin is loaded, the /reload-plugins command re-reads all files without restarting — saving time during development.
# Validate the plugin before publishing
claude plugin validatevalidate runs the same checks as the marketplace review pipeline. It's better to catch problems before submission than after.
MCP Servers and Settings in a Plugin
A plugin can provide MCP servers via an .mcp.json file at its root:
{
"mcpServers": {
"quality-db": {
"command": "npx",
"args": ["-y", "@your-org/quality-mcp-server"]
}
}
}This means installing the plugin automatically connects the required MCP server. The user does not need to separately run claude mcp add — everything arrives together.
The settings.json file at the plugin root lets you define default behavior. Supported keys are agent and subagentStatusLine. Through agent, you can designate one of the plugin's subagents as the active default:
{
"agent": "security-reviewer"
}When such a plugin is enabled, Claude Code will use the system prompt, tool restrictions, and model of that specific subagent.
Marketplace: From Local to Public
Anthropic maintains two public marketplaces:
claude-plugins-official— a curated set of plugins from Anthropic, registered automatically on first launch.claude-community— third-party plugins that have passed review. Connect it via/plugin marketplace add anthropics/claude-plugins-community.
For internal use, a team can create their own private marketplace — a plain git repository with a marketplace.json. Each project points to it in .mcp.json or settings, and all developers gain access to company plugins via /plugin install.
To submit a plugin to the community marketplace:
1. Run claude plugin validate — fix all errors
2. Submit via claude.ai/admin-settings/directory/submissions/plugins/new (Team/Enterprise) or platform.claude.com/plugins/submit (Console, for individuals)
3. After approval, the plugin is pinned to a specific commit SHA in the anthropics/claude-plugins-community catalog
Migrating a Standalone Configuration to a Plugin
If you already have skills and hooks in .claude/, repackaging them is straightforward. The key changes are:
# Create the structure
mkdir -p my-plugin/.claude-plugin
# Copy components
cp -r .claude/commands my-plugin/
cp -r .claude/agents my-plugin/
cp -r .claude/skills my-plugin/
# Hooks: extract from settings.json → my-plugin/hooks/hooks.json
mkdir my-plugin/hooks
# (move the "hooks" object from settings.json)After creating the plugin, remove the originals from .claude/ — otherwise you'll end up with duplicates. Important: subagent definitions in .claude/agents/ take priority over same-named agents from a plugin, so as long as the original is in place, the plugin version won't be used.
Practical Takeaway
A plugin is not a separate technology — it's a way to package everything covered in this section. A skill, subagent, hook, and MCP server remain exactly the same; a plugin simply adds a manifest, namespacing, and a distribution mechanism around them. It's the canonical answer to the question: "How do I share my Claude Code extensions with my team or the community?"
See also
- Slash Commands: Built-in and Custom — commands and skills inside a plugin follow the same rules as their standalone counterparts
- Skills — Portable Capabilities — the SKILL.md structure inside a plugin is identical
- Subagents and Context Isolation — a plugin can contain subagents and designate one as the active default
- Hooks — Lifecycle Events — inside a plugin, hooks live in
hooks/hooks.json, not insettings.json - Model Context Protocol: Architecture and Fundamentals — MCP servers in a plugin are connected via
.mcp.jsonand activated alongside the plugin - What to Choose: Command, Skill, Subagent, MCP, or Hook — a decision matrix for when to use a plugin instead of a standalone configuration
- Settings and Configuration Hierarchy — a plugin's
settings.jsonis applied on top of project and user settings