Plugins — One Install, Whole Workflow
Slash commands, skills, subagents, MCP servers, and hooks bundled into a single installable package — with marketplaces to distribute them, a manifest that does real work, and a context price tag you can read before you buy.
Six chapters of setup, copied by hand, is how teams drift — a plugin installs it all in one command
Manual setup means installing slash commands one by one, creating subagents individually, configuring MCPs separately, wiring hooks, documenting everything — 2+ hours, and you hope teammates configure it correctly. Plugins are bundled collections of customizations — slash commands, subagents, MCP servers, and hooks — that install with a single command: 2 minutes, and the team reproduces the exact setup.
- The highest-level extension mechanism — it bundles every feature from chapters 1–6 plus configuration
- /plugin install pr-review → 3 slash commands, 3 subagents, 2 MCP servers, 4 hooks — ready to use
- Four distribution tiers: Official (Anthropic, all users) · Community (public) · Organization (internal teams) · Personal (single developer)
A plugin is a directory with a manifest — every folder inside is a feature you already know
// .claude-plugin/plugin.json — the manifest { "name": "my-first-plugin", "description": "A greeting plugin", "version": "1.0.0", "author": { "name": "Your Name" }, "homepage": "https://example.com", "repository": "https://github.com/user/repo", "license": "MIT" }
Plus optional top-level dirs: templates/, scripts/, docs/, tests/, and themes/ (ship custom Claude Code themes, v2.1.118+).
| commands/ | Slash commands as Markdown files — chapter 1 |
| skills/ | Agent Skills with SKILL.md files — chapter 3 |
| agents/ | Custom subagent definitions — chapter 4 |
| .mcp.json | MCP server configurations — chapter 5 |
| hooks/hooks.json | Event handlers — chapter 6 |
| .lsp.json | LSP servers for code intelligence |
| bin/ | Executables added to the Bash tool's PATH |
| settings.json | Defaults applied when enabled (agent key) |
One command fans out into four configuration lanes — then converges to "ready"
The lifecycle continues after install: use → update (when available) → disable → re-enable — components come and go as a unit, never one by one.
Plugins namespace their commands — and trade manual copies for versioned installs
| Standalone /hello | Manual setup in CLAUDE.md — best for personal, project-specific workflows |
| Plugin /plugin-name:hello | Automated via plugin.json — best for sharing, distribution, team use |
Spaced invocation (v2.1.136+): /myplugin review resolves to the canonical /myplugin:review. Either form works; the colon form is recommended in scripts.
| Installation | Manual copy → one command |
| Setup time | 5–15 min per feature → 2 min total |
| Bundling | Single file each → multiple components |
| Versioning / updates | Manual → automatic, auto-available |
| Team sharing | Copy files around → install ID |
| Marketplace | No → yes |
Plugins handle secrets, state, monitors, and defaults — each through its own channel
| userConfig (v2.1.83+) | Declare user-configurable options — a description, an optional default, and "sensitive": true values stored in the system keychain rather than plain-text settings files (API keys belong here) |
| ${CLAUDE_PLUGIN_DATA} (v2.1.78+) | Per-plugin persistent state directory that survives across sessions — caches, databases, usage logs. Created on install, removed on uninstall; reference it in hook commands like node ${CLAUDE_PLUGIN_DATA}/track-usage.js |
| monitors (v2.1.105) | Background monitors that auto-arm — "trigger": "session_start" arms when a session begins, "skill_invoke" when the plugin's skill fires. Streams stdout lines as events Claude can react to |
| settings.json | Default settings applied on installation — currently the agent key, which sets the plugin's main-thread agent (e.g. "agent": "agents/specialist-1.md"). Users can override in their own config |
| source: "settings" (v2.1.80+) | Define a plugin inline in your settings file as a marketplace entry — no separate repository or marketplace needed for small local tools |
Plugins can ship a language server and a toolbox — diagnostics on every edit, binaries on PATH
.lsp.json — Language Server Protocol
{
"go": {
"command": "gopls",
"args": ["serve"],
"extensionToLanguage": {
".go": "go"
}
}
}
Once configured: instant diagnostics after edits, go-to-definition / find references, hover types, symbol listing. Optional fields tune transport, env, timeouts, and restartOnCrash. Official marketplace ships pyright-lsp, typescript-lsp, rust-lsp pre-configured.
bin/ — executables on the session PATH
my-plugin/
├── plugin.json
└── bin/
└── my-tool # chmod +x
# with the plugin enabled:
$ my-tool --help
While the plugin is enabled, bin/ is prepended to PATH — hooks, skills, and commands in the same plugin can shell out to its helpers by bare name. Mark files executable in the repo; git preserves the bit.
Three recent changes made a skill the lightest possible plugin
| skills/ merge (v2.1.136+) | A skills entry in plugin.json no longer hides the plugin's default skills/ directory — skills declared in both places are merged, so you can list a few highlights in the manifest without losing the rest |
| Root SKILL.md (v2.1.142+) | A plugin with a top-level SKILL.md and no skills/ subdirectory is itself surfaced as a single skill — the plugin is the skill. An additional pattern for small single-skill plugins where directory layout adds no value |
| No marketplace needed (v2.1.157+) | Plugins placed in .claude/skills directories auto-load without a marketplace. claude plugin init <name> scaffolds a new one |
The pr-review plugin: one command orchestrates a hook, an MCP server, and three subagents
pr-review/ ├── .claude-plugin/plugin.json ├── commands/ │ ├── review-pr.md │ ├── check-security.md │ └── check-tests.md ├── agents/ │ ├── security-reviewer.md │ ├── test-checker.md │ └── performance-analyzer.md ├── mcp/github-config.json └── hooks/pre-review.js
Each agent is ~10 lines of frontmatter + focus areas; the GitHub MCP config reads ${GITHUB_TOKEN} from the environment — never hardcoded.
What /review-pr actually runs
- pre-review.js hook validates you're in a git repo, warns on uncommitted changes
- GitHub MCP fetches the PR data
- security-reviewer, test-checker, performance-analyzer each analyze their slice
- Findings synthesized: ✅ security clean · ⚠️ coverage 65%, recommend 80%+ · ✅ no perf impact · 📝 12 recommendations
The chapter ships three complete plugins — each a different mix of the same parts
1pr-review
3 commands (/review-pr, /check-security, /check-tests) · 3 subagents · GitHub MCP · pre-review hook. Requires a GitHub token via export GITHUB_TOKEN.
2devops-automation
4 commands (/deploy, /rollback, /status, /incident) · 3 subagents (deployment-specialist, incident-commander, alert-analyzer) · Kubernetes MCP · shell scripts (deploy, rollback, health-check) · pre/post-deploy hooks.
3documentation
4 commands (/generate-api-docs, /generate-readme, /sync-docs, /validate-docs) · 3 subagents · GitHub docs MCP · templates: api-endpoint, function-docs, ADR.
Note the third shape: documentation bundles templates as a first-class component — plugins can ship reference material, not just executable parts.
A marketplace is just a repo with marketplace.json — official, community, or private
// .claude-plugin/marketplace.json { "name": "my-team-plugins", "owner": "my-org", "plugins": [ { "name": "code-standards", "source": "./plugins/code-standards", "version": "1.2.0" }, { "name": "deploy-helper", "source": { "source": "github", "repo": "my-org/deploy-helper", "ref": "v2.0.0" } } ] }
- The official Anthropic-managed directory is anthropics/claude-plugins-official; enterprise admins can run private marketplaces for internal distribution
- Required fields: name, owner, plugins[] with name + source each — description, version, author are optional
- Strict mode: strict: true (default) — the local plugin.json is authoritative and the marketplace entry supplements it; strict: false — the marketplace entry is the entire plugin definition
Six places a marketplace can pull a plugin from — all pinnable to a version
| Relative path | "./plugins/my-plugin" — plugin lives in the marketplace repo itself |
| GitHub | { "source": "github", "repo": "acme/lint-plugin", "ref": "v1.0" } |
| Git URL | { "source": "url", "url": "https://git.internal/plugin.git" } — any git host |
| Git subdirectory | { "source": "git-subdir", "url": "…/monorepo.git", "path": "packages/plugin" } — one plugin out of a monorepo |
| npm | { "source": "npm", "package": "@acme/claude-plugin", "version": "^2.0" } |
| pip | { "source": "pip", "package": "claude-data-plugin", "version": ">=1.0" } |
GitHub and git sources accept optional ref (branch/tag) and sha (commit hash) for version pinning — reproducible environments. Plugins can also specify custom npm registries, and the default git timeout is 120 s for large plugin repositories.
Distribution is "add my repo"; publishing adds a tag, a review, and a one-command install
Getting your marketplace to users
# GitHub (recommended) /plugin marketplace add owner/repo-name # other git services — full URL /plugin marketplace add \ https://gitlab.com/org/marketplace-repo.git
Private repositories work via git credential helpers or environment tokens — users need read access. Official-marketplace submissions go through claude.ai/settings/plugins/submit or platform.claude.com/plugins/submit.
The publishing path
- Build the structure + plugin.json, write a README documenting components and requirements
- Test locally with claude --plugin-dir ./my-plugin
- Cut the release with claude plugin tag v0.3.0 (v2.1.118+) — validates the version format and creates the matching git tag
- Submit → review → approval → published; users install with one command
Every plugin charges context rent per turn — and you can read the bill before installing
The /plugin marketplace browser shows each plugin's projected per-turn context-token cost (v2.1.143) — the sum of its always-loaded skills, hooks, and MCP server descriptors:
Everything has a CLI form — and two commands that sound alike do different things
| install <name>@<mkt> | Install from a marketplace |
| uninstall / update / list | Remove · update to latest · list installed |
| enable / disable | Toggle without uninstalling (auto-detected scope) |
| validate | Check plugin structure before publishing |
| tag <version> | Release tag with version validation (v2.1.118+) |
| prune | Remove orphaned auto-installed dependencies (v2.1.121+); uninstall --prune cascades in one step |
| details <name> | Inventory + projected token cost (v2.1.139+) |
Dependency enforcement (v2.1.143)
- plugin disable refuses if another enabled plugin still depends on the target — the dependency graph can't be broken
- plugin enable force-enables transitive dependencies after a single confirmation prompt
- In-session equivalents exist too: /plugin list, /plugin info, /plugin install ./local-path, /plugin install github:username/repo
--plugin-dir loads your work-in-progress; /reload-plugins picks up edits without restarting
# load one or many local plugins claude --plugin-dir ./my-plugin claude --plugin-dir ./a --plugin-dir ./b # .zip archives work too (v2.1.128+) claude --plugin-dir ./my-plugin.zip # fetch a .zip from a URL (v2.1.129+) claude --plugin-url \ https://example.com/releases/my-plugin-0.3.0.zip # after editing plugin files mid-session /reload-plugins
The test checklist
- All slash commands available · subagents function · MCP servers connect · hooks execute · LSP configs load · no config errors
- /reload-plugins re-reads all manifests, commands, agents, skills, hooks, and MCP/LSP configs — plugins also support change auto-detection
- First diagnostics when something won't load: plugin.json paths match the actual directory layout · scripts are chmod +x · JSON validates · /plugin debug name shows the logs
Official plugins update themselves at startup — everything else waits for you
| claude-plugins-official | Auto-update ✅ enabled by default |
| Third-party / local | Auto-update ❌ disabled by default |
| Toggle | /plugin → Marketplaces → Select |
When auto-update runs it: 1) refreshes the marketplace catalog, 2) updates installed plugins to latest, 3) shows a notification prompting /reload-plugins.
| DISABLE_AUTOUPDATER=1 | Disable all auto-updates — Claude Code and plugins |
| + FORCE_AUTOUPDATE_PLUGINS=1 | Keep plugin updates while Claude Code updates stay off |
| CLAUDE_CODE_PLUGIN_PREFER_HTTPS=1 | (v2.1.141+) Clone GitHub plugin sources over HTTPS instead of SSH — for CI runners and containers without SSH keys |
Admins control what installs; the sandbox controls what installed plugins can do
Managed settings (org-level)
| enabledPlugins | Allowlist enabled by default |
| deniedPlugins | Blocklist — cannot be installed |
| extraKnownMarketplaces | Additional marketplaces made available to users |
| strictKnownMarketplaces | Not set = any · [] = lockdown · patterns = allowlist (e.g. "my-org/*"). Managed-only |
| blockedMarketplaces | Blocklist; hostPattern / pathPattern regex since v2.1.119 |
| allowedChannelPlugins | Permitted plugins per release channel |
Enforced on every lifecycle event since v2.1.117 — install, update, refresh, and autoupdate, not just at first add. Managed settings take precedence over user-level settings.
The plugin-subagent sandbox
- Plugin subagents run restricted — three frontmatter keys are banned in their definitions:
- hooks — can't register event handlers
- mcpServers — can't configure MCP servers
- permissionMode — can't override the permission model
So a plugin can't escalate privileges or modify the host environment beyond its declared scope — what you saw in the manifest is what it gets.
A plugin earns its weight with multiple components or a team — otherwise use the smaller tool
| Team onboarding | ✅ Plugin — instant setup, all configurations |
| Framework setup | ✅ Plugin — bundles framework-specific commands |
| Enterprise standards | ✅ Plugin — central distribution, version control |
| Quick task automation | ❌ Command — plugin is overkill complexity |
| Single domain expertise | ❌ Skill — too heavy as a plugin |
| Specialized analysis | ❌ Subagent — create manually or use a skill |
| Live data access | ❌ MCP — keep standalone, don't bundle |
The don'ts that bite
- Don't bundle unrelated features — keep plugins focused and cohesive
- Don't hardcode credentials — env vars or userConfig sensitive values
- Don't skip versioning — semver properly; maintain backward compatibility
- Don't ship untested — test all components together, document dependencies and requirements
Plugins are the distribution layer — everything you've built becomes something you can hand over
A plugin is a directory: .claude-plugin/plugin.json plus the commands, skills, agents, MCP servers, hooks, LSP configs, and bin/ tools you already know — installed in one command, namespaced as /plugin:command, updated as a unit. The manifest carries real machinery (keychain-backed userConfig, persistent data, background monitors). Marketplaces are just repos with marketplace.json, pulling plugins from paths, git, npm, or pip — pinnable by sha, governed by managed settings, and priced in context tokens per turn that you can read before installing. Develop with --plugin-dir, reload with /reload-plugins, release with plugin tag.