Skip to main content
Claude Code plugins follow a standardized directory structure with automatic component discovery. Understanding this structure is essential for creating well-organized, maintainable plugins.

Standard Directory Structure

Every Claude Code plugin follows this organizational pattern:
plugin-name/
├── .claude-plugin/
│   └── plugin.json          # Required: Plugin manifest
├── commands/                 # Slash commands (.md files)
├── agents/                   # Subagent definitions (.md files)
├── skills/                   # Agent skills (subdirectories)
│   └── skill-name/
│       └── SKILL.md         # Required for each skill
├── hooks/
│   └── hooks.json           # Event handler configuration
├── .mcp.json                 # MCP server definitions
└── scripts/                  # Helper scripts and utilities

Critical Rules

Important: The manifest MUST be in .claude-plugin/ directory. All component directories (commands, agents, skills, hooks) MUST be at plugin root level, NOT nested inside .claude-plugin/.
  1. Manifest location: The plugin.json manifest MUST be in .claude-plugin/ directory
  2. Component locations: All component directories MUST be at plugin root level
  3. Optional components: Only create directories for components the plugin actually uses
  4. Naming convention: Use kebab-case for all directory and file names

Plugin Manifest (plugin.json)

The manifest defines plugin metadata and configuration.

Required Fields

{
  "name": "plugin-name"
}
Name requirements:
  • Use kebab-case format (lowercase with hyphens)
  • Must be unique across installed plugins
  • No spaces or special characters
  • Examples: code-review-assistant, test-runner, api-docs
{
  "name": "plugin-name",
  "version": "1.0.0",
  "description": "Brief explanation of plugin purpose",
  "author": {
    "name": "Author Name",
    "email": "[email protected]",
    "url": "https://example.com"
  },
  "homepage": "https://docs.example.com",
  "repository": "https://github.com/user/plugin-name",
  "license": "MIT",
  "keywords": ["testing", "automation", "ci-cd"]
}
Version format: Follow semantic versioning (MAJOR.MINOR.PATCH) Keywords: Use for plugin discovery and categorization

Custom Component Paths

Specify custom paths for components (supplements default directories):
{
  "name": "plugin-name",
  "commands": "./custom-commands",
  "agents": ["./agents", "./specialized-agents"],
  "hooks": "./config/hooks.json",
  "mcpServers": "./.mcp.json"
}
Custom paths supplement defaults—they don’t replace them. Components in both default directories and custom paths will load.
Path rules:
  • Must be relative to plugin root
  • Must start with ./
  • Cannot use absolute paths
  • Support arrays for multiple locations

Component Organization

Commands

Location: commands/ directory Format: Markdown files with YAML frontmatter Auto-discovery: All .md files in commands/ load automatically
commands/
├── review.md        # /review command
├── test.md          # /test command
└── deploy.md        # /deploy command
File format:
---
name: command-name
description: Command description
argument-hint: [optional-arg]
---

Command implementation instructions...

Agents

Location: agents/ directory Format: Markdown files with YAML frontmatter Auto-discovery: All .md files in agents/ load automatically
agents/
├── code-reviewer.md
├── test-generator.md
└── refactorer.md
File format:
---
description: Agent role and expertise
model: sonnet
tools: [Read, Write, Bash]
color: blue
---

Detailed agent instructions and knowledge...

Skills

Location: skills/ directory with subdirectories per skill Format: Each skill in its own directory with SKILL.md file Auto-discovery: All SKILL.md files in skill subdirectories load automatically
skills/
├── api-testing/
│   ├── SKILL.md
│   ├── scripts/
│   │   └── test-runner.py
│   └── references/
│       └── api-spec.md
└── database-migrations/
    ├── SKILL.md
    └── examples/
        └── migration-template.sql
SKILL.md format:
---
name: Skill Name
description: When to use this skill
version: 1.0.0
---

Skill instructions and guidance...
Supporting files: Skills can include scripts, references, examples, or assets in subdirectories

Hooks

Location: hooks/hooks.json or inline in plugin.json Format: JSON configuration defining event handlers
hooks/
├── hooks.json           # Hook configuration
└── scripts/
    ├── validate.sh      # Hook script
    └── check-style.sh   # Hook script
Configuration format:
{
  "PreToolUse": [{
    "matcher": "Write|Edit",
    "hooks": [{
      "type": "command",
      "command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/validate.sh",
      "timeout": 30
    }]
  }]
}
Available events: PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification

MCP Servers

Location: .mcp.json at plugin root or inline in plugin.json Format: JSON configuration for MCP server definitions
{
  "mcpServers": {
    "server-name": {
      "command": "node",
      "args": ["${CLAUDE_PLUGIN_ROOT}/servers/server.js"],
      "env": {
        "API_KEY": "${API_KEY}"
      }
    }
  }
}

