Plugin Development Complete Guide
Building Claude Code plugins means creating directories, manifests, and markdown files that extend Claude's capabilities through commands, skills, agents, and hooks.
Plugin Anatomy
Every plugin follows this directory structure:
my-plugin/
├── .claude-plugin/
│ └── plugin.json # Manifest (REQUIRED)
├── commands/ # Slash commands
│ ├── index.json # Command index (optional)
│ └── my-command.md
├── skills/ # Knowledge packs
│ ├── skill-name/
│ │ └── SKILL.md
│ └── another-skill/
│ └── SKILL.md
├── agents/ # Specialized workers
│ ├── index.json # Agent index (optional)
│ ├── my-agent.md
│ └── another-agent.md
├── hooks/ # Lifecycle scripts
│ ├── hooks.json # Hook configuration
│ ├── my-hook.sh
│ └── scripts/
│ └── helper.sh
├── mcp-server/ # Optional: custom MCP server
│ ├── src/
│ │ └── index.js
│ ├── package.json
│ └── dist/
├── CLAUDE.md # Plugin routing guide (recommended)
├── CONTEXT_SUMMARY.md # Bootstrap context (recommended, 700 tokens max)
└── README.md # Marketplace documentation
Manifest Schema (plugin.json)
Located at .claude-plugin/plugin.json, the manifest defines plugin identity, permissions, and capabilities.
Required Fields
| Field | Type | Example |
|-------|------|---------|
| $schema | string | "https://claude.local/schemas/plugin.schema.json" |
| name | string | "my-awesome-plugin" |
| version | string | "1.0.0" (semver) |
| description | string | One-line summary (50-80 chars) |
| author.name | string | Your name or org |
| license | string | "MIT" or other SPDX |
| permissions.requires | string[] | Minimum permissions needed |
Example Manifest
{
"$schema": "https://claude.local/schemas/plugin.schema.json",
"name": "my-awesome-plugin",
"version": "1.0.0",
"description": "Does something amazing with Claude Code",
"author": {
"name": "Your Name"
},
"license": "MIT",
"repository": "https://github.com/user/my-awesome-plugin",
"keywords": [
"automation",
"productivity",
"development"
],
"permissions": {
"requires": [
"read",
"write"
],
"optional": [
"bash",
"agent",
"mcp"
]
},
"capabilities": {
"provides": [
"my-custom-capability"
],
"requires": []
},
"contextEntry": "CONTEXT_SUMMARY.md",
"context": {
"entry": "CONTEXT_SUMMARY.md",
"title": "My Awesome Plugin",
"summary": "Essential context for using the plugin",
"tags": [
"automation",
"claude-code"
],
"bootstrapFiles": [
"CONTEXT_SUMMARY.md"
],
"maxTokens": 700,
"excludeGlobs": [
"**/node_modules/**",
"**/.git/**"
],
"lazyLoadSections": [
"CLAUDE.md",
"commands/advanced.md",
"skills/expert-mode/SKILL.md"
]
}
}
Manifest Fields Explained
$schema: Validates against Claude's plugin schema. Use as shown above.
name: Unique identifier (lowercase, hyphens). Used in claude plugin install commands.
version: Semantic versioning. Increment when publishing updates (1.0.0 → 1.0.1 for patches, 1.1.0 for features, 2.0.0 for breaking changes).
permissions.requires: Minimum permissions needed. Plugin will not load without these:
read— read fileswrite— write filesbash— execute shell commandsagent— spawn subagentsmcp— use MCP serversnetwork— external HTTP
permissions.optional: Nice-to-have permissions. Plugin works without them but features are limited.
capabilities.provides: Custom capabilities your plugin exposes. Use for plugin discovery and dependency resolution.
contextEntry: Points to the bootstrap file. Always "CONTEXT_SUMMARY.md".
context.bootstrapFiles: Files loaded into context when plugin installs. Keep to 700 tokens.
context.lazyLoadSections: Files loaded on-demand when user references them. Helps large plugins stay responsive.
context.excludeGlobs: Patterns to exclude from context scanning (node_modules, build artifacts, etc.).
Command Authoring
Commands are markdown files in the commands/ directory with YAML frontmatter and implementation body.
Command Frontmatter Schema
---
name: my-command
intent: What this command does (one sentence)
inputs:
- name: description
- task: what the user wants
- query: optional search term
flags:
- name: force
type: boolean
description: Skip confirmations
- name: output
type: choice
choices: [json, text, html]
description: Output format
risk: low
cost: low
tags:
- my-plugin
- productivity
---
Command Body Structure
After frontmatter, the body contains:
- Usage Examples (code blocks with bash syntax)
- Operating Protocol (numbered phases)
- Output Contract (what the command produces)
Full Command Example
---
name: batch-process
intent: Process multiple files with transformation rules
inputs:
- files: pattern matching files to process
- rule: transformation function (e.g., "uppercase", "snake_case")
flags:
- name: dry-run
type: boolean
description: Show changes without applying
- name: workers
type: string
description: Number of parallel workers (default 4)
risk: medium
cost: medium
tags:
- my-plugin
- batch
---
# Batch Process Command
Process multiple files with transformation rules applied in parallel.
## Usage
```bash
/batch-process --files "src/**/*.ts" --rule uppercase
/batch-process --files "*.md" --rule snake_case --dry-run
/batch-process --files "src/**/*.js" --rule lowercase --workers 8
Operating Protocol
- Parse input flags and file pattern
- Validate files exist and are readable
- Check dry-run — if set, show preview without modifying
- Scan matching files into queue
- Apply rule to each file (parallel if workers > 1)
- Report changes: files modified, skipped, failed
- Rollback if failures exceed threshold (--continue-on-error overrides)
Output Contract
Returns JSON object:
{
"processed": 42,
"modified": 40,
"skipped": 2,
"failed": 0,
"duration_ms": 1234,
"files": [
{"path": "src/file.ts", "status": "modified", "size_before": 100, "size_after": 120}
]
}
### Command Naming
Prefix commands with plugin name for namespacing:
- Good: `/my-plugin-batch`, `/my-plugin-audit`
- Avoid: `/batch`, `/process` (too generic)
## Skill Authoring
Skills are knowledge packs in `skills/SKILLNAME/SKILL.md` with frontmatter and progressive loading.
### Skill Frontmatter
```yaml
---
name: my-skill
description: What this skill teaches (one sentence)
allowed-tools:
- Read
- Write
- Bash
- Grep
triggers:
- use my skill
- teach me about skill
- how to use skill
disable-model-invocation: false
---
Set disable-model-invocation: true for user-only reference skills (no model can invoke them).
Skill Body Structure
- Goal (why someone uses this skill)
- Core Loop (numbered steps, 5-10 steps typical)
- Examples (real code snippets)
Full Skill Example
---
name: database-migrations
description: Safely design and test database migrations with rollback paths
allowed-tools:
- Read
- Write
- Bash
triggers:
- database migration
- db migration
- migration strategy
- rollback plan
---
# Database Migrations
Design, test, and execute database migrations safely with automatic rollback paths.
## Goal
Write migrations that are **testable**, **reversible**, and **traceable**. Catch issues in development, not production.
## Core Loop
1. **Analyze** existing schema using introspection (PRAGMA for SQLite, DESCRIBE for MySQL)
2. **Design** migration: identify impact zones (tables, columns, indexes affected)
3. **Write up migration** in idempotent SQL (use CREATE IF NOT EXISTS, etc.)
4. **Test forward** locally: apply migration to dev DB, verify no errors
5. **Test backward** locally: rollback, verify schema returns to original state
6. **Document** rollback procedure: exact SQL to undo, any data caveats
7. **Plan downtime** or use zero-downtime pattern (shadow columns, dual-write)
8. **Execute in staging** first, verify application compatibility
9. **Run in production** during maintenance window with team ready to rollback
10. **Verify** schema matches expectation post-migration
## Examples
### SQLite: Add Column (Reversible)
Forward:
```sql
ALTER TABLE users ADD COLUMN last_login DATETIME DEFAULT NULL;
Backward:
-- SQLite doesn't support DROP COLUMN in older versions, so recreate:
-- Copy old schema to backup, drop table, recreate without new column
PostgreSQL: Add Column with Default (Zero-Downtime)
Forward (in 3 phases to avoid locking):
-- Phase 1: Add column nullable
ALTER TABLE users ADD COLUMN status VARCHAR(20);
-- Phase 2: Backfill existing rows (in batches to avoid locks)
UPDATE users SET status = 'active' WHERE status IS NULL LIMIT 1000;
-- Phase 3: Add constraint and default
ALTER TABLE users ALTER COLUMN status SET DEFAULT 'active';
ALTER TABLE users ALTER COLUMN status SET NOT NULL;
Backward:
ALTER TABLE users DROP COLUMN status;
Testing Migration (Bash)
# Create test database
sqlite3 /tmp/test.db < schema.sql
# Apply migration
sqlite3 /tmp/test.db < migration_up.sql
# Verify schema
echo "SELECT * FROM pragma_table_info(users);" | sqlite3 /tmp/test.db
# Rollback
sqlite3 /tmp/test.db < migration_down.sql
# Verify rollback
echo "SELECT * FROM pragma_table_info(users);" | sqlite3 /tmp/test.db
### Skill Triggers
Choose triggers users actually type. Avoid generic phrases; be specific:
- Good: `database migration`, `migration strategy`, `zero-downtime pattern`
- Avoid: `how to`, `help`, `explain` (too broad)
## Agent Authoring
Agents are specialized workers in markdown with YAML frontmatter and workflow steps.
### Agent Frontmatter
```yaml
---
name: my-agent
intent: One-sentence summary of what agent does
inputs:
- task: primary input
- context: optional background
risk: low
cost: low
tags:
- my-plugin
description: Multi-sentence description (2-3 sentences)
model: claude-sonnet-4-6
tools:
- Read
- Write
- Bash
---
Agent Model Selection
claude-opus-4-6: Complex reasoning, multi-step problems, code architectureclaude-sonnet-4-6: Implementation, bug fixing, most tasks (recommended default)claude-haiku-4-5: Fast research, summaries, quick lookups
Agent Body Structure
Mandatory sections:
- Agent Name (heading)
- Purpose (paragraph explaining intent)
- When to Use (user scenarios)
- Workflow (numbered steps, 3-8 steps typical)
- Known Limitations (edge cases, gotchas)
Full Agent Example
---
name: code-architect
intent: Design system architecture and produce implementation roadmap
inputs:
- problem: architecture challenge to solve
- constraints: technical/business constraints
risk: medium
cost: medium
tags:
- my-plugin
- architecture
- design
description: Analyzes requirements, designs modular architecture, produces detailed implementation roadmap with testing strategy.
model: claude-opus-4-6
tools:
- Read
- Write
- Grep
- Bash
---
# Code Architect Agent
System design specialist that analyzes requirements, designs modular architecture, and produces step-by-step implementation roadmaps.
## Purpose
When teams face architecture decisions, they need structured reasoning about tradeoffs: monolith vs microservices, SQL vs NoSQL, sync vs async. This agent produces **evidence-backed design docs** that make these tradeoffs explicit and testable.
## When to Use
- Starting a new project: need architecture foundation
- Scaling existing system: need refactor strategy
- Evaluating tech choices: need comparison framework
- Code review: need architecture validation
## Workflow
1. **Understand Requirements**
- Read problem statement and constraints
- List functional requirements (features, user stories)
- List non-functional requirements (scale, latency, availability)
- Identify known edge cases
2. **Design Tradeoff Matrix**
- List candidate architectures (3-5 options)
- For each, score on: scalability, complexity, cost, time-to-market
- Highlight which constraints rule out which options
- Recommend top 2 designs
3. **Deep-Dive Recommended Design**
- Draw module boundaries (responsibility, data ownership)
- Define interfaces between modules
- Show data flow end-to-end
- Identify external dependencies
4. **Produce Roadmap**
- Break into 4-6 phases
- For each phase: deliverables, test strategy, rollback plan
- Estimate effort (3-point estimates: optimistic/likely/pessimistic)
- Call out blockers and risks
5. **Create Implementation Checklists**
- Phase-by-phase tasks
- Definition of done for each phase
- Testing/validation criteria
## Known Limitations
- Architecture cannot predict all runtime issues (load patterns, failure modes)
- Assume team has required skills for chosen tech stack
- Roadmap assumes no major scope creep; update if requirements change
- Does not cover devops/infrastructure details (separate discipline)
Hook Script Authoring
Hooks are bash scripts in hooks/ that respond to lifecycle events with JSON on stdin/stdout.
Hook Lifecycle Events
| Event | Fires | Input | Decision |
|-------|-------|-------|----------|
| SessionStart | Claude Code session begins | session context | additionalContext |
| PreToolUse | Before tool call | tool name, input | allow/block/passthrough |
| PostToolUse | After successful tool call | tool output | additionalContext |
| PostToolUseFailure | After tool call fails | tool name, error | additionalContext (can auto-heal) |
| Stop | Session ends | reason | cleanup |
| Notification | User sends message | text | prompt override |
Hook Input Format
{
"tool_name": "Read",
"tool_input": {
"file_path": "/home/user/file.txt"
},
"session_id": "s_abc123",
"user_message": "optional context"
}
Hook Output Format
{
"additionalContext": "Helpful context to pass to Claude",
"decision": "allow",
"blocked_reason": "optional reason if decision is block"
}
Full Hook Script Example
#!/bin/bash
# PreToolUse hook: validate dangerous operations
set -e
# Read input
input=$(cat)
# Extract fields
tool_name=$(echo "$input" | jq -r '.tool_name')
tool_input=$(echo "$input" | jq '.tool_input')
file_path=$(echo "$tool_input" | jq -r '.file_path // empty')
# Block if deleting system files
if [[ "$tool_name" == "Bash" ]] && echo "$input" | jq -r '.tool_input.command' | grep -q "rm -rf /"; then
echo '{"decision": "block", "blocked_reason": "Dangerous operation: rm -rf / blocked"}'
exit 0
fi
# Allow
echo '{"decision": "allow"}'
exit 0
Hook Configuration (hooks.json)
{
"hooks": [
{
"event": "PreToolUse",
"script": "hooks/validate-dangerous.sh",
"enabled": true
},
{
"event": "PostToolUseFailure",
"script": "hooks/capture-errors.sh",
"enabled": true
}
]
}
Hook Security
- Sanitize all inputs:
jq -rprevents injection - Use
flockfor atomic file writes (avoid race conditions) - Do not execute user input directly
- Log hook executions for debugging
- Exit code 0 = success, non-zero = failure (blocks tool call if PreToolUse)
MCP Server Development
Optional: plugins can include custom MCP servers for new tools.
TypeScript MCP Server
// mcp-server/src/index.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
ListToolsRequestSchema,
CallToolRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
const server = new Server(
{ name: "my-mcp-server", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "analyze_code",
description: "Analyzes code for patterns",
inputSchema: {
type: "object",
properties: {
code: { type: "string", description: "Code to analyze" },
language: { type: "string", description: "Programming language" }
},
required: ["code", "language"]
}
}
]
}));
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "analyze_code") {
const { code, language } = request.params.arguments;
const analysis = {
lines: code.split('\n').length,
language,
patterns: ["if-else", "loops", "functions"]
};
return {
content: [{ type: "text", text: JSON.stringify(analysis) }]
};
}
throw new Error(`Unknown tool: ${request.params.name}`);
});
// Start server
const transport = new StdioServerTransport();
await server.connect(transport);
package.json for MCP Server
{
"name": "my-mcp-server",
"version": "1.0.0",
"description": "Custom MCP server for my plugin",
"type": "module",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"start": "node dist/index.js"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0"
}
}
Plugin CLAUDE.md
Short routing guide (under 50 lines) for the plugin's capabilities.
# My Awesome Plugin
## Purpose
Use this plugin when you need to automate batch processing, validate schemas, and generate reports.
## Fast Routing
- Batch process files? → `/batch-process`
- Validate schema? → `/validate-schema`
- Generate report? → `/gen-report`
- Need advanced options? → Open `skills/advanced-batch/SKILL.md`
## Operating Rules
1. Always preview with `--dry-run` before modifying
2. Use `--workers 1` for debugging
3. Check `CONTEXT_SUMMARY.md` for permission requirements
CONTEXT_SUMMARY.md
Bootstrap context loaded when plugin installs. Keep under 700 tokens.
# My Awesome Plugin Bootstrap
What this plugin does in 2-3 sentences. When to install it.
## Quick Start
- `/batch-process --help` for batch operations
- `/validate-schema FILE` to validate JSON/YAML
- Skills: `advanced-batch`, `schema-validation`
## Permissions Needed
- read, write (required)
- bash (optional, for advanced batch processing)
## Key Concepts
- **Batch Processing**: Parallel file transformation using rules
- **Schema Validation**: JSON Schema or custom validators
- **Dry-Run**: Preview changes without applying
## When to Use
- Processing 10+ files with same rule
- Ensuring data consistency
- Automating repetitive tasks
Testing & Validation
Manual Testing Checklist
- [ ] All commands parse without YAML errors
- [ ] All referenced files exist (commands, skills, agents in manifest match filesystem)
- [ ] Frontmatter fields are valid (risk/cost are low/medium/high)
- [ ] Skills have at least 3 triggers
- [ ] Commands have usage examples
- [ ] Agents have workflow steps (minimum 3)
- [ ] README is under 500 words
Validate Manifest
# Check if plugin.json is valid JSON
python3 -m json.tool .claude-plugin/plugin.json > /dev/null && echo "JSON valid"
# Check all referenced files exist
python3 << 'EOF'
import json, os
data = json.load(open('.claude-plugin/plugin.json'))
bootstrap_files = data.get('context', {}).get('bootstrapFiles', [])
for f in bootstrap_files:
if not os.path.exists(f):
print(f"MISSING: {f}")
EOF
Marketplace Publishing
README Requirements
- Title and one-line description
- Features (bullet list, 3-5 items)
- Installation instructions
- Usage examples (at least 2)
- Permissions required
- Version history (latest changes)
Versioning
1.0.0— Initial release1.0.1— Bug fix (patch)1.1.0— New feature (minor)2.0.0— Breaking change (major)
Keyword Optimization
Choose keywords from common Claude Code domains:
- automation, productivity, development, testing
- configuration, debugging, architecture, performance
- documentation, api, integration, workflow
Keep to 10-15 keywords total for discoverability.
Distribution
Plugins are published to the Claude Code marketplace:
- Create repo on GitHub
- Add
.claude-plugin/plugin.jsonand files - Tag release as
v1.0.0 - Submit to marketplace (review process ~24-48 hours)
- Once approved, appears in
claude plugin search
Common Errors & Fixes
| Error | Cause | Fix |
|-------|-------|-----|
| YAML parse error | Invalid frontmatter | Use valid YAML (quotes, hyphens for lists) |
| File not found | Referenced file missing | Add file or update manifest |
| Unknown permission | Typo in permissions | Use: read, write, bash, agent, mcp, network |
| Too many tokens | CONTEXT_SUMMARY too long | Trim to essentials, use lazyLoadSections |
| Tool not available | Tool not in allowed-tools | Add tool to skill frontmatter |