platform/plugin-development/plugin-structure/SKILL.md
This skill should be used when the user asks to "create a plugin", "scaffold a plugin", "understand plugin structure", "organize plugin components", "set up plugin.json", "use ${CLAUDE_PLUGIN_ROOT}", "add commands/agents/skills/hooks", "configure auto-discovery", or needs guidance on plugin directory layout, manifest configuration, component organization, file naming conventions, or Claude Code plugin architecture best practices.
npx skillsauth add harsh040506/claude-code-unified-skill-plugin-library plugin-structureInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Claude Code plugins follow a standardized directory structure with automatic component discovery. Understanding this structure enables creating well-organized, maintainable plugins that integrate seamlessly with Claude Code.
Key concepts:
.claude-plugin/plugin.json${CLAUDE_PLUGIN_ROOT}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:
Manifest location: The plugin.json manifest MUST be in .claude-plugin/ directory
Why: Claude Code scans for the .claude-plugin/plugin.json path specifically to detect installed plugins. A manifest placed anywhere else (e.g., at plugin root or in a config/ folder) will be silently ignored — the plugin won't load, and no error is surfaced to explain why.
Component locations: All component directories (commands, agents, skills, hooks) MUST be at plugin root level, NOT nested inside .claude-plugin/
Why: Auto-discovery works by scanning known paths relative to plugin root: {plugin-root}/commands/, {plugin-root}/agents/, etc. Components inside .claude-plugin/ are in the manifest's reserved namespace and will not be discovered by the scanner. This is a common structural mistake that results in commands or agents that simply never appear.
Optional components: Only create directories for components the plugin actually uses
Why: Claude Code's scanner checks every component directory it finds. Empty directories don't cause errors, but they add overhead and signal intent that isn't backed by content. More importantly, an empty hooks/ directory without a valid hooks.json can cause confusing behavior if the scanner expects a file. Create only the directories you populate.
Naming convention: Use kebab-case for all directory and file names
Why: Component identifiers derived from filenames (e.g., review-pr from review-pr.md) are normalized to kebab-case in the plugin system's registry. A file named ReviewPR.md or review_pr.md produces a non-standard identifier that may conflict with namespacing rules or fail to match user invocations like /review-pr. Consistent kebab-case eliminates these mismatches.
The manifest defines plugin metadata and configuration. Located at .claude-plugin/plugin.json:
{
"name": "plugin-name"
}
Name requirements:
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
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"
}
Important: Custom paths supplement defaults—they don't replace them. Components in both default directories and custom paths will load.
Path rules:
./Location: commands/ directory
Format: Markdown files with YAML frontmatter
Auto-discovery: All .md files in commands/ load automatically
Example structure:
commands/
├── review.md # /review command
├── test.md # /test command
└── deploy.md # /deploy command
File format:
---
name: command-name
description: Command description
---
Command implementation instructions...
Usage: Commands integrate as native slash commands in Claude Code
Location: agents/ directory
Format: Markdown files with YAML frontmatter
Auto-discovery: All .md files in agents/ load automatically
Example structure:
agents/
├── code-reviewer.md
├── test-generator.md
└── refactorer.md
File format:
---
description: Agent role and expertise
capabilities:
- Specific task 1
- Specific task 2
---
Detailed agent instructions and knowledge...
Usage: Users can invoke agents manually, or Claude Code selects them automatically based on task context
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
Example structure:
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
Usage: Claude Code autonomously activates skills based on task context matching the description
Location: hooks/hooks.json or inline in plugin.json
Format: JSON configuration defining event handlers
Registration: Hooks register automatically when plugin enables
Example structure:
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
Usage: Hooks execute automatically in response to Claude Code events
Location: .mcp.json at plugin root or inline in plugin.json
Format: JSON configuration for MCP server definitions
Auto-start: Servers start automatically when plugin enables
Example format:
{
"mcpServers": {
"server-name": {
"command": "node",
"args": ["${CLAUDE_PLUGIN_ROOT}/servers/server.js"],
"env": {
"API_KEY": "${API_KEY}"
}
}
}
}
Usage: MCP servers integrate seamlessly with Claude Code's tool system
Use ${CLAUDE_PLUGIN_ROOT} environment variable for all intra-plugin path references:
{
"command": "bash ${CLAUDE_PLUGIN_ROOT}/scripts/run.sh"
}
Why it matters — concrete failure illustration:
Suppose you write a hook like this on your development machine:
"command": "bash /Users/alice/plugins/my-plugin/hooks/validate.sh"
This works perfectly on Alice's machine. When Bob installs the same plugin from the marketplace, the plugin lands at /home/bob/.claude/plugins/my-plugin/. The hook runs, resolves /Users/alice/..., finds nothing, and silently fails — the hook never fires for Bob, with no error message explaining why. The same failure applies if Alice moves the plugin to a different folder, renames it, or reinstalls via a different method.
With ${CLAUDE_PLUGIN_ROOT}, the path resolves to the plugin's actual installed location at runtime, regardless of who installed it or where:
"command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/validate.sh"
Where to use it:
Never use:
/Users/name/plugins/...)./scripts/... in commands)~/plugins/...)In manifest JSON fields (hooks, MCP servers):
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/tool.sh"
In component files (commands, agents, skills):
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"
Commands: Use kebab-case .md files
code-review.md → /code-reviewrun-tests.md → /run-testsapi-docs.md → /api-docsAgents: Use kebab-case .md files describing role
test-generator.mdcode-reviewer.mdperformance-analyzer.mdSkills: Use kebab-case directory names
api-testing/database-migrations/error-handling/Scripts: Use descriptive kebab-case names with appropriate extensions
validate-input.shgenerate-report.pyprocess-data.jsDocumentation: Use kebab-case markdown files
api-reference.mdmigration-guide.mdbest-practices.mdConfiguration: Use standard names
hooks.json.mcp.jsonplugin.jsonClaude Code automatically discovers and loads components:
.claude-plugin/plugin.json when plugin enablescommands/ directory for .md filesagents/ directory for .md filesskills/ for subdirectories containing SKILL.mdhooks/hooks.json or manifest.mcp.json or manifestDiscovery timing:
Override behavior: Custom paths in plugin.json supplement (not replace) default directories
Logical grouping: Group related components together
scripts/ for different purposesMinimal manifest: Keep plugin.json lean
Documentation: Include README files
Consistency: Use consistent naming across components
test-runner, name related agent test-runner-agentClarity: Use descriptive names that indicate purpose
api-integration-testing/, code-quality-checker.mdutils/, misc.md, temp.shLength: Balance brevity with clarity
review-pr, run-ci)code-reviewer, test-generator)error-handling, api-design)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
Plugin providing only skills:
my-plugin/
├── .claude-plugin/
│ └── plugin.json
└── skills/
├── skill-one/
│ └── SKILL.md
└── skill-two/
└── SKILL.md
Component not loading:
SKILL.md (not README.md or other name)Path resolution errors:
${CLAUDE_PLUGIN_ROOT}./ in manifestecho $CLAUDE_PLUGIN_ROOT in hook scriptsAuto-discovery not working:
.claude-plugin/)Conflicts between plugins:
For detailed examples and advanced patterns, see files in references/ and examples/ directories.
testing
Performs quality control on single-cell RNA-seq data (.h5ad or .h5 files) using scverse best practices with MAD-based filtering and comprehensive visualizations. Use when users request QC analysis, filtering low-quality cells, assessing data quality, or following scverse/scanpy best practices for single-cell analysis.
tools
Deep learning for single-cell analysis using scvi-tools. This skill should be used when users need (1) data integration and batch correction with scVI/scANVI, (2) ATAC-seq analysis with PeakVI, (3) CITE-seq multi-modal analysis with totalVI, (4) multiome RNA+ATAC analysis with MultiVI, (5) spatial transcriptomics deconvolution with DestVI, (6) label transfer and reference mapping with scANVI/scArches, (7) RNA velocity with veloVI, or (8) any deep learning-based single-cell method. Triggers include mentions of scVI, scANVI, totalVI, PeakVI, MultiVI, DestVI, veloVI, sysVI, scArches, variational autoencoder, VAE, batch correction, data integration, multi-modal, CITE-seq, multiome, reference mapping, latent space.
testing
This skill should be used when scientists need help with research problem selection, project ideation, troubleshooting stuck projects, or strategic scientific decisions. Use this skill when users ask to pitch a new research idea, work through a project problem, evaluate project risks, plan research strategy, navigate decision trees, or get help choosing what scientific problem to work on. Typical requests include "I have an idea for a project", "I'm stuck on my research", "help me evaluate this project", "what should I work on", or "I need strategic advice about my research".
development
Run nf-core bioinformatics pipelines (rnaseq, sarek, atacseq) on sequencing data. Use when analyzing RNA-seq, WGS/WES, or ATAC-seq data—either local FASTQs or public datasets from GEO/SRA. Triggers on nf-core, Nextflow, FASTQ analysis, variant calling, gene expression, differential expression, GEO reanalysis, GSE/GSM/SRR accessions, or samplesheet creation.