Portable Path References

$

Use ${CLAUDE_PLUGIN_ROOT} environment variable for all intra-plugin path references:
{
  "command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/run.sh"
}
Never use hardcoded absolute paths or relative paths from working directory. Always use $.
Why it matters: Plugins install in different locations depending on:
  • User installation method (marketplace, local, npm)
  • Operating system conventions
  • User preferences
Where to use it:
  • Hook command paths
  • MCP server command arguments
  • Script execution references
  • Resource file paths
Never use:
  • Hardcoded absolute paths (/Users/name/plugins/...)
  • Relative paths from working directory (./scripts/... in commands)
  • Home directory shortcuts (~/plugins/...)

Path Resolution

In manifest JSON fields:
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/tool.sh"
In component files:
Reference scripts at: ${CLAUDE_PLUGIN_ROOT}/scripts/helper.py
In executed scripts:
#!/bin/bash
# ${CLAUDE_PLUGIN_ROOT} available as environment variable
source "${CLAUDE_PLUGIN_ROOT}/lib/common.sh"

File Naming Conventions

Component Files

Commands: Use kebab-case .md files
  • code-review.md/code-review
  • run-tests.md/run-tests
  • api-docs.md/api-docs
Agents: Use kebab-case .md files describing role
  • test-generator.md
  • code-reviewer.md
  • performance-analyzer.md
Skills: Use kebab-case directory names
  • api-testing/
  • database-migrations/
  • error-handling/

Supporting Files

Scripts: Use descriptive kebab-case names with appropriate extensions
  • validate-input.sh
  • generate-report.py
  • process-data.js
Documentation: Use kebab-case markdown files
  • api-reference.md
  • migration-guide.md
  • best-practices.md
Configuration: Use standard names
  • hooks.json
  • .mcp.json
  • plugin.json

Auto-Discovery Mechanism

Claude Code automatically discovers and loads components:
1

Plugin Manifest

Reads .claude-plugin/plugin.json when plugin enables
2

Commands

Scans commands/ directory for .md files
3

Agents

Scans agents/ directory for .md files
4

Skills

Scans skills/ for subdirectories containing SKILL.md
5

Hooks

Loads configuration from hooks/hooks.json or manifest
6

MCP Servers

Loads configuration from .mcp.json or manifest
Discovery timing:
  • Plugin installation: Components register with Claude Code
  • Plugin enable: Components become available for use
  • No restart required: Changes take effect on next Claude Code session

Common Patterns

Minimal Plugin

Single command with no dependencies:
my-plugin/
├── .claude-plugin/
│   └── plugin.json    # Just name field
└── commands/
    └── hello.md       # Single command
Complete plugin with all component types:
my-plugin/
├── .claude-plugin/
│   └── plugin.json
├── commands/          # User-facing commands
├── agents/            # Specialized subagents
├── skills/            # Auto-activating skills
├── hooks/             # Event handlers
│   ├── hooks.json
│   └── scripts/
├── .mcp.json          # External integrations
└── scripts/           # Shared utilities

Skill-Focused Plugin

Plugin providing only skills:
my-plugin/
├── .claude-plugin/
│   └── plugin.json
└── skills/
    ├── skill-one/
    │   └── SKILL.md
    └── skill-two/
        └── SKILL.md

Best Practices

Logical Grouping

Group related components together in subdirectories

Minimal Manifest

Keep plugin.json lean, rely on auto-discovery

Consistent Naming

Use consistent naming across components

Portable Paths

Always use $ for paths

Troubleshooting

Component Not Loading

  • Verify file is in correct directory with correct extension
  • Check YAML frontmatter syntax (commands, agents, skills)
  • Ensure skill has SKILL.md (not README.md or other name)
  • Confirm plugin is enabled in Claude Code settings

Path Resolution Errors

  • Replace all hardcoded paths with ${CLAUDE_PLUGIN_ROOT}
  • Verify paths are relative and start with ./ in manifest
  • Check that referenced files exist at specified paths
  • Test with echo $CLAUDE_PLUGIN_ROOT in hook scripts

Auto-Discovery Not Working

  • Confirm directories are at plugin root (not in .claude-plugin/)
  • Check file naming follows conventions (kebab-case, correct extensions)
  • Verify custom paths in manifest are correct
  • Restart Claude Code to reload plugin configuration

Conflicts Between Plugins

  • Use unique, descriptive component names
  • Namespace commands with plugin name if needed
  • Document potential conflicts in plugin README
  • Consider command prefixes for related functionality

Build docs developers (and LLMs) love