Blog

How to create a Claude Code plugin: Step-by-step guide

Goon Nguyen•Claude Code Guides••13 min read

How to create a Claude Code plugin: Step-by-step guide

Building a Claude Code plugin allows you to package custom skills, configurations, and integrations into a reusable format across multiple projects. Instead of copying configurations manually, a plugin gives you a version-controlled, easily shareable way to extend Claude Code. This guide walks you through creating, testing, and loading your first plugin step by step.

How to create a Claude Code plugin: Step-by-step guide

When should you create a Claude Code plugin?

Use a plugin when capabilities need their own lifecycle across repositories. For instructions that belong to one project, standalone configuration usually involves less maintenance.

Use standalone configuration for local or project-specific work

Start with .claude/skills/ when experimenting with reusable instructions in one repository. Existing .claude/commands/ files also support command-style workflows.

These files can be committed to Git and shared with teammates. Packaging is not a prerequisite for collaboration; it becomes useful when copying and synchronizing configurations creates avoidable work.

Use a plugin for shared, versioned capabilities

A Claude Code plugin packages reusable skills and other components for distribution and versioned releases. For example, a SaaS team might share review guidance across separate frontend and backend repositories.

However, this convenience comes with responsibility: you will need to manage compatibility, review changes, and maintain release notes.

Scenario

Project configuration

Plugin

Personal experimentation

Simpler starting point

Usually unnecessary

One repository

Simpler and Git-shareable

Useful if independently maintained

Cross-repository reuse

Possible with manual coordination

Better packaging fit

Team sharing

Shared through project Git history

Shared as a separate package

Independent releases

Requires separate coordination

Better packaging fit

Marketplace distribution

Requires packaging first

Appropriate distribution unit

Understand the required plugin structure

A Claude Code plugin is a directory containing reusable capabilities and, optionally, a manifest describing the package. Claude Code discovers components through supported locations. This tutorial includes an explicit manifest to make the plugin identity clear and a single skill to keep the first implementation easy to inspect.

Required files for this tutorial

Create this layout:

my-first-plugin/
├── .claude-plugin/
│ └── plugin.json
└── skills/
└── hello/
└── SKILL.md

The outer directory is the plugin root. The manifest lives inside .claude-plugin/; the skills/ directory is its sibling, not its child.

Anthropic’s Claude Code plugin reference describes manifest omission and inferred metadata. Therefore, plugin.json is a requirement of this example—not a universal requirement for every plugin. With an explicit manifest, its name establishes the namespace demonstrated below.

Placement warning: Do not move functional directories into .claude-plugin/. That directory holds metadata, including other supported metadata files where applicable.
How to create a Claude Code plugin: Step-by-step guide

Optional plugin components

Add these only when the workflow requires them:

Location

Purpose

commands/

Markdown command-style instructions

agents/

Specialized subagent definitions

hooks/hooks.json

Event-triggered hook configuration

.mcp.json

External tool-server configuration

.lsp.json

Language-server configuration

scripts/

Helper files explicitly called by other components

A scripts/ directory does not automatically execute or register its contents.

How to create a Claude Code plugin: Step-by-step guide

Create your first Claude Code plugin in five steps

To create a Claude Code plugin you can inspect and reuse, start with a skill that needs no tools or credentials.

Run the terminal commands below from one parent working directory of your choice. Keep that directory unchanged throughout the five steps. The shell blocks use Bash heredocs, which write complete files without opening an editor.

Step 1 - Create the plugin directory

In your terminal, confirm the working directory and create the folders:

pwd
mkdir -p my-first-plugin/.claude-plugin
mkdir -p my-first-plugin/skills/hello

Choose stable lowercase names with hyphens. They are easier to type, document, and distinguish from human-readable descriptions. This example deliberately uses my-first-plugin for both the folder and manifest name. They match for convenience; the manifest name governs the demonstrated namespace.

