
Plugin Creator
- 1 installs
- Updated February 26, 2026
- ylt/claude-plugins
Guides creating complete Claude Code plugins with commands, agents, skills, hooks, MCP servers, and LSP servers, including plugin.json manifest configuration.
About
A guide for scaffolding and configuring Claude Code plugins, covering component types, manifest setup, and distribution. A developer uses it when building or organizing a Claude Code plugin.
- Covers commands, agents, skills, hooks, MCP, and LSP components
- Guidance on plugin.json manifest and distribution
Plugin Creator by the numbers
- 1 all-time installs (skills.sh)
- Ranked #642 of 782 Skill Development skills by installs in the Skillselion catalog
- Data as of Jul 8, 2026 (Skillselion catalog sync)
npx skills add https://github.com/ylt/claude-plugins --skill plugin-creatorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| Last updated | February 26, 2026 |
| Repository | ylt/claude-plugins ↗ |
What it does
Guides creating complete Claude Code plugins with commands, agents, skills, hooks, MCP servers, and LSP servers, including plugin.json manifest configuration.
Files
Plugin Creator
Guide for creating complete Claude Code plugins with commands, agents, skills, hooks, MCP servers, and LSP servers.
About Plugins
A plugin is a self-contained directory of components that extends Claude Code. Plugins bundle related functionality into a single distributable package that users install and enable.
Plugin Components
| Component | Purpose | Location |
|---|---|---|
| Commands | Slash commands users invoke | commands/*.md |
| Agents | Specialized subagents | agents/*.md |
| Skills | Auto-activating knowledge packs | skills/*/SKILL.md |
| Hooks | Event-driven automation | hooks/hooks.json |
| MCP Servers | External tool integrations | .mcp.json |
| LSP Servers | Code intelligence | .lsp.json |
Only include components the plugin actually needs. A minimal plugin may have just one command or skill.
Plugin Structure
plugin-name/
├── .claude-plugin/
│ └── plugin.json # Manifest (only file in this dir)
├── commands/ # At root level
├── agents/ # At root level
├── skills/ # At root level
├── hooks/
│ ├── hooks.json
│ └── scripts/
├── .mcp.json
├── .lsp.json
└── scripts/Critical rule: Component directories MUST be at plugin root, NOT inside .claude-plugin/. Only plugin.json goes in .claude-plugin/.
Plugin Creation Process
Follow these steps in order. Skip steps only when clearly inapplicable.
1. Understand plugin requirements 2. Plan plugin components 3. Scaffold the plugin 4. Implement components 5. Validate and test 6. Iterate
Step 1: Understand Plugin Requirements
Clarify the plugin's purpose and scope before building anything.
Key questions to resolve:
- What problem does this plugin solve?
- Who will use it and when?
- What component types are needed?
- Any external service dependencies?
For example, when building a database-tools plugin, the analysis shows: 1. Users need commands to run migrations and query schemas 2. An MCP server connects to the database 3. A hook validates SQL before execution 4. A skill provides migration best practices
Conclude this step with a clear understanding of which components to build.
Step 2: Plan Plugin Components
Map requirements to specific components:
| Component | Count | Purpose |
|---|---|---|
| Commands | 2 | create-migration, run-migration |
| Skills | 1 | Migration best practices |
| MCP | 1 | Database connection |
| Hooks | 1 | SQL validation |
For each component, identify:
- Triggering conditions (commands: user invocation; agents: auto/manual; skills: description match; hooks: event match)
- Required tools and permissions
- External dependencies (binaries, APIs, env vars)
Step 3: Scaffold the Plugin
Run the scaffolding script to create the directory structure:
python3 scripts/scaffold-plugin.py <plugin-name> --path <parent-dir> [--components <list>]Arguments:
plugin-name— kebab-case identifier (e.g.,database-tools)--path— parent directory to create plugin in--components— comma-separated subset:commands,agents,skills,hooks,mcp,lsp,scripts(default: all)
Example:
python3 scripts/scaffold-plugin.py database-tools --path ~/plugins --components commands,skills,hooks,mcpThe script creates the directory structure with template files for each component. Customize or delete the generated examples.
Configure the manifest in .claude-plugin/plugin.json:
{
"name": "database-tools",
"version": "0.1.0",
"description": "Database migration and query tools",
"keywords": ["database", "migrations", "sql"]
}For the full manifest schema (all fields, component paths, metadata), consult `references/plugin-reference.md`.
Step 4: Implement Components
Implement each component following the patterns in `references/component-patterns.md`. Key points per component type:
Commands
Markdown files in commands/ with YAML frontmatter. Write instructions for Claude (these are prompts Claude follows). Use $ARGUMENTS for user input. Filename becomes the slash command name.
---
description: Run database migrations
argument-hint: up|down|status
allowed-tools: ["Read", "Bash", "Glob"]
---
# Run Migrations
Based on $ARGUMENTS, execute the appropriate migration action...Agents
Markdown files in agents/ with <example> blocks in the description for reliable auto-triggering. Include 2-4 realistic examples showing user messages that should invoke the agent.
---
name: sql-reviewer
description: |
SQL query and migration review specialist.
<example>
user: Review this migration for safety issues
assistant: (uses sql-reviewer)
</example>
---
System prompt defining the agent's role and behavior...Skills
For creating skills within a plugin, invoke the skill-creator skill (/skill-creator). It provides the complete methodology for understanding use cases, planning resources, writing effective SKILL.md with strong triggers, and progressive disclosure design.
Create skill directories within the plugin's skills/ directory. Follow the same standards: third-person description with specific trigger phrases, imperative form in body, lean SKILL.md with detailed content in references/.
Hooks
Configure in hooks/hooks.json. Three hook types: command (shell scripts), prompt (LLM evaluation), agent (agentic verification). Always use ${CLAUDE_PLUGIN_ROOT} for portable paths.
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/scripts/validate.sh"
}]
}]
}
}Hook scripts must be executable (chmod +x), include a shebang, read JSON from stdin, and output JSON decisions to stdout.
MCP Servers
Configure in .mcp.json. Use ${CLAUDE_PLUGIN_ROOT} for plugin-relative paths. Servers start automatically when the plugin enables.
{
"mcpServers": {
"database": {
"command": "node",
"args": ["${CLAUDE_PLUGIN_ROOT}/servers/db.js"],
"env": { "DB_URL": "${DB_URL}" }
}
}
}Document required environment variables clearly.
LSP Servers
Configure in .lsp.json. Map file extensions to language identifiers. The language server binary must be installed separately.
{
"typescript": {
"command": "typescript-language-server",
"args": ["--stdio"],
"extensionToLanguage": { ".ts": "typescript", ".tsx": "typescriptreact" }
}
}For complete patterns, examples, and all configuration options for every component type, consult `references/component-patterns.md`.
Step 5: Validate and Test
Test locally:
claude --plugin-dir /path/to/plugin-nameDebug loading issues:
claude --debugValidation checklist:
- [ ]
.claude-plugin/plugin.jsonhas valid JSON withnamefield - [ ] Component directories are at plugin root (not in
.claude-plugin/) - [ ] All paths use
${CLAUDE_PLUGIN_ROOT}(no hardcoded paths) - [ ] Hook scripts are executable with shebangs
- [ ] Skills have
SKILL.mdwith frontmatter (name+description) - [ ] Agent descriptions include
<example>blocks - [ ] MCP server commands exist and are reachable
- [ ] Required environment variables are documented
For debugging details and common issues, consult `references/plugin-reference.md`.
Step 6: Iterate
After testing the plugin on real tasks: 1. Strengthen skill trigger phrases based on what users actually say 2. Add missing edge case handling in hooks 3. Improve agent examples for more reliable auto-triggering 4. Bump version in plugin.json before distributing updates (caching prevents updates otherwise)
Resources
Reference Files
Consult these when implementing specific component types or troubleshooting:
- `references/plugin-reference.md` — Complete technical reference: manifest schema, auto-discovery, environment variables, installation scopes, CLI commands, debugging, common issues
- `references/component-patterns.md` — Detailed patterns for every component type: commands, agents, skills, hooks, MCP servers, LSP servers. Includes format specs, frontmatter fields, and working examples
Scripts
- `scripts/scaffold-plugin.py` — Scaffolds a new plugin directory with selected components and template files
External Skills
- skill-creator (
/skill-creator) — Invoke when creating skills within a plugin. Provides the full methodology for writing effective skills with progressive disclosure.
Component Patterns Reference
How to write each plugin component type with correct format, frontmatter, and best practices.
Table of Contents
---
Commands
Slash commands users invoke directly. Located in commands/ as .md files.
Format
---
description: What the command does (shown in /help)
argument-hint: Description of expected arguments
allowed-tools: ["Read", "Write", "Glob", "Grep", "Bash"]
---
# Command Title
Instructions FOR Claude to execute when this command is invoked.
Write as a prompt — Claude follows these instructions when the user runs the command.
Use $ARGUMENTS to reference what the user passes after the command name.Frontmatter Fields
| Field | Required | Description |
|---|---|---|
description | Yes | Shown in command listing |
argument-hint | No | Describes expected arguments |
allowed-tools | No | Restricts which tools Claude can use |
Key Principles
- Write instructions for Claude, not documentation for the user
- Use
$ARGUMENTSplaceholder for user-provided input - Keep commands focused on a single workflow
- Reference skills or agents when complex logic is needed
- Command filename becomes the slash command name:
deploy.md→/plugin:deploy
Example: Code Review Command
---
description: Review code changes for quality, security, and best practices
argument-hint: Optional file path or PR number to review
allowed-tools: ["Read", "Glob", "Grep", "Bash"]
---
# Code Review
Perform a thorough code review on the specified target.
If $ARGUMENTS contains a file path, review that file.
If $ARGUMENTS contains a PR number, use `gh pr diff $ARGUMENTS` to get the diff.
If $ARGUMENTS is empty, review staged changes with `git diff --cached`.
## Review Checklist
1. **Correctness**: Logic errors, edge cases, off-by-one errors
2. **Security**: Injection, XSS, hardcoded secrets, OWASP top 10
3. **Performance**: N+1 queries, unnecessary allocations, missing indexes
4. **Maintainability**: Naming, complexity, duplication
Present findings organized by severity: Critical > Warning > Suggestion.---
Agents
Specialized subagents Claude can invoke automatically or users invoke manually. Located in agents/ as .md files.
Format
---
name: agent-name
description: |
What this agent specializes in.
<example>
user: Example user message that triggers this agent
assistant: (uses agent-name)
</example>
<example>
user: Another triggering scenario
assistant: (uses agent-name)
</example>
model: sonnet
tools: ["Read", "Glob", "Grep", "Bash", "Write", "Edit"]
---
Detailed system prompt defining the agent's role, expertise, constraints, and output format.Frontmatter Fields
| Field | Required | Description |
|---|---|---|
name | Yes | Agent identifier (kebab-case) |
description | Yes | When to use, with <example> blocks |
model | No | sonnet, opus, haiku |
tools | No | Tool allowlist |
color | No | Display color in UI |
Description with Examples
The <example> blocks in the description are critical for reliable auto-triggering. Include 2-4 examples showing realistic user messages:
description: |
Security analysis specialist for code and configurations.
<example>
user: Check this API endpoint for security vulnerabilities
assistant: (uses security-reviewer)
</example>
<example>
user: Is this authentication implementation secure?
assistant: (uses security-reviewer)
</example>System Prompt Patterns
Analysis agent: Define what to analyze, criteria, output format Generation agent: Define what to create, constraints, quality standards Validation agent: Define what to check, pass/fail criteria, reporting format Orchestration agent: Define workflow steps, decision points, delegation rules
---
Skills
Auto-activating knowledge packs. Located in skills/ as subdirectories with SKILL.md.
Format
---
name: Skill Name
description: "This skill should be used when the user asks to \"do X\", \"perform Y\", or mentions Z. Specific trigger phrases and scenarios."
---
# Skill Name
Core instructions and guidance. Keep lean (1,500-2,000 words).
Move detailed content to references/ subdirectory.
## Additional Resources
- **`references/patterns.md`** - Detailed patterns and examples
- **`scripts/validate.sh`** - Validation utilityStructure
skill-name/
├── SKILL.md # Core instructions (required)
├── references/ # Detailed docs (loaded as needed)
├── examples/ # Working code examples
├── scripts/ # Utility scripts
└── assets/ # Templates, images, etc.Key Principles
- Description triggers activation — include specific user phrases
- Third person in description: "This skill should be used when..."
- Imperative form in body: "Configure the server" not "You should configure"
- Progressive disclosure: lean SKILL.md, detailed references
- Reference the skill-creator skill for full methodology on creating high-quality skills
Creating Skills Within Plugins
For creating skills as part of a plugin, invoke the skill-creator skill (/skill-creator). It provides the complete methodology for:
- Understanding use cases with concrete examples
- Planning reusable contents (scripts, references, assets)
- Writing effective SKILL.md with strong triggers
- Progressive disclosure design
- Packaging and validation
Create the skill directory within the plugin's skills/ directory instead of the default skill path.
---
Hooks
Event-driven automation. Configured in hooks/hooks.json or inline in plugin.json.
Configuration Format
{
"hooks": {
"EventName": [
{
"matcher": "ToolPattern",
"hooks": [
{
"type": "command|prompt|agent",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/hook.sh",
"timeout": 30
}
]
}
]
}
}For inline in plugin.json, use the same structure under a top-level "hooks" key.
Available Events
| Event | When | Matcher |
|---|---|---|
PreToolUse | Before tool execution | Tool name pattern |
PostToolUse | After successful tool use | Tool name pattern |
PostToolUseFailure | After tool failure | Tool name pattern |
PermissionRequest | Permission dialog shown | — |
UserPromptSubmit | User submits prompt | — |
Notification | Notification sent | — |
Stop | Claude attempts to stop | — |
SubagentStart | Subagent starts | — |
SubagentStop | Subagent attempts to stop | — |
SessionStart | Session begins | — |
SessionEnd | Session ends | — |
TeammateIdle | Teammate about to go idle | — |
TaskCompleted | Task marked completed | — |
PreCompact | Before history compaction | — |
Hook Types
command — Execute a shell command/script:
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh"
}prompt — Evaluate with an LLM (uses $ARGUMENTS for context):
{
"type": "prompt",
"prompt": "Review this tool call for safety concerns: $ARGUMENTS. Respond with JSON: {\"decision\": \"allow|block\", \"reason\": \"...\"}"
}agent — Run an agentic verifier with tools:
{
"type": "agent",
"prompt": "Verify the code changes are safe and follow conventions: $ARGUMENTS"
}Hook Script Requirements
- Must be executable (
chmod +x) - Include shebang (
#!/usr/bin/env bash) - Use
${CLAUDE_PLUGIN_ROOT}for paths - Input via stdin (JSON with tool_name, tool_input, etc.)
- Output JSON to stdout for decisions:
{"decision": "allow", "reason": "Checks passed"}
{"decision": "block", "reason": "Blocked: dangerous operation"}---
MCP Servers
External tool integrations via Model Context Protocol. Configured in .mcp.json or inline in plugin.json.
Configuration Format
{
"mcpServers": {
"server-name": {
"command": "node",
"args": ["${CLAUDE_PLUGIN_ROOT}/servers/server.js"],
"env": {
"API_KEY": "${API_KEY}",
"DATA_PATH": "${CLAUDE_PLUGIN_ROOT}/data"
}
}
}
}Server Types
stdio (local process):
{
"command": "${CLAUDE_PLUGIN_ROOT}/servers/db-server",
"args": ["--config", "${CLAUDE_PLUGIN_ROOT}/config.json"]
}SSE (hosted, often with OAuth):
{
"url": "https://api.example.com/mcp",
"headers": { "Authorization": "Bearer ${TOKEN}" }
}Key Principles
- Servers start automatically when plugin enables
- Use
${CLAUDE_PLUGIN_ROOT}for all plugin-relative paths - Environment variables expand at runtime
- Document required env vars in plugin README
- Server tools integrate seamlessly with Claude's toolkit
---
LSP Servers
Language Server Protocol integration for code intelligence. Configured in .lsp.json or inline in plugin.json.
Configuration Format
{
"language-name": {
"command": "language-server-binary",
"args": ["serve"],
"extensionToLanguage": {
".ext": "language-id"
}
}
}Required Fields
| Field | Description |
|---|---|
command | LSP binary to execute (must be in PATH) |
extensionToLanguage | Maps file extensions to language identifiers |
Optional Fields
| Field | Description |
|---|---|
args | Command-line arguments |
transport | stdio (default) or socket |
env | Environment variables |
initializationOptions | Options for server init |
settings | Passed via workspace/didChangeConfiguration |
restartOnCrash | Auto-restart on crash |
maxRestarts | Max restart attempts |
Example: TypeScript LSP
{
"typescript": {
"command": "typescript-language-server",
"args": ["--stdio"],
"extensionToLanguage": {
".ts": "typescript",
".tsx": "typescriptreact",
".js": "javascript",
".jsx": "javascriptreact"
}
}
}Important: The language server binary must be installed separately. LSP plugins configure the connection, not the server itself.
Plugin Technical Reference
Complete technical reference for the Claude Code plugin system.
Table of Contents
- Plugin Manifest Schema
- Directory Structure
- Auto-Discovery Mechanism
- Environment Variables
- Installation Scopes
- Plugin Caching
- CLI Commands
- Version Management
- Debugging
- Common Issues
---
Plugin Manifest Schema
Located at .claude-plugin/plugin.json. Optional — if omitted, Claude Code auto-discovers components and derives the name from the directory.
Required Fields
Only name is required (if manifest exists):
{
"name": "plugin-name"
}Name must be kebab-case, unique across installed plugins.
All Fields
{
"name": "plugin-name",
"version": "1.0.0",
"description": "Brief plugin description",
"author": {
"name": "Author Name",
"email": "author@example.com",
"url": "https://github.com/author"
},
"homepage": "https://docs.example.com/plugin",
"repository": "https://github.com/author/plugin",
"license": "MIT",
"keywords": ["keyword1", "keyword2"],
"commands": "./custom/commands/special.md",
"agents": "./custom/agents/",
"skills": "./custom/skills/",
"hooks": "./config/hooks.json",
"mcpServers": "./mcp-config.json",
"outputStyles": "./styles/",
"lspServers": "./.lsp.json"
}Component Path Fields
| Field | Type | Description |
|---|---|---|
commands | string\ | array |
agents | string\ | array |
skills | string\ | array |
hooks | string\ | array\ |
mcpServers | string\ | array\ |
outputStyles | string\ | array |
lspServers | string\ | array\ |
Path rules:
- Custom paths supplement defaults (don't replace them)
- Must be relative to plugin root, starting with
./ - Support arrays for multiple locations
---
Directory Structure
plugin-name/
├── .claude-plugin/ # Metadata (only plugin.json goes here)
│ └── plugin.json
├── commands/ # Slash commands (.md files)
├── agents/ # Subagent definitions (.md files)
├── skills/ # Skills (subdirectories with SKILL.md)
│ └── skill-name/
│ └── SKILL.md
├── hooks/ # Event handlers
│ ├── hooks.json
│ └── scripts/
├── .mcp.json # MCP server definitions
├── .lsp.json # LSP server configurations
└── scripts/ # Shared utilitiesCritical: Component directories MUST be at plugin root, NOT inside .claude-plugin/.
---
Auto-Discovery Mechanism
Claude Code automatically discovers components:
1. Reads .claude-plugin/plugin.json when plugin enables 2. Scans commands/ for .md files 3. Scans agents/ for .md files 4. Scans skills/ for subdirectories containing SKILL.md 5. Loads hooks/hooks.json or manifest hooks 6. Loads .mcp.json or manifest MCP config 7. Loads .lsp.json or manifest LSP config
No restart required — changes take effect on next session.
---
Environment Variables
${CLAUDE_PLUGIN_ROOT}
Absolute path to the plugin directory. Use in all intra-plugin path references:
{
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/run.sh"
}Available in:
- Hook command paths
- MCP server command/args
- Script execution
- As environment variable in executed scripts
Never use: hardcoded absolute paths, relative paths from working directory, or ~/ shortcuts.
---
Installation Scopes
| Scope | Settings File | Use Case |
|---|---|---|
user | ~/.claude/settings.json | Personal, all projects (default) |
project | .claude/settings.json | Team, shared via VCS |
local | .claude/settings.local.json | Project-specific, gitignored |
managed | managed-settings.json | Read-only, update only |
---
Plugin Caching
Marketplace plugins are copied to ~/.claude/plugins/cache. Implications:
- Plugins cannot reference files outside their directory
- Path traversal (
../shared-utils) won't work after install - Symlinks are honored during copy (use for external dependencies)
---
CLI Commands
# Install
claude plugin install <name>[@marketplace] [--scope user|project|local]
# Uninstall (aliases: remove, rm)
claude plugin uninstall <name>[@marketplace] [--scope user|project|local]
# Enable/Disable
claude plugin enable <name> [--scope ...]
claude plugin disable <name> [--scope ...]
# Update
claude plugin update <name> [--scope user|project|local|managed]---
Version Management
Follow semver: MAJOR.MINOR.PATCH
- Set in
plugin.jsonor marketplace entry (plugin.json takes priority) - Bump version before distributing changes (caching prevents updates otherwise)
- Pre-release versions:
2.0.0-beta.1
---
Debugging
Run claude --debug (or /debug in TUI) to see:
- Plugin loading details
- Manifest errors
- Component registration
- MCP server initialization
---
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| Plugin not loading | Invalid plugin.json | Validate JSON syntax |
| Commands not appearing | Wrong directory | Ensure commands/ at root, not in .claude-plugin/ |
| Hooks not firing | Script not executable | chmod +x script.sh |
| MCP server fails | Missing ${CLAUDE_PLUGIN_ROOT} | Use variable for all paths |
| Path errors | Absolute paths | Use relative paths starting with ./ |
| LSP executable not found | Server not installed | Install the binary separately |
Hook Troubleshooting
1. Check executable: chmod +x ./scripts/your-script.sh 2. Verify shebang: #!/usr/bin/env bash 3. Check path uses ${CLAUDE_PLUGIN_ROOT} 4. Test manually: ./scripts/your-script.sh
MCP Server Troubleshooting
1. Verify command exists and is executable 2. Check all paths use ${CLAUDE_PLUGIN_ROOT} 3. Use claude --debug to see initialization errors 4. Test server outside Claude Code
#!/usr/bin/env python3
"""
Plugin Scaffolder - Creates a new Claude Code plugin from template
Usage:
scaffold-plugin.py <plugin-name> --path <path> [--components <comma-separated>]
Components: commands,agents,skills,hooks,mcp,lsp,scripts (default: all)
Examples:
scaffold-plugin.py my-plugin --path ./plugins
scaffold-plugin.py my-plugin --path ./plugins --components commands,hooks,mcp
"""
import re
import sys
from pathlib import Path
MANIFEST_TEMPLATE = """{{
"name": "{plugin_name}",
"version": "0.1.0",
"description": "TODO: Brief description of {plugin_title}"
}}
"""
COMMAND_TEMPLATE = """---
description: TODO: What this command does (shown in /help listing)
argument-hint: TODO: Expected arguments description
allowed-tools: ["Read", "Write", "Glob", "Grep", "Bash"]
---
# {plugin_title} Command
TODO: Replace with command implementation for {plugin_name}.
Write instructions FOR Claude to execute when the user invokes this command.
Commands are prompts — Claude follows these instructions, they are not shown to the user.
Use $ARGUMENTS to reference what the user passes after the command name.
Example real commands from other plugins:
- code-review: Analyzes staged changes for quality, security, and best practices
- deploy: Runs deployment pipeline with environment selection
- test-runner: Executes test suites with coverage reporting
$ARGUMENTS
"""
AGENT_TEMPLATE = """---
name: {plugin_name}-agent
description: |
TODO: Describe what this agent specializes in and when Claude should invoke it.
Include 2-4 <example> blocks showing realistic user messages that trigger this agent.
<example>
user: TODO: Example user message that should trigger this agent
assistant: (uses {plugin_name}-agent)
</example>
<example>
user: TODO: Another triggering scenario
assistant: (uses {plugin_name}-agent)
</example>
---
# {plugin_title} Agent
TODO: Write the system prompt for this agent.
Define the agent's role, expertise, constraints, and output format.
This prompt is what the agent sees as its instructions when invoked.
Example real agent system prompts follow patterns:
- **Analysis agent**: Define what to analyze, criteria, output format
- **Generation agent**: Define what to create, constraints, quality standards
- **Validation agent**: Define what to check, pass/fail criteria, reporting format
- **Orchestration agent**: Define workflow steps, decision points, delegation rules
"""
SKILL_TEMPLATE = """---
name: {skill_title}
description: "TODO: This skill should be used when the user asks to \\"do X\\", \\"perform Y\\", or mentions Z. Include specific trigger phrases and scenarios that should activate this skill."
---
# {skill_title}
TODO: Replace with skill content for {plugin_name}.
Use the skill-creator skill (/skill-creator) for the complete methodology:
- Understanding use cases with concrete examples
- Planning reusable contents (scripts, references, assets)
- Writing effective SKILL.md with strong triggers
- Progressive disclosure design
Key requirements:
- Description must use third person ("This skill should be used when...")
- Body must use imperative/infinitive form ("Configure the server" not "You should configure")
- Keep SKILL.md lean (1,500-2,000 words), move detailed content to references/
"""
HOOKS_TEMPLATE = """{{
"hooks": {{
"TODO: Replace with event name (PreToolUse, PostToolUse, Stop, etc.)": [
{{
"matcher": "TODO: Tool name pattern (e.g., Write|Edit)",
"hooks": [
{{
"type": "command",
"command": "${{CLAUDE_PLUGIN_ROOT}}/hooks/scripts/TODO-rename.sh"
}}
]
}}
]
}}
}}
"""
HOOK_SCRIPT_TEMPLATE = """#!/usr/bin/env bash
# Hook script for {plugin_name}
#
# This script is called by Claude Code when a hook event fires.
# Input: JSON via stdin with tool_name, tool_input, etc.
# Output: JSON to stdout with decision and reason.
#
# Example real hook scripts:
# - validate-write.sh: Checks file writes for security issues
# - validate-bash.sh: Blocks dangerous shell commands
# - load-context.sh: Injects additional context on session start
set -euo pipefail
# Read hook input from stdin
INPUT=$(cat)
# TODO: Implement hook logic here
# Parse input with jq: echo "$INPUT" | jq -r '.tool_name'
# Output decision (allow or block)
echo '{{"decision": "allow", "reason": "TODO: Implement validation logic"}}'
"""
MCP_TEMPLATE = """{{
"mcpServers": {{
"{plugin_name}-server": {{
"command": "TODO: server binary or runtime (e.g., node, python3)",
"args": ["${{CLAUDE_PLUGIN_ROOT}}/servers/TODO-server.js"],
"env": {{
"TODO_API_KEY": "${{TODO_API_KEY}}"
}}
}}
}}
}}
"""
LSP_TEMPLATE = """{{
"TODO-language-name": {{
"command": "TODO: language-server-binary",
"args": ["--stdio"],
"extensionToLanguage": {{
".TODO": "TODO-language-id"
}}
}}
}}
"""
ALL_COMPONENTS = ["commands", "agents", "skills", "hooks", "mcp", "lsp", "scripts"]
def title_case_plugin_name(plugin_name):
"""Convert hyphenated plugin name to Title Case for display."""
return ' '.join(word.capitalize() for word in plugin_name.split('-'))
def scaffold_plugin(plugin_name, path, components):
"""
Create a new plugin directory with selected components.
Args:
plugin_name: Plugin name in kebab-case
path: Parent directory for the plugin
components: List of component types to include
Returns:
Path to created plugin directory, or None if error
"""
plugin_dir = Path(path).resolve() / plugin_name
plugin_title = title_case_plugin_name(plugin_name)
# Check if directory already exists
if plugin_dir.exists():
print(f"❌ Error: Directory already exists: {plugin_dir}")
return None
# Create base structure with manifest
try:
(plugin_dir / ".claude-plugin").mkdir(parents=True, exist_ok=False)
print(f"✅ Created plugin directory: {plugin_dir}")
except Exception as e:
print(f"❌ Error creating directory: {e}")
return None
# Write plugin.json manifest
try:
manifest_path = plugin_dir / ".claude-plugin" / "plugin.json"
manifest_path.write_text(MANIFEST_TEMPLATE.format(
plugin_name=plugin_name,
plugin_title=plugin_title
))
print("✅ Created .claude-plugin/plugin.json")
except Exception as e:
print(f"❌ Error creating manifest: {e}")
return None
# Create requested components
try:
for comp in components:
if comp == "commands":
cmd_dir = plugin_dir / "commands"
cmd_dir.mkdir(exist_ok=True)
(cmd_dir / "example.md").write_text(COMMAND_TEMPLATE.format(
plugin_name=plugin_name,
plugin_title=plugin_title
))
print("✅ Created commands/ with example command")
elif comp == "agents":
agent_dir = plugin_dir / "agents"
agent_dir.mkdir(exist_ok=True)
(agent_dir / f"{plugin_name}-agent.md").write_text(AGENT_TEMPLATE.format(
plugin_name=plugin_name,
plugin_title=plugin_title
))
print(f"✅ Created agents/{plugin_name}-agent.md")
elif comp == "skills":
skill_name = f"{plugin_name}-skill"
skill_title_inner = title_case_plugin_name(skill_name)
skill_dir = plugin_dir / "skills" / skill_name
skill_dir.mkdir(parents=True, exist_ok=True)
(skill_dir / "SKILL.md").write_text(SKILL_TEMPLATE.format(
plugin_name=plugin_name,
skill_title=skill_title_inner
))
print(f"✅ Created skills/{skill_name}/SKILL.md")
elif comp == "hooks":
hooks_dir = plugin_dir / "hooks" / "scripts"
hooks_dir.mkdir(parents=True, exist_ok=True)
(plugin_dir / "hooks" / "hooks.json").write_text(
HOOKS_TEMPLATE.format(plugin_name=plugin_name)
)
hook_script = hooks_dir / "example-hook.sh"
hook_script.write_text(HOOK_SCRIPT_TEMPLATE.format(
plugin_name=plugin_name
))
hook_script.chmod(0o755)
print("✅ Created hooks/ with hooks.json and example script")
elif comp == "mcp":
(plugin_dir / ".mcp.json").write_text(MCP_TEMPLATE.format(
plugin_name=plugin_name
))
print("✅ Created .mcp.json")
elif comp == "lsp":
(plugin_dir / ".lsp.json").write_text(LSP_TEMPLATE.format(
plugin_name=plugin_name
))
print("✅ Created .lsp.json")
elif comp == "scripts":
(plugin_dir / "scripts").mkdir(exist_ok=True)
print("✅ Created scripts/")
else:
print(f"⚠️ Unknown component '{comp}', skipping")
except Exception as e:
print(f"❌ Error creating components: {e}")
return None
# Print next steps (maps to plugin-creator skill Steps 4-6)
print(f"\n✅ Plugin '{plugin_name}' scaffolded at {plugin_dir}")
print("\nNext steps:")
print("1. Edit .claude-plugin/plugin.json to complete the TODO description and metadata")
print("2. Implement components — replace TODO items in generated files")
print(" See references/component-patterns.md for format specs and examples")
print("3. For skills, invoke /skill-creator for the full skill methodology")
print("4. Delete any example files not needed for your plugin")
print(f"5. Test locally: claude --plugin-dir {plugin_dir}")
print("6. Debug loading: claude --debug")
return plugin_dir
def main():
if len(sys.argv) < 4 or sys.argv[2] != '--path':
print("Usage: scaffold-plugin.py <plugin-name> --path <path> [--components <list>]")
print("\nPlugin name requirements:")
print(" - Kebab-case identifier (e.g., 'my-plugin')")
print(" - Lowercase letters, digits, and hyphens only")
print(" - Max 64 characters")
print(" - Must match directory name exactly")
print("\nComponents (comma-separated, default: all):")
print(f" {','.join(ALL_COMPONENTS)}")
print("\nExamples:")
print(" scaffold-plugin.py my-plugin --path ./plugins")
print(" scaffold-plugin.py my-plugin --path . --components commands,hooks,mcp")
sys.exit(1)
plugin_name = sys.argv[1]
path = sys.argv[3]
# Parse optional --components
components = list(ALL_COMPONENTS)
i = 4
while i < len(sys.argv):
if sys.argv[i] == '--components' and i + 1 < len(sys.argv):
components = [c.strip() for c in sys.argv[i + 1].split(',')]
i += 2
else:
print(f"❌ Unknown option: {sys.argv[i]}")
sys.exit(1)
# Validate name
if not re.match(r'^[a-z][a-z0-9]*(-[a-z0-9]+)*$', plugin_name):
print(f"❌ Error: '{plugin_name}' is not valid kebab-case")
print(" Use lowercase letters, digits, and hyphens (e.g., 'my-plugin')")
sys.exit(1)
if len(plugin_name) > 64:
print(f"❌ Error: Plugin name exceeds 64 characters")
sys.exit(1)
print(f"🔌 Scaffolding plugin: {plugin_name}")
print(f" Location: {path}")
print(f" Components: {', '.join(components)}")
print()
result = scaffold_plugin(plugin_name, path, components)
if result:
sys.exit(0)
else:
sys.exit(1)
if __name__ == "__main__":
main()