17 KiB
name, description
| name | description |
|---|---|
| box-factory-plugin-design | Interpretive guidance for designing Claude Code plugins. Helps you understand plugin architecture, marketplace distribution, and when plugins are the right pattern. Use when creating or reviewing plugins. |
Plugin Design Skill
This skill provides interpretive guidance and best practices for creating Claude Code plugins. ALWAYS fetch current official documentation before creating plugins - this skill helps you understand what the docs mean and how to create excellent plugins.
Required Reading Before Creating Plugins
Fetch these docs with WebFetch every time:
- https://code.claude.com/docs/en/plugins - Plugin overview and quickstart
- https://code.claude.com/docs/en/plugins-reference - Complete specifications
- https://code.claude.com/docs/en/plugin-marketplaces - Distribution patterns
Core Understanding
Plugins Are Packaging, Not Functionality
Key insight: Plugins don't add new capabilities to Claude Code. They package existing extension points (commands, agents, skills, hooks, MCP servers) for distribution.
What this means:
- Plugins bundle components together
- The value is distribution and discoverability
- Components work the same inside or outside plugins
- You're organizing and sharing, not creating new primitives
Decision test: If you're asking "should this be a plugin?", you're asking the wrong question. Ask "should I package these existing components for sharing?"
Critical Directory Structure (Official Specification)
The #1 mistake that causes plugins to install but not work:
✅ Correct:
plugin-name/
├── .claude-plugin/
│ └── plugin.json ← Only metadata here
├── commands/ ← At plugin root
├── agents/ ← At plugin root
├── skills/ ← At plugin root
└── hooks/ ← At plugin root
❌ Wrong (won't work):
plugin-name/
└── .claude-plugin/
├── plugin.json
├── commands/ ← Won't be found!
└── agents/ ← Won't be found!
Official docs say: "All other directories (commands/, agents/, skills/, hooks/) must be at the plugin root, not inside .claude-plugin/."
Skills Directory Structure
Skills use subdirectories with a SKILL.md file:
skills/
├── skill-one/
│ ├── SKILL.md ← Skill definition
│ └── helpers.py ← Supporting files (optional)
└── skill-two/
└── SKILL.md
Plugin Manifest (plugin.json) - Official Specification
Located at .claude-plugin/plugin.json:
Required Fields
- name: Unique identifier in kebab-case (e.g., "deployment-tools")
Optional Metadata Fields We Use
| Field | Type | Purpose |
|---|---|---|
| version | string | Semantic versioning (e.g., "2.1.0") |
| description | string | Brief plugin purpose explanation |
| repository | string | Source code location |
Optional Metadata Fields We NEVER Use
| Field | Type | Purpose |
|---|---|---|
| author | object | Author details: {name, email, url} |
| homepage | string | Documentation URL |
| license | string | License identifier (MIT, Apache-2.0, etc.) |
| keywords | array | Discovery tags for categorization |
Component Path Fields (Optional)
Override default locations:
- commands: Additional command files/directories (string or array)
- agents: Agent markdown files (string or array)
- hooks: Hook configuration path or inline JSON
- mcpServers: MCP server configuration path or inline JSON
Note: Custom paths supplement default directories, they don't replace them.
Best practice: Always include description and version even though they're optional - improves discoverability and user trust. Do NOT include author, repository, homepage, license, or keywords unless explicitly specified.
Advanced Features (Official Specification)
Environment Variables
Use ${CLAUDE_PLUGIN_ROOT} in paths to reference the plugin's absolute directory.
Custom Component Paths
Specify additional locations for components:
{
"name": "my-plugin",
"commands": ["./extra-commands", "./legacy/commands"],
"agents": "./custom-agents"
}
All paths must be relative to plugin root and start with ./
Inline Component Configuration
Define hooks or MCP servers directly in plugin.json instead of separate files:
{
"name": "my-plugin",
"hooks": {
"PreToolUse:Bash": "./hooks/bash-guard.sh"
},
"mcpServers": {
"custom-server": {
"command": "node",
"args": ["./server.js"]
}
}
}
MCP Server Configuration (Best Practices)
CRITICAL: When configuring MCP servers in plugins, follow these security and maintainability patterns.
Always Use External Configuration Files
✅ CORRECT - External file:
// plugin.json
{
"name": "my-plugin",
"mcpServers": "./.mcp.json"
}
// .mcp.json (at plugin root)
{
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}"
}
}
}
❌ WRONG - Inline configuration:
{
"name": "my-plugin",
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": ""
}
}
}
}
Why external files are better:
- Separation of concerns (metadata vs configuration)
- Easier to edit MCP config independently
- Cleaner plugin.json focused on plugin metadata
- Matches user expectations from standalone MCP setups
Always Use Environment Variable References
✅ CORRECT - Environment variable reference:
{
"server-name": {
"command": "server-binary",
"env": {
"API_KEY": "${API_KEY}",
"AUTH_TOKEN": "${AUTH_TOKEN}",
"DATABASE_URL": "${DATABASE_URL}"
}
}
}
❌ WRONG - Hardcoded empty strings:
{
"server-name": {
"env": {
"API_KEY": "",
"AUTH_TOKEN": "",
"DATABASE_URL": ""
}
}
}
❌ VERY WRONG - Hardcoded actual secrets:
{
"server-name": {
"env": {
"API_KEY": "sk_live_abc123..."
}
}
}
Why environment variables are critical:
- Security: Never commit secrets to git history
- Portability: Different users/environments have different credentials
- Standard practice:
${VAR_NAME}is the established MCP pattern - Documentation clarity: Shows what env vars are required
Document Required Environment Variables
In your README, always include:
## MCP Server Setup
This plugin includes the [Server Name] MCP server.
### Prerequisites
- [Tool requirements, e.g., Node.js, Python]
- [Service account or API access]
### Configuration
1. Obtain credentials:
- Visit [credential URL]
- Create [token/API key] with `scope1`, `scope2` permissions
2. Set environment variables:
```bash
export API_KEY="your_key_here"
export AUTH_TOKEN="your_token_here"
- The MCP server will start automatically when the plugin is enabled
**Required documentation elements:**
- Prerequisites (tools, accounts, permissions)
- How to obtain credentials with specific scopes/permissions
- Exact environment variable names to set
- Example export commands
- When the server starts (usually: when plugin enabled)
#### Common MCP Server Types
**GitHub:**
```json
{
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}"
}
}
}
Filesystem:
{
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/allowed/path"],
"env": {}
}
}
Database:
{
"database": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"DATABASE_URL": "${DATABASE_URL}"
}
}
}
Custom server using plugin root:
{
"custom": {
"command": "${CLAUDE_PLUGIN_ROOT}/servers/custom-server",
"args": ["--config", "${CLAUDE_PLUGIN_ROOT}/config.json"],
"env": {
"CUSTOM_API_KEY": "${CUSTOM_API_KEY}"
}
}
}
MCP Configuration Checklist
Before publishing plugin with MCP servers:
Security:
- ✓ All secrets use
${ENV_VAR}references (never hardcoded) - ✓ No empty string placeholders for secrets
- ✓ No actual credentials in git history
- ✓ .env files in .gitignore if used for local testing
Structure:
- ✓ MCP configuration in external file (
.mcp.jsonor custom path) - ✓ Path in plugin.json is relative and starts with
./ - ✓ Valid JSON syntax in MCP configuration file
Documentation:
- ✓ README explains how to obtain credentials
- ✓ Required scopes/permissions documented
- ✓ Environment variable names clearly listed
- ✓ Example export commands provided
- ✓ Troubleshooting section for common issues
Testing:
- ✓ Verified MCP server starts with plugin enabled
- ✓ Tested with actual credentials in environment
- ✓ Confirmed required tools/dependencies work
Marketplace Distribution (Official Specification)
Marketplace.json Structure
Located at .claude-plugin/marketplace.json:
Required fields:
- name: Marketplace identifier (kebab-case)
- owner: Maintainer information object
- plugins: Array of plugin entries
Plugin entry fields:
{
"name": "plugin-name",
"source": "./plugins/plugin-name",
"description": "Optional override",
"strict": true
}
Source Types
Local path (development):
"source": "./plugins/my-plugin"
GitHub repository:
"source": {
"source": "github",
"repo": "owner/repo"
}
Git URL:
"source": {
"source": "url",
"url": "https://gitlab.com/user/plugin.git"
}
The strict Field
strict: true(default): Plugin must have its ownplugin.jsonstrict: false: Marketplace entry serves as complete manifest
Use strict: false when: Packaging third-party content without modifying it.
Decision Framework
When to Create a Plugin
Create plugin when:
- You have multiple related components (commands + agents + hooks)
- You want to share with team/community
- You need versioning and distribution
- You want one-command installation (
/plugin install)
Don't create plugin when:
- Single command/agent (just share the file)
- Personal workflow (no distribution need)
- Rapid iteration (plugins add packaging overhead)
- Testing concepts (develop components first, package later)
Plugin Scope Philosophy (Best Practices)
Good plugin scope:
- Focused purpose (testing suite, security scanner, docs generator)
- Related components work together
- Clear value proposition
- Composable with other plugins
Bad plugin scope:
- "Everything for development" (too broad)
- Unrelated utilities thrown together
- Duplicates core functionality
- Conflicts with other plugins
Development Workflow (Best Practices)
The docs show the mechanics. Here's the philosophy:
- Build components first - Create and test commands/agents individually
- Test without packaging - Use
.claude/directories for iteration - Package when ready - Add plugin.json and organize structure
- Validate locally - Use
claude plugin validate .command - Create test marketplace - Local marketplace with absolute paths
- Install and test -
/plugin marketplace add ./path/to/marketplace - Iterate - Fix issues, restart Claude Code, test again
- Document - Write comprehensive README
- Publish - Push to GitHub, share marketplace
Key insight: Don't start with plugin structure. Build components, then package them.
Testing Commands (Official Specification)
Validate plugin structure:
claude plugin validate .
Checks JSON syntax and directory structure.
Add local marketplace for testing:
/plugin marketplace add ./absolute/path/to/marketplace
Install from local marketplace:
/plugin install plugin-name@marketplace-name
Verify installation:
Check /help for newly installed commands and agents.
Common Pitfalls (Best Practices)
Pitfall #1: Components in Wrong Directory
Problem: Putting commands/agents inside .claude-plugin/
Why it fails: Claude Code only looks at plugin root for components
Solution: Keep .claude-plugin/ for metadata only, put all components at root
Pitfall #2: Premature Pluginification
Problem: Creating plugin for single command or concept
Why it fails:
- Overhead of marketplace setup
- Harder to iterate quickly
- Users just want the file
- More complex to maintain
Better: Share the markdown file directly, create plugin later if collection grows
Pitfall #3: Kitchen Sink Plugin
Problem: "All my utilities" plugin with unrelated components
Why it fails:
- Unclear purpose
- Users only want subset
- Hard to maintain and version
- Discovery problems
Better: Focused plugins (testing tools, git helpers, docs generators)
Pitfall #4: Missing Documentation
Problem: Plugin without README or usage examples
Why it fails:
- Users don't know what's included
- No installation instructions
- No troubleshooting guidance
- Low adoption
Solution: Comprehensive README with:
- Installation steps
- Component list with examples
- Required dependencies
- Troubleshooting section
- Changelog
Pitfall #5: Ignoring Semantic Versioning
Problem: Breaking changes in minor/patch versions
Why it fails: Users expect:
1.0.0 → 1.0.1- Bug fixes only, safe to auto-update1.0.0 → 1.1.0- New features, backward compatible1.0.0 → 2.0.0- Breaking changes, needs migration
Solution: Follow semver strictly, document breaking changes
Marketplace Organization (Best Practices)
Embedded vs External Plugins
Embedded (monorepo approach):
marketplace/
├── .claude-plugin/marketplace.json
└── plugins/
├── plugin-one/
└── plugin-two/
Pros:
- Single source of truth
- Atomic updates
- Easier testing
Cons:
- Monorepo management overhead
- Slower independent development
External (distributed approach):
{
"plugins": [
{
"name": "plugin-one",
"source": {
"source": "github",
"repo": "org/plugin-one"
}
}
]
}
Pros:
- Independent versioning
- Faster iteration
- Individual repos easier to manage
Cons:
- Dependency coordination
- Potential version conflicts
Team Distribution Strategy
Official mechanism: Configure .claude/settings.json at repository level:
{
"extraKnownMarketplaces": ["owner/marketplace-repo"],
"enabledPlugins": ["plugin-name@marketplace-name"]
}
Best practices to consider:
- Test plugins thoroughly before team rollout
- Document required environment variables
- Have rollback plan if plugin breaks
- Establish approval process for new plugins
- Communicate plugin updates to team
Plugin Quality Checklist
Before publishing:
Structure (from official docs):
- ✓ Valid
plugin.jsonat.claude-plugin/plugin.json - ✓ Components at plugin root (not in
.claude-plugin/) - ✓ Proper directory names (commands, agents, skills, hooks)
- ✓
claude plugin validate .passes - ✓ Relative paths start with
./
Metadata (best practices):
- ✓ Descriptive name (kebab-case)
- ✓ Clear description (what problem it solves)
- ✓ Semantic versioning
- ✓ Author info (for support)
- ✓ Repository link (for issues/PRs)
- ✓ Keywords for discovery
Documentation (best practices):
- ✓ Comprehensive README
- ✓ Installation instructions
- ✓ Usage examples for each component
- ✓ Required dependencies documented
- ✓ Troubleshooting section
- ✓ Changelog
Design (best practices):
- ✓ Focused scope (clear purpose)
- ✓ No duplication of core functionality
- ✓ Components complement each other
- ✓ Tested locally before publishing
Example: High-Quality Plugin Manifest
Basic (what docs show):
{
"name": "my-plugin",
"description": "A plugin",
"version": "1.0.0"
}
Issues:
- ❌ Vague description
Excellent (applying best practices):
{
"name": "python-testing-suite",
"version": "1.0.0",
"description": "Comprehensive Python testing tools with pytest integration, coverage reporting, and failure analysis",
"repository": "https://github.com/username/python-testing-suite",
}
Improvements:
- ✅ Specific description (what it does, how it helps)
- ✅ (optional, but okay)Repository for issues and PRs
Documentation References
These are the authoritative sources. Fetch them before creating plugins:
Plugin creation:
- https://code.claude.com/docs/en/plugins - Overview and quickstart
Complete specifications:
- https://code.claude.com/docs/en/plugins-reference - All schemas and patterns
Distribution:
- https://code.claude.com/docs/en/plugin-marketplaces - Marketplace setup
Component specifications:
- Reference agent-design, slash-command-design skills for component details
Remember: Official docs provide structure and features. This skill provides best practices and patterns for creating excellent plugins.