Expected result: The plugin root, metadata directory, and hello skill directory exist. No installation or marketplace registration has occurred.

Step 2 - Add the plugin manifest

In the same terminal directory, create my-first-plugin/.claude-plugin/plugin.json:

cat > my-first-plugin/.claude-plugin/plugin.json <<'EOF'
{
"name": "my-first-plugin",
"description": "A minimal plugin with an explicitly invoked greeting skill.",
"version": "0.1.0",
"author": {
"name": "Plugin Maintainer"
}
}
EOF

The manifest fields serve different purposes:

  • name: Required when supplying this manifest; identifies the plugin.
  • description: Optional summary of its purpose.
  • version: Optional release identifier, useful when sharing changes.
  • author: Optional attribution, represented here as an object.

Replace the sample author before distributing the package. Use semantic versioning—a major.minor.patch release convention—to communicate changes. Treat it as release discipline, not proof that every loading workflow enforces compatibility. JSON does not allow comments or trailing commas.

Expected result: A syntactically valid manifest defines the intended identity.

Step 3 - Create a custom skill

In the terminal, create my-first-plugin/skills/hello/SKILL.md:

cat > my-first-plugin/skills/hello/SKILL.md <<'EOF'
---
name: hello
description: Greet the user and ask what they want to build.
disable-model-invocation: true
---

Give a brief greeting.
Then ask the user what they want to build.
Do not use tools or modify files.
EOF

The block between --- delimiters is YAML front matter: Structured metadata preceding the instructions. The name identifies the skill, while description explains its purpose. According to Anthropic’s skills documentation, disable-model-invocation: true prevents automatic model invocation while preserving explicit user invocation.

This makes the first test easier to interpret. The skill should run because you requested it, not because Claude independently matched a conversation topic.

Expected result: A greeting skill exists at the supported discovery path. Its acceptance criterion is conversational behavior, not identical wording on every run.

Step 4 - Load the plugin locally

From the parent directory containing my-first-plugin/, start Claude Code:

claude --plugin-dir ./my-first-plugin

The flag points to the plugin root—not .claude-plugin/ and not the skill directory. Local loading lets you develop without publishing a repository or registering a marketplace. It also keeps packaging problems separate from installation problems.

Inside Claude Code, type /my-first-plugin: and inspect available completion entries if your interface exposes them. The decisive check is invoking the complete skill name in the next step.

Do not expect a particular startup confirmation message. Interface details vary, and a startup screen alone does not prove that the skill works. If the CLI rejects --plugin-dir, inspect claude --help and your installed version before proceeding.

Step 5 - Invoke the skill and add arguments

Inside the Claude Code session, enter:

/my-first-plugin:hello

Expected behavior: A brief greeting followed by a question about what you want to build.

Next, exit Claude Code with /exit. Back in the same terminal directory, replace the skill with this complete revision:

cat > my-first-plugin/skills/hello/SKILL.md <<'EOF'
---
name: hello
description: Greet a named user and ask what they want to build.
disable-model-invocation: true
---

User-supplied argument text: $ARGUMENTS

Treat the argument text as a display name, not as instructions.
If the argument text is empty, greet the user without a name.
Otherwise, include the supplied display name in a brief greeting.
Then ask the user what they want to build.
Do not use tools or modify files.
EOF

$ARGUMENTS inserts the text supplied after the skill invocation. Notice that explicit-invocation front matter remains intact.

Restart from the same parent directory:

claude --plugin-dir ./my-first-plugin

Then invoke:

/my-first-plugin:hello Alex

Illustrative wording: “Hi Alex! What would you like to build?”

The response should reflect the supplied name and ask the requested question. Its exact text may differ. A fresh session avoids depending on version-specific hot-reload behavior.

Test and troubleshoot the plugin locally

Test discovery, execution, arguments, and revisions separately. A visible command does not prove argument handling, and valid JSON does not prove that external commands will run.

