How to create and share a Claude Code plugin

LLM Mart · Sep 25, 2026 · 0 views 8 listing impressions
How to create and share a Claude Code plugin

A Claude Code plugin is a directory containing skills, agents, hooks, MCP servers, or LSP configurations, optionally described by a .claude-plugin/plugin.json manifest. Test it locally with --plugin-dir, then distribute it through a marketplace so other people can install and update it as one versioned unit.

The trigger for creating one is specific: a second repository needs the same setup. Until then, standalone .claude/ configuration iterates faster and costs nothing to change.

Standalone or plugin

Standalone (.claude/) Plugin
Skill names /hello /plugin-name:hello
Availability One project Any project that installs it
Distribution Copy files manually /plugin install from a marketplace
Versioning None Explicit, with controlled updates
Best for Personal workflows, experiments Sharing with teammates or the community

Start standalone, convert when you are ready to share. The conversion is mechanical, and doing it early mostly buys you a namespace prefix you did not need yet.

If you are still deciding what the thing should be at all — Claude skills vs. connectors vs. plugins separates the packaging question from the capability question.

Build the plugin

mkdir -p my-first-plugin/.claude-plugin

The manifest at .claude-plugin/plugin.json defines the plugin's identity:

{
  "name": "my-first-plugin",
  "description": "A greeting plugin to learn the basics",
  "version": "1.0.0",
  "author": { "name": "Your Name" }
}
Field Purpose
name Unique identifier and skill namespace. Skills are prefixed with it: /my-first-plugin:hello.
description Shown in the plugin manager when browsing or installing.
version Optional. When set, users only receive updates after you bump it.
author Optional, useful for attribution.

Then add a skill. Skills live in skills/, one directory each, containing a SKILL.md:

mkdir -p my-first-plugin/skills/hello
---
description: Greet the user with a personalized message
---

Greet the user named "$ARGUMENTS" warmly and ask how you can help them today.

Get the directory layout right

This is the single most common plugin bug, and it produces a plugin that loads with nothing in it.

Only plugin.json goes inside .claude-plugin/. Everything else sits at the plugin root.

Directory Purpose
.claude-plugin/ Contains plugin.json — optional when components use default locations
skills/ Skills as <name>/SKILL.md directories
commands/ Skills as flat markdown files — use skills/ for new plugins
agents/ Custom subagent definitions
hooks/ Event handlers in hooks.json
.mcp.json MCP server configurations
.lsp.json LSP server configurations for code intelligence
monitors/ Background monitor configurations
bin/ Executables added to the Bash tool's PATH while the plugin is enabled
settings.json Default settings applied when the plugin is enabled

The plugin root is the individual plugin's own directory — never ~/.claude/. A plugin that ships exactly one skill can place SKILL.md directly at the plugin root, but use the skills/ layout for anything that might grow.

Test it locally

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

Then invoke the skill by its namespaced name:

/my-first-plugin:hello Alex

As you make changes, /reload-plugins picks them up without restarting — it reloads plugins, skills, agents, hooks, plugin MCP servers, and plugin LSP servers.

A few things --plugin-dir supports that are easy to miss:

  • It accepts a .zip archive of the plugin directory.
  • Repeat the flag to load several plugins at once.
  • Point it at a folder of plugins and each immediate subfolder with a manifest loads separately. Claude Code skips everything else in that folder without reporting an error, including plugins that have no manifest — which is the usual explanation for "my plugin silently didn't load."
  • When a --plugin-dir plugin shares a name with an installed marketplace plugin, the local copy wins for that session, so you can test changes without uninstalling.

Test each component deliberately: run every skill, check agents appear in /context under Custom Agents, and trigger the event each hook matches to confirm its effect. Claude Code records which hooks matched, their exit codes, and their output in the debug log.

For faster iteration without the flag, claude plugin init my-tool scaffolds a plugin in ~/.claude/skills/my-tool/ that loads automatically on the next session as my-tool@skills-dir, with no marketplace or install step.

Convert existing configuration

If you already have .claude/ configuration, migration is a copy plus one format change:

mkdir -p my-plugin/.claude-plugin
# write plugin.json, then:
cp -r .claude/commands my-plugin/
cp -r .claude/agents   my-plugin/
cp -r .claude/skills   my-plugin/

Hooks are the exception. They move from settings.json into my-plugin/hooks/hooks.json, where the inner format is the same — copy the hooks object across:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npm run lint:fix" }]
      }
    ]
  }
}

