Plugins — Packaging It All
What Are Plugins
Throughout this course you have built individual pieces of automation: skills that guide Claude's behavior, hooks that enforce guardrails, MCP servers that connect external data, and subagents that handle specialized tasks. A plugin is the packaging layer that bundles all of those pieces into a single, distributable unit.
Think of a plugin as a toolbox. Instead of asking every developer on your team to manually copy a SKILL.md here, a hook configuration there, and an MCP server definition somewhere else, you create one plugin that contains everything. Anyone can install it with a single command and immediately gain access to all the functionality inside.
Plugins solve three problems at once: distribution (getting your tools to other people), consistency (everyone runs the same version), and organization (related pieces live together instead of scattered across config files).
Plugin Structure
Every plugin follows a standard directory layout that Claude Code recognizes automatically:
my-plugin/
plugin.json # manifest — name, version, components
commands/ # slash commands
deploy.md
review.md
skills/ # auto-invoked skills
code-style.md
testing-standards.md
hooks/ # hook definitions
pre-commit-lint.sh
agents/ # subagent definitions
security-reviewer.md
.mcp.json # MCP server configurations
The plugin.json file is the manifest. It tells Claude Code what components the plugin provides and how to wire them together. The remaining directories contain the actual component files using the same formats you have already learned in previous lessons.
The plugin.json Manifest
Here is a complete manifest for a full-stack development plugin:
{
"name": "fullstack-toolkit",
"description": "Full-stack development workflows with linting, testing, and deployment",
"version": "1.2.0",
"author": "yourname",
"components": {
"commands": ["commands/deploy.md", "commands/review.md"],
"skills": ["skills/code-style.md", "skills/testing-standards.md"],
"hooks": ["hooks/pre-commit-lint.sh"],
"agents": ["agents/security-reviewer.md"],
"mcp": [".mcp.json"]
},
"settings": {
"defaultBranch": "main",
"testCommand": "npm test"
}
}
The components object maps each type of component to its file paths within the plugin directory. The optional settings object defines configurable values that components can reference. Version numbers follow semantic versioning so consumers know when breaking changes occur.
Installing Plugins
There are several ways to add a plugin to your Claude Code environment:
# Install from a Git repository
/plugin install https://github.com/yourname/fullstack-toolkit
# Install from a local directory (useful during development)
/plugin install ./my-plugin
# Install from npm
/plugin install @yourname/fullstack-toolkit
# List installed plugins
/plugin list
# Remove a plugin
/plugin remove fullstack-toolkit
When you install a plugin, Claude Code copies its contents into your local plugin directory and registers each component. Commands become available as slash commands, skills are loaded into the auto-invocation system, hooks are registered in your settings, and MCP servers are configured in your .mcp.json.
Creating a Plugin From Scratch
Let us build a plugin that enforces code quality standards. Start by creating the scaffold:
mkdir -p quality-gate/{commands,skills,hooks,agents}
cd quality-gate
Create the manifest:
{
"name": "quality-gate",
"description": "Automated code quality enforcement with linting, testing, and security checks",
"version": "0.1.0",
"components": {
"commands": ["commands/check.md"],
"skills": ["skills/quality-standards.md"],
"hooks": ["hooks/pre-push-tests.sh"]
}
}
Add a command in commands/check.md:
---
name: check
description: Run the full quality gate — lint, test, security scan
---
Run the following checks in sequence and report results:
1. Run the project linter: `npm run lint`
2. Run the test suite: `npm test`
3. Run a security audit: `npm audit --production`
Summarize all results in a table showing pass/fail status for each step.
If any step fails, suggest specific fixes for the issues found.
Add a skill in skills/quality-standards.md:
---
triggers:
- file_write
- file_edit
globs: ["**/*.ts", "**/*.tsx"]
---
When writing or editing TypeScript files, follow these standards:
- All functions must have explicit return types
- Use `const` by default, `let` only when reassignment is needed
- Every exported function requires a JSDoc comment
- No `any` types — use `unknown` and narrow with type guards
Add a hook script in hooks/pre-push-tests.sh:
#!/bin/bash
# Run tests before any git push operation
echo "Running quality gate before push..."
npm test --silent
if [ $? -ne 0 ]; then
echo "Tests failed. Push blocked."
exit 1
fi
echo "All tests passed. Proceeding with push."
Auto-Discovery and the Plugin Root Variable
Claude Code automatically discovers components by scanning plugin directories. When it finds a plugin.json, it reads the manifest and registers every listed component. You do not need to manually wire anything after installation.
Inside your plugin files, use the ${CLAUDE_PLUGIN_ROOT} variable to reference other files relative to the plugin root. This keeps paths portable regardless of where the plugin is installed:
Refer to the coding standards defined in ${CLAUDE_PLUGIN_ROOT}/skills/quality-standards.md
when reviewing code changes.
This variable resolves at runtime to the plugin's actual installation path, so your components can reference each other without hardcoded paths.
MCP Servers in Plugins
Plugins can bundle MCP server configurations so that external integrations install automatically. Include a .mcp.json file at the plugin root:
{
"mcpServers": {
"plugin-github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
}
},
"plugin-postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"DATABASE_URL": "${DATABASE_URL}"
}
}
}
}
Environment variables use the ${VAR_NAME} syntax and are resolved from the user's environment at runtime. This means the plugin can define which integrations it needs without embedding any credentials.
Per-Project Plugin Configuration
After installing a plugin, individual projects can customize its behavior through a local configuration file at .claude/plugin-name.local.md:
# Quality Gate — Local Configuration
## Overrides
- Skip security audit in development (run only on CI)
- Use `pnpm` instead of `npm` for all commands
- Add `--coverage` flag to test runs
- Custom lint config path: `./config/.eslintrc.json`
This local configuration is read by Claude Code and merged with the plugin's defaults. It lets each project adapt the plugin without modifying the plugin itself.
Distribution and Sharing
Once your plugin is ready, you have several options for distribution:
Git repository. Push the plugin directory to a Git repo. Anyone can install it with the repo URL. Tag releases for version control.
npm package. Publish the plugin as an npm package for teams that use Node.js toolchains. Add a package.json alongside plugin.json and publish normally.
Team sharing. For internal teams, host plugins in a private Git repository or a shared directory. Document installation in your team's onboarding guide.
Try this: create a simple plugin with one command and one skill, install it locally, and verify that the command appears when you type / in Claude Code.
Best Practices
Keep plugins focused. A plugin should solve one category of problems. A "quality gate" plugin is good. A "quality gate plus deployment plus database management plus analytics" plugin is too broad -- split it into multiple plugins.
Document thoroughly. Include a README in your plugin root that explains what each component does, what environment variables are needed, and any prerequisites.
Version properly. Use semantic versioning. Bump the major version when you change component interfaces, minor for new features, and patch for bug fixes.
Test before distributing. Install your plugin in a fresh project and verify that every component works. Broken plugins erode team trust in the tooling.
Keep secrets out. Never embed API keys, tokens, or passwords in plugin files. Always use environment variable references and document which variables the user needs to set.
With plugins, everything you have learned in this course -- skills, hooks, MCP servers, subagents, and commands -- comes together into a single, portable package that you can share with your team or the broader community.