You have built custom skills, configured agents, and wired up hooks in your .claude/ directory. That works well for a single project, but the moment you want the same functionality across multiple repositories or shared with teammates, copy-pasting files breaks down. Plugins solve this by packaging your extensions into portable, versioned units that anyone can install with a single command.
In this lesson, you will learn the full plugin lifecycle: creating the manifest, bundling components, testing locally, managing costs along the way, and distributing plugins to your team or the community.
Learning Objectives
- Understand the plugin architecture and how it differs from standalone .claude/ configuration
- Create a plugin.json manifest with proper metadata and component paths
- Bundle skills, agents, hooks, and MCP servers into a distributable plugin
- Test plugins locally with --plugin-dir before publishing
- Track session costs with /cost and manage token spending across plugin development
What Are Plugins?
Plugins are self-contained packages that extend Claude Code with custom skills, agents, hooks, MCP servers, and LSP servers. Unlike standalone configuration files that live in your .claude/ directory, plugins are installable, versioned, and shareable.
The key difference is namespacing. A skill in .claude/commands/review.md creates /review. The same skill inside a plugin named code-tools creates /code-tools:review. This prevents naming collisions when multiple plugins define similarly named commands.
Here is a quick comparison of when to use each approach:
| Approach | Skill name | Best for |
|---|---|---|
Standalone (.claude/ directory) | /review | Personal workflows, single-project customization, quick experiments |
Plugin (.claude-plugin/plugin.json) | /code-tools:review | Sharing with teammates, cross-project reuse, versioned releases |
Start standalone, convert later
Begin by prototyping in .claude/ for fast iteration. Once your skills and hooks stabilize, convert them into a plugin for distribution. The conversion process is straightforward and covered later in this lesson.
Plugin Structure
Every plugin lives in its own directory. The only special directory is .claude-plugin/, which holds the manifest. Everything else sits at the plugin root:
my-plugin/
├── .claude-plugin/ # Metadata directory
│ └── plugin.json # Plugin manifest (only file here)
├── commands/ # Slash commands (markdown files)
│ └── deploy.md
├── skills/ # Agent Skills (SKILL.md in subdirectories)
│ └── code-review/
│ └── SKILL.md
├── agents/ # Custom subagents
│ └── security-reviewer.md
├── hooks/ # Event handlers
│ └── hooks.json
├── .mcp.json # MCP server configurations
├── .lsp.json # LSP server configurations
└── scripts/ # Supporting scripts for hooks
└── format-code.sh
Directory placement matters
A common mistake is placing commands/, agents/, or skills/ inside .claude-plugin/. Only plugin.json belongs in .claude-plugin/. All component directories must be at the plugin root.
The plugin.json Manifest
The manifest at .claude-plugin/plugin.json defines your plugin's identity and configuration. The only required field is name, but a well-documented manifest makes your plugin easier to discover and maintain.
Here is a complete example:
{
"name": "deployment-tools",
"version": "1.2.0",
"description": "Deployment automation skills and pre-deploy safety checks",
"author": {
"name": "DevOps Team",
"email": "devops@company.com",
"url": "https://github.com/company"
},
"homepage": "https://docs.company.com/claude-plugins/deployment-tools",
"repository": "https://github.com/company/deployment-tools-plugin",
"license": "MIT",
"keywords": ["deployment", "ci-cd", "automation"]
}Here is what each field does:
| Field | Required | Description |
|---|---|---|
name | Yes | Unique identifier in kebab-case. Becomes the namespace prefix for all skills. |
version | No | Semantic version (MAJOR.MINOR.PATCH). Start at 1.0.0 for stable releases. |
description | No | Shown in the plugin manager when browsing or installing. |
author | No | Attribution with name, email, and URL fields. |
homepage | No | Link to documentation. |
repository | No | Link to source code. |
license | No | SPDX identifier like MIT or Apache-2.0. |
keywords | No | Tags for discovery and search. |
You can also specify custom component paths if your directories do not follow the default layout:
{
"name": "my-plugin",
"commands": ["./custom/commands/"],
"agents": ["./custom/agents/reviewer.md"],
"skills": "./custom/skills/",
"hooks": "./config/hooks.json",
"mcpServers": "./mcp-config.json"
}Custom paths supplement default directories. If both commands/ and a custom path exist, both are loaded.
Creating a Plugin Step-by-Step
Let us build a plugin called pr-helper that adds a code review skill and a specialized review agent.
Create the plugin directory and manifest
Set up the directory structure and write the manifest:
mkdir -p pr-helper/.claude-plugin
mkdir -p pr-helper/skills/review
mkdir -p pr-helper/agentsCreate pr-helper/.claude-plugin/plugin.json:
{
"name": "pr-helper",
"version": "1.0.0",
"description": "PR review skill and specialized review agent",
"author": {
"name": "Your Name"
}
}Add a skill
Skills live in subdirectories under skills/, each containing a SKILL.md file. Create pr-helper/skills/review/SKILL.md:
---
name: review
description: Reviews code changes for bugs, security issues, and best practices. Use when reviewing PRs or analyzing code quality.
---
When reviewing code, check for:
1. **Correctness**: Logic errors, off-by-one mistakes, unhandled edge cases
2. **Security**: SQL injection, XSS, hardcoded secrets, unsafe deserialization
3. **Performance**: N+1 queries, unnecessary re-renders, missing indexes
4. **Readability**: Unclear naming, missing comments on non-obvious logic
5. **Test coverage**: Untested branches, missing edge case tests
Format findings as a numbered list with severity (critical/warning/suggestion) and specific line references.After installing, Claude can invoke this skill automatically when the task context matches, or you can call it manually with /pr-helper:review.
Add an agent
Agents are markdown files in the agents/ directory with frontmatter defining their name and description. Create pr-helper/agents/security-reviewer.md:
---
name: security-reviewer
description: Specialized agent that audits code changes for security vulnerabilities, unsafe patterns, and compliance issues.
---
You are a security-focused code reviewer. When invoked, perform a thorough security audit of the code or changes presented to you.
Focus areas:
- Authentication and authorization flaws
- Input validation and sanitization gaps
- Sensitive data exposure (API keys, tokens, PII in logs)
- Dependency vulnerabilities (known CVEs in imported packages)
- Injection attacks (SQL, command, template)
- Insecure cryptographic practices
For each finding, provide:
1. Severity level (Critical / High / Medium / Low)
2. Location (file and line)
3. Description of the vulnerability
4. Recommended fix with a code example
If no security issues are found, state that explicitly with a brief summary of what was checked.This agent appears in the /agents list and can be invoked by Claude automatically when security-related review tasks arise.
Add hooks (optional)
Hooks let your plugin respond to Claude Code events automatically. Create pr-helper/hooks/hooks.json to run a linter after every file edit:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/lint-check.sh"
}
]
}
]
}
}The ${CLAUDE_PLUGIN_ROOT} variable resolves to the plugin's installation directory at runtime, ensuring paths work regardless of where the plugin is installed.
Available hook events include PreToolUse, PostToolUse, SessionStart, SessionEnd, Stop, and several others. Hook types can be command (run a shell script), prompt (evaluate with an LLM), or agent (run an agentic verifier).
Add MCP servers (optional)
If your plugin needs to connect Claude to external tools, add an .mcp.json at the plugin root:
{
"mcpServers": {
"pr-database": {
"command": "${CLAUDE_PLUGIN_ROOT}/servers/pr-db-server",
"args": ["--config", "${CLAUDE_PLUGIN_ROOT}/config.json"],
"env": {
"DB_PATH": "${CLAUDE_PLUGIN_ROOT}/data"
}
}
}
}Plugin MCP servers start automatically when the plugin is enabled and appear as standard tools in Claude's toolkit.
Testing Locally
Use the --plugin-dir flag to load your plugin during development without installing it:
claude --plugin-dir ./pr-helperOnce Claude Code starts, verify your plugin works:
- Run
/pr-helper:reviewto test the skill - Run
/agentsto confirm the security-reviewer agent appears - Make a file edit to trigger any PostToolUse hooks
- Run
/helpto see your commands listed under the plugin namespace
You can load multiple plugins simultaneously:
claude --plugin-dir ./pr-helper --plugin-dir ./deploy-toolsIf something is not working, run with the debug flag for detailed loading information:
claude --debug --plugin-dir ./pr-helperThis shows which plugins are being loaded, any manifest errors, and component registration details.
Restart after changes
Changes to plugin files require restarting Claude Code. The --plugin-dir flag reads files at startup, not on every command invocation.
Debugging Checklist
| Issue | Likely cause | Solution |
|---|---|---|
| Plugin not loading | Invalid JSON in plugin.json | Validate syntax with claude plugin validate . |
| Commands not appearing | Wrong directory structure | Move commands/ to plugin root, not inside .claude-plugin/ |
| Hooks not firing | Script not executable | Run chmod +x scripts/lint-check.sh |
| MCP server fails | Missing ${CLAUDE_PLUGIN_ROOT} | Use the variable for all paths in hook and MCP configs |
| Path errors after install | Absolute paths used | All paths must be relative and start with ./ |
Cost Management with /cost
Plugin development involves frequent testing cycles, and each interaction with Claude Code consumes API tokens. Keeping an eye on costs prevents surprises, especially when running multiple plugin-loaded sessions.
Checking Session Costs
Run /cost at any point during a session to see your current token usage:
Total cost: $0.55
Total duration (API): 6m 19.7s
Total duration (wall): 6h 33m 10.2s
Total code changes: 0 lines added, 0 lines removed
This shows cumulative API cost, time spent on API calls versus wall-clock time, and a summary of code changes made during the session.
Reducing Costs During Development
Several strategies help keep plugin development affordable:
- Use
/clearbetween test runs: Stale context from previous tests wastes tokens on every subsequent message. Clear the conversation when switching between testing different plugin components. - Choose the right model: Use
/modelto switch to Sonnet for routine testing. Reserve Opus for complex debugging sessions. For subagent tasks within plugins, specifymodel: haikuin agent configuration. - Minimize MCP server overhead: Each MCP server adds tool definitions to context even when idle. Disable servers you are not actively testing with
/mcp. - Write specific test prompts: "Test the review skill on auth.ts" is cheaper than "test everything in the plugin."
Team Budget Management
For API users, workspace spend limits can be configured in the Anthropic Console. Admins can set per-workspace budgets and view cost and usage reporting. The average cost is roughly $6 per developer per day, with 90% of users staying below $12 per day.
Subscription users
If you are on Claude Max or Pro, usage is included in your subscription and /cost data is not relevant for billing. Use /stats instead to view usage patterns.
Installing Plugins
Once a plugin is published or available from a marketplace, users install it through the /plugin interface or CLI commands.
From a Marketplace
The primary installation method uses marketplaces, which are catalogs of plugins hosted on GitHub, GitLab, or other git services:
# Add a marketplace first
/plugin marketplace add your-org/claude-plugins
# Then install a specific plugin
/plugin install pr-helper@your-org-claude-pluginsInstallation Scopes
When installing a plugin, you choose a scope that determines visibility:
| Scope | Settings file | Use case |
|---|---|---|
user | ~/.claude/settings.json | Personal plugins across all projects (default) |
project | .claude/settings.json | Team plugins shared via version control |
local | .claude/settings.local.json | Project-specific plugins, gitignored |
# Install to project scope so the entire team gets it
claude plugin install pr-helper@my-marketplace --scope projectManaging Installed Plugins
# List and manage via interactive UI
/plugin
# Disable without uninstalling
/plugin disable pr-helper@my-marketplace
# Re-enable
/plugin enable pr-helper@my-marketplace
# Remove completely
/plugin uninstall pr-helper@my-marketplace
# Update to latest version
/plugin update pr-helper@my-marketplaceSharing and Distributing Plugins
Creating a Marketplace
A marketplace is a repository containing a .claude-plugin/marketplace.json file that catalogs your plugins:
{
"name": "acme-tools",
"owner": {
"name": "Acme DevTools Team",
"email": "devtools@acme.com"
},
"plugins": [
{
"name": "pr-helper",
"source": "./plugins/pr-helper",
"description": "PR review skill and security audit agent",
"version": "1.0.0"
},
{
"name": "deploy-tools",
"source": {
"source": "github",
"repo": "acme/deploy-tools-plugin"
},
"description": "Deployment automation and safety checks"
}
]
}Plugin sources can be relative paths (for monorepo-style marketplaces), GitHub repositories, git URLs, npm packages, or pip packages.
Hosting on GitHub
Push your marketplace repository to GitHub and share with teammates:
# Teammates add the marketplace
/plugin marketplace add acme/claude-plugins
# Then install individual plugins
/plugin install pr-helper@acme-claude-pluginsFor private repositories, Claude Code uses your existing git credential helpers. If git clone works for the repo in your terminal, it works in Claude Code.
Team-Wide Configuration
To automatically prompt team members to install your marketplace when they clone a project, add this to .claude/settings.json:
{
"extraKnownMarketplaces": {
"acme-tools": {
"source": {
"source": "github",
"repo": "acme/claude-plugins"
}
}
},
"enabledPlugins": {
"pr-helper@acme-tools": true,
"deploy-tools@acme-tools": true
}
}When team members trust the repository folder, Claude Code prompts them to install these marketplaces and plugins automatically.
Validating Before Distribution
Always validate your marketplace before sharing:
# Validate from the marketplace directory
claude plugin validate .
# Or from within Claude Code
/plugin validate .This catches JSON syntax errors, missing required fields, invalid source paths, and duplicate plugin names.
Converting Standalone Config to a Plugin
If you already have working skills and hooks in your .claude/ directory, migration is straightforward:
Create the plugin structure
mkdir -p my-plugin/.claude-pluginCreate my-plugin/.claude-plugin/plugin.json with your chosen name and version.
Copy existing components
cp -r .claude/commands my-plugin/
cp -r .claude/agents my-plugin/
cp -r .claude/skills my-plugin/Migrate hooks
If you have hooks in settings.json, extract the hooks object into my-plugin/hooks/hooks.json. The format is identical. Update any paths to use ${CLAUDE_PLUGIN_ROOT} instead of relative project paths.
Test the migrated plugin
claude --plugin-dir ./my-pluginVerify that all commands, agents, and hooks work as expected under the new namespace.
After migration, skill names change from /review to /my-plugin:review. Update any documentation or team instructions that reference the old names.
Build and Test a Plugin
intermediate25 minCreate a plugin called quality-gate with one skill and one agent, then test it locally.
Part 1: Create the plugin
- Create the directory structure:
.claude-plugin/,skills/check/, andagents/ - Write
plugin.jsonwith namequality-gate, version1.0.0, and a description - Create
skills/check/SKILL.mdthat instructs Claude to verify code quality by checking for missing error handling, console.log statements left in production code, and TODO comments that should be resolved - Create
agents/style-enforcer.mdwith frontmatter (name: style-enforcer,description) and a system prompt that focuses on code style consistency: naming conventions, import ordering, and file organization
Part 2: Test locally
- Run
claude --plugin-dir ./quality-gateand verify:/quality-gate:checkis available (run/helpto confirm)- The style-enforcer agent appears in
/agents
- Try the check skill on a file in any project
Part 3: Track costs
- Run
/costto see how much the testing session consumed - Run
/clearand run/costagain to see the reset
Bonus: Add a hooks/hooks.json that runs a PostToolUse hook after every Write or Edit event, echoing a reminder message. Test that it fires when Claude edits a file.
Key Takeaway
Plugins package your Claude Code extensions (skills, agents, hooks, MCP servers) into portable, versioned units that anyone can install with a single command. Every plugin needs a .claude-plugin/plugin.json manifest at minimum, with components in standard directories at the plugin root. Test locally with claude --plugin-dir ./your-plugin before publishing. Distribute through marketplace repositories hosted on GitHub or internal git servers. Use /cost to monitor spending during development, and choose the right model and context management strategies to keep costs down. Start with standalone .claude/ configuration for rapid prototyping, then convert to a plugin when you are ready to share.
Next Steps
You now know how to create, test, and distribute plugins. In the final lesson of this course, we will pull everything together with real-world workflows that combine skills, agents, hooks, and plugins into a complete Claude Code power-user setup.