Then remove the originals from .claude/. Project and user .claude/agents/ definitions override same-named plugin agents, so the plugin version does not take effect until the originals are gone. Skills behave differently: the original /name and the namespaced /plugin-name:name both remain available, so a stale copy quietly shadows nothing and confuses everyone.

Ship a marketplace

Distribution goes through a marketplace: a .claude-plugin/marketplace.json at a repository root.

{
  "name": "company-tools",
  "owner": { "name": "DevTools Team", "email": "devtools@example.com" },
  "plugins": [
    {
      "name": "code-formatter",
      "source": "./plugins/formatter",
      "description": "Automatic code formatting on save",
      "version": "2.1.0"
    },
    {
      "name": "deployment-tools",
      "source": { "source": "github", "repo": "company/deploy-plugin", "ref": "v2.0.0" },
      "description": "Deployment automation tools"
    }
  ]
}

Each entry needs a name and a source. Sources can be relative paths, GitHub repositories, git repositories, git subdirectories, npm packages, or zip archives.

Three things to get right:

Marketplace names are public and singular. Users type them: /plugin install my-tool@company-tools. Each user can register only one marketplace per name — adding a second with the same name replaces the first. To publish several plugins under one name, list them all in a single marketplace.json.

A set of names is reserved for official Anthropic use, including claude-plugins-official, claude-community, and agent-skills, along with names that impersonate them. Reserved names are re-checked on every load, not only when a marketplace is added.

Relative paths resolve against the marketplace root, the directory containing .claude-plugin/. They do not resolve at all if users add your marketplace via a direct URL to the marketplace.json file, because only that file gets downloaded. For URL-based distribution, use any other source type.

Pin what you depend on. A GitHub source takes an optional ref for a branch or tag and a sha for an exact commit. For anything a team relies on, pin it.

Validate before you share

claude plugin validate ./my-plugin

Validation prints ✔ Validation passed, or passes with warnings. Add --strict to treat warnings as errors. Run it from your marketplace directory too — claude plugin validate . — and install a test plugin from the local path before pointing anyone else at it.

Validation checks structure. It does not tell you whether the plugin changes what Claude actually does. For that, claude plugin eval runs the plugin against a set of test prompts, several times each with and without the plugin loaded, so you can see what it contributes and catch regressions when you change it or a new model ships. That is the check worth adding to CI, because a plugin that stops triggering is indistinguishable from a plugin that works until someone measures it.

Distribution options

A public GitHub repository is the default: users add it with /plugin marketplace add owner/repo.

A private repository keeps a marketplace internal to your team, using your existing git authentication.

Organisation settings distribute through claude.ai for Team and Enterprise organisations. One constraint applies there: a plugin distributed this way cannot include a top-level bin/ directory.

The community marketplace is claude-community, where third-party submissions land after review. Submit through the in-app form on claude.ai (Team or Enterprise organisations with directory management access) or the Console form (for individual authors). Run claude plugin validate locally first — the review pipeline runs the same check, plus automated safety screening.

Approved plugins are pinned to a specific commit SHA in the community catalog, with CI bumping the pin as you push. The public catalog syncs nightly, so there is a delay between approval and installability.

The curated claude-plugins-official marketplace is separate. Anthropic decides what goes in it at its discretion; there is no application process, and the submission form does not add plugins to it.

Version and update deliberately

When version is set in plugin.json, users receive updates only when you bump it. That makes the field a release gate rather than metadata: changing a hook that runs on every file edit without bumping the version means nobody gets the fix.

Before each release:

  • Bump version in plugin.json, and in the marketplace entry if it declares one.
  • Update the README.md — installation, usage, and what each component does.
  • Re-run claude plugin validate, and the eval suite if you have one.
  • Have someone else install it from the marketplace, not from --plugin-dir.

To rename or remove a plugin without stranding existing users, the marketplace renames field maps a former name to its current name, or to null if the plugin is gone.

What you are asking people to trust

A plugin can carry hooks that run shell commands on lifecycle events, MCP servers that reach external services, executables added to the Bash tool's PATH, and agents with their own permission modes. Installing one is a trust decision of the same kind as adding a dependency — which is why the vetting checklist applies to plugins at least as much as to individual skills.

Publishing one puts you on the other side of that decision. Two things make it easier for people to say yes: a README that states plainly what each hook fires on and what each MCP server can reach, and a repository where the diff between versions is readable. Neither is hard. Both are frequently absent.

Next step: Package a proven Claude workflow as a plugin, then list its reusable skills on LLM Mart so the people who would benefit from it can find it.

Sources

0 0 0 0 Sign in to react

Comments (0)

Sign in to join the conversation.

No comments yet.