How to create a Claude Code plugin, step by step
Build a minimal Claude Code plugin: plugin.json, one skill, claude plugin validate, --plugin-dir, reload and debug, checked against the official docs.
To create a Claude Code plugin you need a directory, a .claude-plugin/plugin.json manifest and at least one component such as a skill. This guide builds the smallest useful one and tests it locally, following the official Create a Claude Code plugin page, which showed a last-modified date of 2026-10-10 when we checked it. Commands and version requirements change between releases, so confirm against the current docs.
What a Claude Code plugin is and when you need one
A plugin bundles skills, agents, hooks and MCP servers under one directory with a manifest. Per the docs, skills, agents, hooks and MCP servers all work standalone in a project or home directory, and you should keep that setup while it serves one project or only you. Make a plugin when you want to share the setup with teammates, install it in several projects, or publish versioned releases.
The visible change is naming: plugin skills and agents get the plugin name as a prefix, such as /my-plugin:hello, so two plugins can each provide a hello skill without colliding. If you have not written a skill yet, start with Claude Code skills.
Plugin layout: what goes where
Each component type has a fixed place under the plugin root, which is the directory you pass to --plugin-dir. From the plugin layout section:
| Location | Contents |
|---|---|
.claude-plugin/plugin.json |
The manifest |
skills/ |
One <name>/SKILL.md directory per skill |
commands/ |
Flat Markdown files, the older form of skills; use skills/ for new plugins |
agents/ |
One Markdown file per subagent |
hooks/hooks.json |
Hook configuration under a top-level "hooks" key |
.mcp.json |
MCP server definitions |
The common mistake is putting components in the wrong place. The docs warn that only plugin.json goes inside .claude-plugin/, and components saved there do not load.
Step 1: create the directory and plugin.json
mkdir -p my-first-plugin/.claude-plugin
Save this as my-first-plugin/.claude-plugin/plugin.json, the example from the walkthrough:
{
"name": "my-first-plugin",
"description": "A greeting plugin to learn the basics",
"version": "1.0.0",
"author": {
"name": "Your Name"
}
}
name is required and becomes the prefix on every skill and agent; do not put spaces in it. description is what users see in /plugin. version is optional, and setting it keeps users on that version until you change it. author needs a name if present. The manifest reference lists every other field.
Step 2: add a skill
mkdir -p my-first-plugin/skills/hello
Create my-first-plugin/skills/hello/SKILL.md:
---
name: hello
description: Greet the user with a friendly message
disable-model-invocation: true
---
Greet the user warmly and ask how you can help them today.
disable-model-invocation: true stops Claude from running the skill on its own; remove it for a skill Claude should trigger itself. The command is the plugin name plus the skill name: /my-first-plugin:hello.
Step 3: validate with claude plugin validate
claude plugin validate ./my-first-plugin
Per the docs, this checks the manifest and the frontmatter of every skill, agent and command file, and exits 0 on Validation passed. Add --strict to fail on warnings too. A failure names the field to fix; the troubleshooting page explains each message.
Step 4: load it with –plugin-dir and run it
claude --plugin-dir ./my-first-plugin
Then, inside the session:
/my-first-plugin:hello
Claude replies with a greeting. The plugin loads only in sessions started with the flag. Per Develop without a marketplace, --plugin-dir accepts a directory or a .zip, can be repeated, and --plugin-url fetches a .zip from a URL. Loading a folder that holds several plugins requires Claude Code v2.1.265 or later. The CLAUDE_CODE_PLUGIN_DIRS environment variable is the option when you cannot add a flag.
To have the plugin load in every session without the flag, the docs describe claude plugin init my-tool, which scaffolds a plugin under ~/.claude/skills/.
Add hooks, agents or an MCP server
Add only the directories you use. Agents go in agents/ as one Markdown file each. Hooks go in hooks/hooks.json with a top-level "hooks" key whose value has the same shape as hooks in a settings file, so the examples in Claude Code hooks examples carry over. MCP servers go in .mcp.json at the plugin root. The plugin components page covers each one, including LSP servers and user configuration.
Test and debug: /reload-plugins, /plugin Errors tab, claude plugin list
The docs give this order of checks when a change does not show up:
claude plugin validate <path>in your shell./reload-pluginsin the session to apply edits made on disk, then run the skill’s command or look in the/pluginInstalled tab./plugin, Errors tab, which lists what failed to load and why.claude plugin listin your shell, which showsStatus: ✔ loadedor the load error. Pass--plugin-dirwith the plugin path beforeplugin listto include the plugin you are developing.
For MCP servers use /mcp. For hooks, trigger the event and read the debug log. Three documented failures:
<component> path not foundin the Errors tab: a path in your manifest points at nothing.- Skills missing:
skills/is inside.claude-plugin/, or askillsmanifest entry points at a file instead of a directory containingSKILL.md. - Nothing loads and no error:
--plugin-dirpoints at a marketplace root instead of one plugin folder.
The userConfig dialog does not appear with --plugin-dir; run /plugin configure <plugin-name>. To check the plugin actually changes Claude’s behavior, the docs point to claude plugin eval and Test plugins with evals.
Share it
The docs list three routes: send the directory or a .zip to a few people, list it in your own marketplace so teammates install it by name, or submit it to Anthropic’s directory. Details are on the publish page. Anthropic also provides the plugin-dev plugin from the claude-plugins-official marketplace, whose /plugin-dev:create-plugin command walks you through designing and validating a larger plugin.
What to change in your setup
The first three items follow the docs; the last two are our own judgment.
- Run the walkthrough once to learn the layout, then validate and load your own plugin with
claude plugin validateand--plugin-dir. - To convert a project’s
.claude/files, follow Convert an existing.claude/setup: createmy-plugin/.claude-plugin/plugin.json, thencp -rthecommands,agentsandskillsfolders you have into the plugin root. - Move hooks by copying the
hooksobject from.claude/settings.jsonintomy-plugin/hooks/hooks.json; the format is the same. While the originals remain, a hook present in both places runs twice, and skills appear both as/deployand/my-plugin:deploy. After testing, delete the originals and remove thehooksobject from settings. - Our inference: if the setup serves only you or one repository, keeping standalone files is simpler, as the docs themselves suggest.
- Our inference: update any saved commands or notes to the prefixed form, such as
/my-plugin:deploy, once you switch.
FAQ
- Is plugin.json required to create a Claude Code plugin?
- No. The manifest is optional. If you load a plugin with --plugin-dir and it has no manifest, Claude Code names the plugin after its directory. When you do write one, name is the only required field.
- Where does the skills folder go in a Claude Code plugin?
- At the plugin root, next to .claude-plugin/. Only plugin.json goes inside .claude-plugin/; components saved there do not load.
- How do I pick up edits without restarting Claude Code?
- Run /reload-plugins in the session. It applies the changes you made on disk and prints one Reloaded line with counts.
- Does the userConfig dialog show when I load a plugin with --plugin-dir?
- No. Run /plugin configure followed by the plugin name in the session to open it.