Skip to main content
A plugin is a directory of skills, agents, hooks, and MCP servers, plus a plugin.json file, called the manifest, that names the plugin. Claude Code loads the directory as one unit, so you can share it with teammates, install it in several projects, or publish it to a marketplace. This page is for people writing their own plugins.
These cases are covered on other pages:
Start from the section that matches what you already have:

Decide when to use a plugin

Skills, agents, hooks, and MCP servers all work standalone in your project or home directory. Keep that standalone 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. When you move standalone skills, agents, hooks, and MCP config into a plugin, their location and names change:
  • Where the files go: under the plugin’s own directory, called the plugin root, as skills/, agents/, hooks/hooks.json, and .mcp.json.
  • How they’re named: 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.
To move an existing setup into a plugin, see Convert an existing .claude/ setup.

Create your first plugin

In this walkthrough, you create a plugin whose only component is one skill, a greeting, and run it with --plugin-dir, which loads a plugin for one session without installing it. A plugin can hold any mix of components, such as skills, agents, hooks, and MCP servers, and none is required; one skill is the smallest example that shows the layout. You need Claude Code installed and signed in. Open a terminal in the directory where you want to keep the plugin, such as ~/projects, and run the commands in these steps from it. You can keep a plugin anywhere, because you pass its path to Claude Code when you start a session.
1

Create the plugin directory

Create the plugin directory, with a .claude-plugin/ folder inside it to hold the manifest:
2

Write the manifest

The manifest is a JSON file named plugin.json that tells Claude Code the plugin’s name and describes it. Save this one as my-first-plugin/.claude-plugin/plugin.json:
my-first-plugin/.claude-plugin/plugin.json
The four fields do this:
  • name: required. It identifies the plugin and becomes the prefix on every skill and agent the plugin provides. Don’t put spaces in it.
  • description: the text users see for the plugin in /plugin.
  • version: optional. Setting it keeps users on that version until you change it; Release a new version says when to set or omit it.
  • author: who to credit. name is required inside it; email and url are optional.
Every other field is on the manifest reference.Only plugin.json goes inside .claude-plugin/. The skill you add next goes directly under my-first-plugin/, next to that folder.
3

Add a skill

This plugin’s one component is a skill. Each skill is a directory under skills/ that contains a SKILL.md file. Create the skill’s directory:
Then create my-first-plugin/skills/hello/SKILL.md with this content:
my-first-plugin/skills/hello/SKILL.md
The disable-model-invocation: true line means Claude doesn’t run the skill on its own, so only you trigger it. Remove that line from a skill you want Claude to run on its own. The skill’s command combines the plugin name and the skill’s name, so you run this one as /my-first-plugin:hello. For the other frontmatter fields, see the skill frontmatter reference.
4

Validate the plugin

Check the manifest and the skill’s frontmatter before you run anything:
The command prints the manifest path it checked and ✔ Validation passed. If it prints ✘ Validation failed instead, each line above that result line names the field to fix. Look up each message under claude plugin validate reports errors.
5

Run Claude Code with the plugin

Start a session with the plugin loaded:
Once Claude Code starts, run the skill:
Claude replies with a greeting.
The plugin loads only in sessions you start with --plugin-dir. To keep working on it without the flag, or to test a .zip build, see Develop without a marketplace.

Share your plugin

A plugin you built with Create your first plugin exists only on your machine. When it’s ready for other people, there are three ways to get it to them:

Plugin layout

Each kind of component, such as skills, agents, hooks, and MCP servers, goes in a fixed directory under the plugin root, which is the directory you pass to --plugin-dir. Add only the directories you use. To click through a complete plugin directory and read what each file does, open the plugin explorer. The table lists the directories most plugins start with, and the full layout lists the rest.
Only plugin.json goes inside .claude-plugin/. Components saved there don’t load.The plugin root is the plugin’s own directory, not ~/.claude/ itself. A .mcp.json saved at ~/.claude/.mcp.json doesn’t load.

Develop without a marketplace

You don’t need a marketplace to run a plugin you’re writing. Load it directly from disk or a URL instead:
  • --plugin-dir: loads a directory or .zip archive for one session.
  • --plugin-url: fetches a .zip archive from a URL for one session.
  • claude plugin init: scaffolds a plugin under ~/.claude/skills/ that loads every session.
If two plugins loaded in different ways share a name, see Name conflicts for which one Claude Code keeps.

Load a plugin for one session