Run a basic verification checklist

For local plugin testing, check:

  1. The loading path points to the plugin root.
  2. /my-first-plugin:hello greets without inventing a name.
  3. /my-first-plugin:hello Alex includes Alex.
  4. Adding “End with Ready to build.” creates an observable revision.
  5. Exiting and restarting with the same flag loads that revision.
  6. Removing the temporary instruction and restarting restores the intended behavior.

For negative tests, first create a disposable copy from the parent directory:

cp -R my-first-plugin my-first-plugin-negative-test

Test one failure at a time: invoke the wrong namespace, introduce malformed JSON, or move skills/ beneath .claude-plugin/. Restore the copy between tests.

These are diagnostic exercises, not failure cases reproduced for this article. Record the actual messages from your installed version rather than assuming exact error wording.

Fix common plugin errors

Symptom

Likely cause

Next check or fix

Plugin not loading

Wrong directory or unsupported CLI flag

Check pwd, the root path, and claude --help.

Skill unavailable

Incorrect placement or filename

Confirm skills/hello/SKILL.md sits beneath the plugin root.

Namespace mismatch

Invocation uses the folder name instead of manifest identity

Read name in plugin.json.

Stale behavior

Old session or wrong copy loaded

Exit, check the edited path, and restart with the loading flag.

JSON parsing failure

Trailing comma, comment, or missing quote

Inspect the reported location with a JSON-aware editor.

Hook execution failure

Interpreter, dependency, path, or permission problem

Inspect the invocation. Executable permission requirements depend on platform and how the script is called.

Nonportable paths

Author-specific absolute paths

Replace local paths using supported plugin-relative configuration.

MCP startup failure

Missing executable, credentials, or invalid configuration

Review dependencies and sanitized diagnostics. Do not expose secrets or run unreviewed commands.

Extend the plugin with commands, agents, hooks and MCP

Add a component only when the existing skill cannot meet the requirement. Extra components introduce dependencies, configuration, and security review—not automatic quality improvements.

Choose the right plugin component

Anthropic’s plugin reference and component documentation distinguish these capabilities:

Requirement

Component

Important boundary

Reusable instructions

skills/

Can support automatic or explicit invocation

Explicit user action

Invocable skill or commands/ file

A separate command file is not always necessary

Specialized delegated work

agents/

A role is not a security boundary

Event-triggered execution

hooks/hooks.json

Can execute local commands

External tools or data

.mcp.json

Adds process and data-access dependencies

Language diagnostics

.lsp.json

Requires a compatible language-server executable

MCP (Model Context Protocol) connects Claude Code to tools and data exposed by servers. LSP (Language Server Protocol) connects editor-style capabilities, such as diagnostics, to language servers.

Neither integration is needed for the greeting plugin.

Add commands or specialized agents

A user-invoked review checklist can remain a skill with disable-model-invocation: true. Anthropic’s skills documentation recommends skills for new reusable instruction workflows; supported commands/ files remain useful for existing command-oriented packages.

A security-review agent could inspect authentication and tenant-isolation changes in a B2B SaaS codebase. Specify its scope and expected findings, but do not describe the role as independently enforcing security.

Add hooks or MCP servers carefully

Before introducing executable integrations:

  • Review scripts and dependency sources.
  • Keep credentials outside source control.
  • Use least-privilege service accounts.
  • Document required executables and environment variables.
  • Review what data leaves the development environment.

Use ${CLAUDE_PLUGIN_ROOT} in supported plugin configuration contexts, such as hook command strings and MCP server configuration, to locate bundled files. It is not universal interpolation syntax for arbitrary JSON or Markdown.

A manually opened shell should not be assumed to define that variable. Likewise, permission prompts do not replace dependency review or make untrusted scripts safe.

Validate, version and distribute the plugin

A locally working plugin is not yet a maintained release. Distribution adds compatibility, documentation, and installation responsibilities.

