name: claude-code-plugin-development description: This skill should be used when the user asks to "create a plugin", "build a plugin", "write a plugin", or wants to bundle agents, hooks, commands, skills, or MCP servers into a distributable Claude Code plugin.
Claude Code Plugin Development
Create distributable plugins that bundle commands, agents, skills, hooks, MCP servers, and LSP servers.
Official docs: https://code.claude.com/docs/en/plugins-reference
Quick Reference
You MUST read these references for detailed schemas and examples:
- Plugin Manifest - Complete plugin.json schema
- Plugin Components - Commands, agents, skills, hooks, MCP, LSP
- CLI Commands - Install, uninstall, enable, disable, update
- Debugging - Common issues and troubleshooting
Plugin Structure
my-plugin/
├── .claude-plugin/
│ └── plugin.json # Required manifest
├── commands/ # Slash commands (.md files)
├── agents/ # Subagents (.md files)
├── skills/ # Skills (subdirs with SKILL.md)
├── hooks/
│ └── hooks.json # Hook configuration
├── .mcp.json # MCP server definitions
├── .lsp.json # LSP server configurations
└── scripts/ # Hook and utility scripts
Important: Components go at plugin root, NOT inside .claude-plugin/. Only plugin.json belongs in .claude-plugin/.
Marketplace Structure
A marketplace can contain multiple plugins. The marketplace root has its own .claude-plugin/marketplace.json:
my-marketplace/
├── .claude-plugin/
│ └── marketplace.json # Lists all plugins in this marketplace
├── plugins/
│ ├── plugin-a/
│ │ ├── .claude-plugin/
│ │ │ └── plugin.json
│ │ └── skills/
│ └── plugin-b/
│ ├── .claude-plugin/
│ │ └── plugin.json
│ └── commands/
marketplace.json
{
"name": "my-marketplace",
"owner": {
"name": "author-name"
},
"plugins": [
{
"name": "plugin-a",
"source": "./plugins/plugin-a",
"description": "First plugin description",
"version": "1.0.0"
},
{
"name": "plugin-b",
"source": "./plugins/plugin-b",
"description": "Second plugin description",
"version": "0.2.0"
}
]
}
Critical: When adding a new plugin to a marketplace:
- Add it to
marketplace.jsonor it won't be installable - If using release-please, add a jsonpath entry to the config for the new plugin's version
Minimal plugin.json
{
"name": "my-plugin",
"version": "1.0.0",
"description": "Brief plugin description"
}
Installation Scopes
| Scope | Location | Use case |
|---|---|---|
| user | ~/.claude/settings.json | Personal plugins (default) |
| project | .claude/settings.json | Team plugins via version control |
| local | .claude/settings.local.json | Project-specific, gitignored |
| managed | managed-settings.json | Read-only managed plugins |
Environment Variables
Use ${CLAUDE_PLUGIN_ROOT} for paths in hooks and MCP configs:
{
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh"
}
Plugin Components Summary
| Component | Location | Format |
|---|---|---|
| Commands | commands/ | Markdown with frontmatter |
| Agents | agents/ | Markdown with frontmatter |
| Skills | skills/*/SKILL.md | Directories with SKILL.md |
| Hooks | hooks/hooks.json | JSON configuration |
| MCP servers | .mcp.json | MCP server config |
| LSP servers | .lsp.json | Language server config |
CLI Quick Reference
# Install
claude plugin install <plugin>@<marketplace> --scope user
# Manage
claude plugin enable <plugin>
claude plugin disable <plugin>
claude plugin update <plugin>
claude plugin uninstall <plugin>
# Debug
claude --debug
Permissions
Problem: Using ! backticks to run plugin scripts fails with permission error:
Error: Bash command permission check failed for pattern
"!`${CLAUDE_PLUGIN_ROOT}/scripts/my-script.sh 2>&1 || true`":
This Bash command contains multiple operations.
Cause: ! backticks have their own permission model separate from allowed-tools. Complex commands or scripts fail.
Solution: Use the Bash tool instead of ! backticks for scripts:
---
allowed-tools: Bash(${CLAUDE_PLUGIN_ROOT}/scripts/my-script.sh:*)
---
Run the script:
```bash
${CLAUDE_PLUGIN_ROOT}/scripts/my-script.sh
```
Simple git commands still work with ! backticks: !git branch --show-current``
Common Issues
Plugin installed but commands don't appear?
The plugin may be disabled. Check ~/.claude/settings.json:
"enabledPlugins": {
"my-plugin@my-marketplace": false // ← Disabled!
}
Fix with: claude plugin enable my-plugin@my-marketplace then restart Claude Code.
Local changes not picked up?
Use claude plugin update <plugin> or do a full reinstall:
claude plugin marketplace remove my-marketplace
claude plugin marketplace add ./
claude plugin install my-plugin@my-marketplace
Important
After creating or modifying plugins, inform the user:
Plugin changes take effect immediately after installation. Use
claude --debugto verify plugin loading.
Checklist
Before finalizing a plugin:
-
plugin.jsonhas name, version, description - Components at plugin root (not in
.claude-plugin/) - All paths use
${CLAUDE_PLUGIN_ROOT}variable - Scripts are executable (
chmod +x) - If part of a marketplace, plugin is listed in
marketplace.json - If using release-please, add jsonpath for new plugin version in config
- Test with
claude --debugto verify loading