You can load a plugin for a single session in three ways: from a directory or .zip archive on disk with --plugin-dir, from a URL with --plugin-url, or from an environment variable when you can’t add a flag. Each plugin loads for that session only, and nothing is written to your settings for it. When you edit the plugin’s files during the session, run /reload-plugins to load the changes.

From a directory or .zip

When you start claude from your shell, pass --plugin-dir with the plugin’s root directory or a .zip archive of it. Repeat the flag to load several plugins:

From a folder of plugins

To load several plugins from one place, pass a folder that holds them, such as --plugin-dir ./plugins. Loading a folder of plugins requires Claude Code v2.1.265 or later. If the folder has no .claude-plugin/ directory and no plugin components at its top level, Claude Code treats it as a folder of plugins. Each immediate subfolder that has a .claude-plugin/plugin.json manifest then loads as a separate plugin. Everything else in the folder is skipped without an error, including a subfolder that has no manifest. If a plugin in the folder doesn’t load, check that its subfolder has a .claude-plugin/plugin.json. In an interactive session, you can also add and remove plugins in the folder after startup:
  • A subfolder you add loads as a new plugin once its manifest exists.
  • When you remove a subfolder, its plugin unloads.
A message appears in the session for each of these changes. If loading or unloading a plugin mid-conversation would invalidate the prompt cache, the change is held instead, and the message tells you to run /reload-plugins to apply it.

From a URL

When you start claude from your shell, pass --plugin-url with the address of a .zip archive, such as a build artifact your CI publishes:
Claude Code downloads the archive at startup. To load several, repeat the flag or pass the URLs space-separated in one quoted argument. Point the flag only at archives you control or trust. If Claude Code can’t fetch the archive, or the archive is invalid, it starts without the plugin and records a plugin load error that you can review in the /plugin manager’s Errors tab.

From an environment variable

To load plugins in a session where you can’t add the --plugin-dir flag, list their absolute paths in the CLAUDE_CODE_PLUGIN_DIRS environment variable instead. Claude Code loads each path as it loads a --plugin-dir path. These plugins load in addition to any you pass with --plugin-dir. Project and local settings can’t set this variable. CLAUDE_CODE_PLUGIN_DIRS requires Claude Code v2.1.280 or later. Managed settings can turn off --plugin-dir and CLAUDE_CODE_PLUGIN_DIRS. See Flags that load a plugin for one session. To test a plugin together with a plugin it depends on, see Test a plugin and its dependency locally.

Make a plugin load in every session

Your personal skills directory is ~/.claude/skills/. Claude Code loads any folder there that contains a .claude-plugin/plugin.json as a plugin in every session, with no flag and no install step. claude plugin init scaffolds one of these plugins for you.

Scaffold the plugin with claude plugin init

claude plugin init writes a starter plugin under ~/.claude/skills/. Requires Claude Code v2.1.157 or later. Scaffold one from your shell:
The command creates ~/.claude/skills/my-tool/ with a .claude-plugin/plugin.json and a root SKILL.md. It prints ✔ Created plugin "my-tool" at ~/.claude/skills/my-tool followed by It will auto-load next session as my-tool@skills-dir. Run /reload-plugins to load it now. Pass --with skills to have claude plugin init scaffold a skill under skills/ for you. The other --with values are on the plugin commands reference.

Name the plugin’s skills

The root skill at ~/.claude/skills/my-tool/SKILL.md is also a personal skill, so you invoke it as /my-tool, not /my-tool:my-tool. Skills you add under skills/ inside the plugin get the plugin-name prefix, such as /my-tool:example.

Stop loading the plugin

To stop loading a scaffolded plugin, delete its directory, or run claude plugin disable my-tool@skills-dir in your shell with the my-tool@skills-dir name that claude plugin init printed. In the ID my-tool@skills-dir, skills-dir stands where a marketplace name would, because the plugin loads from your skills directory rather than from a marketplace.

Share the plugin through a repository

claude plugin init writes the plugin to your personal skills directory at ~/.claude/skills/, so it loads for you in every project. To make a plugin load for everyone in one repository, create the same layout yourself at <project>/.claude/skills/<name>/, including its .claude-plugin/plugin.json. See Plugins shared through a repository for the conditions under which Claude Code loads it.

Test and debug