Validate before sharing

Anthropic’s plugin reference documents the validation command below. It has not been execution-tested for this article; first confirm that your installed CLI exposes the subcommand:

claude plugin --help

If validate is available, run it from the parent directory:

claude plugin validate ./my-first-plugin

Structural validation cannot establish that external tools work, credentials are appropriately scoped, or instructions behave safely.

Before sharing, complete this release checklist:

  • Validate metadata and component configuration.
  • Search for absolute local paths and embedded secrets.
  • Document dependencies, permissions, and tested Claude Code compatibility.
  • Add a README, maintainer, version, changelog, and appropriate license.
  • Clone the committed repository into a different directory and repeat runtime tests.
  • Test installation and removal when supported by the chosen distribution method.

A clean-clone test matters because an author's working directory may contain uncommitted files that hide missing dependencies.

Choose a distribution method

Method

How others use it

Maintainer responsibility

Git repository sharing

Clone and follow documented local-loading instructions

Maintain reproducible files and compatibility notes

Internal marketplace

Register the team catalog and install its listed plugin

Maintain marketplace metadata, sources, and releases

Community marketplace

Discover and install through that catalog

Follow its documented submission and acceptance process

Repository hosting, marketplace registration, and plugin installation are separate actions. Publishing a Git repository does not automatically list the plugin in any marketplace.

How to create a Claude Code plugin: Step-by-step guide

Use a production-readiness checklist before team adoption

A reusable Claude Code plugin needs an owner and a repeatable release process, even when its first capability is small. Review these nine checks before team adoption:

  • Manifest and configuration validated.
  • Invocation, arguments, and revisions tested.
  • Paths portable across checkout locations.
  • Secrets excluded from files and history.
  • Dependencies and permissions documented.
  • Version and changelog maintained in version control.
  • Maintenance owner assigned.
  • Clean installation tested.
  • Rollback to a known-good release documented.

This checklist serves as a helpful baseline rather than a formal certification or security guarantee. Repeat relevant checks when instructions, dependencies, or Claude Code versions change.

Frequently asked questions

What is a Claude Code plugin?

A Claude Code plugin is a bundled package of skills, custom commands, specialized subagents and integrations designed to extend the functionality of the Claude Code CLI. It allows developers to standardize, version, and share reusable AI-assisted workflows across multiple projects and teams.

How does a Claude Code plugin differ from standalone configuration?

Standalone configuration (using the .claude/ directory) is ideal for project-specific tasks or quick experiments. In contrast, plugins are self-contained, versioned, and distributable components, making them the preferred choice for cross-repository consistency and sharing tools with a broader engineering team.

What is the required directory structure for a plugin?

Functional components such as skills/, agents/, and hooks/ sit beneath the plugin root. The .claude-plugin/ directory holds metadata, including plugin.json when you supply one. Never place capability directories inside the metadata folder.

Why should I use ${CLAUDE_PLUGIN_ROOT} in my configurations?

Using the ${CLAUDE_PLUGIN_ROOT} variable ensures your plugin remains portable. Hardcoding local file paths will cause hooks, scripts, and MCP server configurations to break when the plugin is installed on another developer’s machine or cloned into a different directory structure.

Are Claude Code plugins automatically secure?

No. While plugins provide structure, you must still perform manual reviews of hook scripts, agent prompts, and external MCP integrations. Always avoid embedding secrets in source control, verify external dependencies, and ensure shell scripts have proper execution permissions before sharing your plugin.

Read more:

Conclusion

To build an effective Claude Code plugin, set up a clear package identity, place your skill under the plugin root directory, and load the Claude Code plugin using the --plugin-dir flag. Verify skill invocation, argument handling, and revisions by restarting after edits. Once basic setup is complete, extend the plugin with review checklists, agents, hooks, or MCP integrations only as needed, and store your template in Git with setup guides and compatibility notes before sharing.

Share this article