Plugin Authoring — Official Best Practices
What Plugins Do
Plugins bundle skills, agents, hooks, and MCP servers into shareable packages. Skills get namespaced: /plugin-name:skill-name.
Directory Structure
my-plugin/
├── .claude-plugin/
│ └── plugin.json # Manifest (ONLY file inside .claude-plugin/)
├── skills/ # Agent Skills with SKILL.md
│ └── code-review/
│ └── SKILL.md
├── commands/ # Skills as simple Markdown files
│ └── review.md
├── agents/ # Custom agent definitions
│ └── reviewer.md
├── hooks/
│ └── hooks.json # Hook configurations
├── .mcp.json # MCP server configurations
├── .lsp.json # LSP server configurations
├── settings.json # Default settings (only "agent" key supported)
└── README.md # DocumentationCritical: skills/, agents/, hooks/ go at plugin root, NOT inside .claude-plugin/.
plugin.json Manifest
See quick-ref/manifest-schema.md for the complete schema.
{
"name": "my-plugin",
"description": "A code quality plugin with review skills and formatting hooks",
"version": "1.0.0",
"author": {
"name": "Your Name"
},
"homepage": "https://github.com/user/my-plugin",
"repository": "https://github.com/user/my-plugin",
"license": "MIT"
}name: unique identifier, becomes skill namespace prefixversion: semantic versioning (MAJOR.MINOR.PATCH)- Only
nameanddescriptionare required
Namespacing
Plugin skills are prefixed: /my-plugin:hello, /my-plugin:review. This prevents conflicts between plugins with same skill names.
Plugin Components
Skills in plugins
Same as standalone skills but in plugin-root/skills/. Each needs SKILL.md with frontmatter.
Agents in plugins
Same Markdown format as .claude/agents/. Placed in plugin-root/agents/.
Hooks in plugins
Create hooks/hooks.json — same format as hooks in settings.json:
{
"hooks": {
"PostToolUse": [{
"matcher": "Write|Edit",
"hooks": [{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs prettier --write" }]
}]
}
}MCP servers in plugins
Configure in .mcp.json at plugin root. Use ${CLAUDE_PLUGIN_ROOT} for relative paths:
{
"my-server": {
"command": "${CLAUDE_PLUGIN_ROOT}/servers/my-server",
"args": ["--config", "${CLAUDE_PLUGIN_ROOT}/config.json"],
"env": { "API_KEY": "${API_KEY}" }
}
}Default settings
settings.json at plugin root — currently only agent key supported:
{ "agent": "security-reviewer" }This activates the named agent as main thread when plugin is enabled.
Development & Testing
# Test locally (no install needed)
claude --plugin-dir ./my-plugin
# Multiple plugins
claude --plugin-dir ./plugin-one --plugin-dir ./plugin-two
# Verify components
/help # Skills listed under namespace
/agents # Agents visible
/mcp # MCP servers runningChanges require restart to take effect.
Distribution
- Version control — push to Git repository
- Plugin marketplace — submit via claude.ai/settings/plugins/submit
- Team sharing — configure team marketplace in
.claude/plugins.json
When Plugin vs Standalone
| Standalone | Plugin |
|---|---|
| Personal workflow | Sharing with team/community |
| Single project | Reusable across projects |
| Quick experiments | Versioned releases |
Short names (/hello) | Namespaced (/plugin:hello) |
Tip: Start standalone in .claude/, convert to plugin when ready to share.
Anti-Patterns
| Anti-Pattern | Fix |
|---|---|
Components inside .claude-plugin/ | Only plugin.json goes there; rest at root |
| No description in plugin.json | Required for discovery |
| Hardcoded paths in MCP config | Use ${CLAUDE_PLUGIN_ROOT} |
| Missing README | Add docs for users installing the plugin |
Checklist
.claude-plugin/plugin.jsonwith name, description, version- Components at plugin root (not inside.claude-plugin/)
- Skills have proper SKILL.md with frontmatter
- MCP configs use
${CLAUDE_PLUGIN_ROOT}for paths - Tested with
--plugin-dir - README.md with installation instructions
- Semantic versioning