When a change to your plugin doesn’t show up, work through these checks in order. Each one tells you what Claude Code did with the plugin:
  1. In your shell, run claude plugin validate <path>. It 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. Exit codes and directory handling are on the plugin commands reference.
  2. In the running session, run /reload-plugins to apply edits you made on disk. It prints one Reloaded: line with counts. Then confirm a skill loaded by typing its /plugin-name:skill command, or by finding the plugin in the /plugin Installed tab.
  3. In the same session, run /plugin. The Installed tab lists your plugin and, in the plugin’s details, the components Claude Code found. The Errors tab lists what failed to load and why, such as a path in your manifest that doesn’t exist.
  4. Back in your shell, run claude plugin list. It prints session-only and skills-directory plugins in their own sections with Status: ✔ loaded or the load error. To include the plugin you’re developing, pass --plugin-dir with its path before plugin list.
To check an MCP server, run /mcp in the session to see the server’s status. When the server is healthy, /mcp lists it as connected. If it isn’t, see MCP servers that don’t start. To check a hook, trigger the event it matches. For example, ask Claude to edit a file to trigger a PostToolUse hook. Then read the debug log, which shows which hooks matched, their exit codes, and their output. The next sections cover the failures you’re most likely to hit while developing, and the troubleshooting page has the full entry for each.

A component path isn’t found

The Errors tab of /plugin shows <component> path not found: <path>, for example commands path not found. A component path in your manifest, such as commands, skills, agents, or hooks, points at nothing. Fix the path or create the directory, then run /reload-plugins in the session. See commands path not found.

--plugin-dir at a marketplace root doesn’t load the plugins under plugins/

--plugin-dir takes the plugin’s root directory, the one that contains .claude-plugin/plugin.json and the component directories such as skills/. If you point it at a marketplace root instead, Claude Code doesn’t read marketplace.json, so a plugin under plugins/ doesn’t load, and you see no error. Point the flag at one plugin’s folder, or add the marketplace. See the troubleshooting entry.

The plugin loads but its skills are missing

The skills/ directory is inside .claude-plugin/, or a skills entry in the manifest points at a file. Move skills/ to the plugin root, point each skills entry at a directory that contains SKILL.md, and run /reload-plugins in the session. See Plugin loads but its skills are missing.

The userConfig dialog never appears

The dialog for your plugin’s userConfig options is part of installing through /plugin in a session. Loading with --plugin-dir doesn’t show it, and neither does claude plugin install in the shell. With the plugin loaded, run /plugin configure <plugin-name> in the session to open it. See The userConfig dialog never appears.

Check that the plugin changes Claude’s behavior

A plugin that loads without errors can still fail to steer Claude the way you intend. claude plugin eval, which you run in your shell, runs your test cases with and without the plugin and scores the difference. See Test plugins with evals, starting with Create your first eval suite.

Convert an existing .claude/ setup

If you already have skills, agents, or hooks under a project’s .claude/ directory, you can move them into a plugin without rewriting them. Run the commands in these steps from the project root, which is the directory that contains .claude/, because the cp paths are relative to it.
1

Create the plugin structure

Create the plugin directory and its .claude-plugin/ folder alongside .claude/. You can move the plugin anywhere afterwards.
Create my-plugin/.claude-plugin/plugin.json:
my-plugin/.claude-plugin/plugin.json
2

Copy your existing files

Copy each configuration directory you have to the plugin root, and skip the command for any directory you don’t have.
Run ls -a my-plugin to confirm that each directory you copied appears next to .claude-plugin.
3

Move your hooks

If you have hooks in .claude/settings.json or .claude/settings.local.json, create a hooks directory:
Create my-plugin/hooks/hooks.json and copy the hooks object from your settings file into it. The format is the same.This example shows the shape with one hook that runs a linter on each file Claude writes or edits. Replace the example with your own hooks object.
my-plugin/hooks/hooks.json
4

Test the migrated plugin

Load the plugin for a session:
Check each component under its new name:
  • Skills: run /my-plugin:deploy for a skill that was /deploy.
  • Subagents: ask Claude to use the my-plugin:reviewer agent for an agent that was reviewer.
  • Hooks: trigger the event each hook matches.
If something is missing, work through Test and debug.
While the originals are still under .claude/, they stay loaded alongside the plugin’s copies:
  • Skills and agents: the two sets don’t collide, because the plugin’s skills and agents carry the my-plugin: prefix. /deploy and /my-plugin:deploy both work, and Claude sees reviewer and my-plugin:reviewer as two subagents.
  • Hooks: hooks have no prefix, so a hook that is in both your settings file and hooks/hooks.json runs twice each time its event fires.
After you’ve confirmed the plugin works, delete the originals from .claude/ and remove the hooks object from your settings file.

Next steps