Claude Code Plugins: Packaging Integrations for Distribution

How to package commands, agents, skills, hooks, and MCP servers into a single Claude Code plugin your team or customers install once. Real structure, marketplace.json, and what belongs inside.

By Tharindu Perera·Published 2026-05-12·13 min
13 min
Advanced
2026-05-12

A Claude Code setup that actually helps your team is rarely the default install. It is a CLAUDE.md, three custom commands, a subagent that knows your services, a hook that blocks accidental git push --force, and an MCP server pointed at your internal API. The hard part is not building those pieces. The hard part is getting them onto every engineer's laptop, in sync, without each person hand-editing dotfiles.

That is the problem Claude Code plugins solve. A plugin bundles all of those primitives into a single installable unit, distributed through a marketplace, versioned in a repo, governed by your enterprise policy. The plugin model became a first-class system in Claude Code v2.1.108 this spring, and as of the May 2026 update the official marketplace already lists thousands of skills and hundreds of plugins.

This guide covers how the packaging model works, what belongs inside a plugin versus what should stay in user config, how marketplaces actually distribute plugins, and the patterns vendors like Prismatic are using to ship customer-facing integrations as Claude Code plugins instead of standalone CLIs.

What changed: from per-user config to packaged distribution

Before plugins, every Claude Code primitive lived in someone's home directory or a project-local dotfile. Skills sat in ~/.claude/skills/. Hooks went in ~/.claude/settings.json or a project .claude/settings.json. MCP servers got registered through claude mcp add or a project .mcp.json. Subagents lived in ~/.claude/agents/ or .claude/agents/.

You could share these across a team with git submodules, dotfile repos, or onboarding scripts. None of that scaled cleanly. The pieces had no shared identity, no version, no manifest, no install command. A new engineer onboarding had to follow a README and hope nothing drifted.

Plugins fix this by giving the bundle a name, a version, and a single install path. From the user side it is one command:

/plugin install internal-tools@my-team-marketplace

That command resolves the marketplace, fetches the plugin, writes everything into ~/.claude/plugins/, and registers the plugin's commands, agents, skills, hooks, and MCP servers automatically. The user does not edit a settings file. They do not run mcp add. They do not symlink anything.

For more background on how the underlying primitives behave once they are installed, see our Claude Code power user guide. The plugin model does not replace those primitives. It packages them.

The plugin directory layout

Every plugin follows the same structure. Most directories are optional, but the layout itself is fixed:

my-plugin/
├── .claude-plugin/
│   ├── plugin.json           # Required: identity and manifest
│   └── marketplace.json      # Optional: only if this repo is also a marketplace
├── commands/                 # Slash commands (.md files)
├── agents/                   # Subagent definitions (.md files)
├── skills/                   # Each skill in its own subdirectory
│   └── skill-name/
│       └── SKILL.md
├── hooks/
│   └── hooks.json            # Event handler config
├── .mcp.json                 # MCP servers the plugin contributes
├── scripts/                  # Helper scripts referenced by hooks or commands
└── README.md

Two things trip people up here. First, the component directories sit at plugin root, not inside .claude-plugin/. The plugin manifest lives in .claude-plugin/plugin.json, but commands and agents and skills do not. Second, file and directory names must be kebab-case. Claude Code uses the directory name as the component identifier, and casing inconsistencies are the most common reason a plugin loads without errors but no command shows up.

A minimal plugin.json looks like this:

{
  "name": "internal-tools",
  "version": "0.4.1",
  "description": "Internal helpers for the platform team: deploy commands, infra-aware subagent, MCP server for our metrics API.",
  "author": {
    "name": "Platform Team",
    "email": "platform@example.com"
  },
  "homepage": "https://github.com/example/claude-internal-tools",
  "license": "MIT",
  "keywords": ["internal", "deploy", "metrics"]
}

That is the entire required surface. Optional fields cover dependencies, output styles, LSP servers, experimental flags, and explicit lists of components for the rare cases where you want to override auto-discovery.

Component naming is namespaced by the plugin name. An agent file at agents/release-bot.md inside a plugin named internal-tools appears in Claude Code as internal-tools:release-bot. The namespace prevents collisions when a user has ten plugins installed, three of which all define a deploy command.

An example plugin that bundles all the primitives

Here is a more realistic example. Imagine a plugin for a platform team that owns deploys, observability, and a metrics API. The plugin needs to contribute one slash command, one subagent, one skill, one hook that blocks risky operations, and one MCP server.

The command at commands/deploy.md:

---
description: Deploy the current service to staging or production
---

You are running the team's standard deploy flow.

1. Read .platform/service.yaml to identify the service name and target cluster.
2. Run `./scripts/preflight.sh` and abort on non-zero exit.
3. Run the deploy via `kubectl --context=$CONTEXT apply -k overlays/$ENV`.
4. Tail the rollout with `kubectl rollout status` until it succeeds or fails.

Never deploy to production without an explicit user confirmation in this session.

The subagent at agents/incident-investigator.md:

---
description: Cross-references logs, metrics, and recent deploys to triage an incident
---

You are an incident triage agent. When invoked, you:

1. Pull the last 50 deploys from the metrics MCP server.
2. Correlate timestamps with error rate spikes from the same server.
3. Surface the three most likely root-cause deploys with a confidence score.
4. Stop and hand back to the user. Do not propose fixes unsolicited.

The hook in hooks/hooks.json that blocks force-pushes to main:

{
  "PreToolUse": [
    {
      "matcher": "Bash",
      "hooks": [
        {
          "type": "command",
          "command": "${CLAUDE_PLUGIN_ROOT}/scripts/block-force-push.sh"
        }
      ]
    }
  ]
}

That script inspects the proposed command and exits non-zero if it sees push --force targeting main or master. The ${CLAUDE_PLUGIN_ROOT} variable resolves to the absolute install path of the plugin, which is the only safe way to reference bundled scripts since the user's working directory and ~/.claude/plugins/ location are not stable across machines.

The MCP server in .mcp.json:

{
  "mcpServers": {
    "metrics": {
      "command": "node",
      "args": ["${CLAUDE_PLUGIN_ROOT}/scripts/metrics-server.js"],
      "env": {
        "METRICS_API_URL": "${env:METRICS_API_URL}"
      }
    }
  }
}

The server can be a Node binary, a Python script, or anything else the user's machine can execute. Bundling it inside the plugin means the user does not install it separately. When the plugin loads, the MCP server starts. When it unloads, the server stops.

This same pattern, primitives bundled with a manifest, is what Prismatic just shipped publicly. Their open-source Prismatic Skills for Claude Code plugin packages skills like CNI Builder and Component Builder alongside a Prism MCP dev server that connects Claude directly to the customer's Prismatic environment. The skills carry the knowledge, the MCP server carries the access, and the plugin manifest stitches both into one install.

The marketplace.json layer

A plugin is the unit of install. A marketplace is the unit of discovery. Marketplaces are themselves git repositories (or zip URLs) containing a .claude-plugin/marketplace.json file that lists available plugins and where to find them.

A small internal marketplace looks like this:

{
  "name": "platform-team",
  "description": "Plugins maintained by the Platform team at Example Inc.",
  "plugins": [
    {
      "name": "internal-tools",
      "source": "github:example/claude-internal-tools",
      "version": "0.4.1"
    },
    {
      "name": "db-runbooks",
      "source": "github:example/claude-db-runbooks",
      "version": "1.0.0"
    }
  ]
}

Users register the marketplace once:

/plugin marketplace add github:example/claude-marketplace

After that, every plugin listed in the marketplace is one install command away. Updates flow through git pull semantics. When you tag a new version of internal-tools, users update with /plugin update internal-tools.

The official Anthropic-managed marketplace at anthropics/claude-plugins-official is auto-registered on every install. Third-party marketplaces are opt-in. Users add them explicitly, and starting with v2.1.108, Claude Code accepts arbitrary third-party plugin sources via the --plugin-url flag for direct installs and --plugin-dir for local zip archives.

If your team needs a private marketplace, the path of least resistance is a private GitHub repo, a single marketplace.json, and a list of plugins each in their own repo. There is no service to run. No registry to host. Git is the registry.

What belongs in a plugin versus user config

A plugin should be opinionated about the team or product it represents. It should not try to be opinionated about the individual user's editor preferences, terminal aliases, or personal CLAUDE.md.

Belongs in the plugin:

  • Commands the whole team should be able to run identically
  • Subagents that encode domain knowledge about your systems
  • Skills that wrap your internal APIs or workflows
  • Hooks that enforce team-wide safety rules
  • MCP servers for your internal tools or data sources
  • The scripts those primitives call

Belongs in the user's own config:

  • Personal CLAUDE.md preferences (tone, output style, language preferences)
  • Editor and shell integration
  • Personal aliases and shortcuts
  • API keys and credentials, always through environment variables, never bundled

A common mistake is shipping a global CLAUDE.md inside a plugin. Plugins can contribute output styles and component-level prompts, but the user's top-level CLAUDE.md is the user's domain. Overwriting it via a plugin breaks the contract and creates conflicts when a user installs multiple plugins.

The other common mistake is shipping credentials in the MCP server config. Always reference them with ${env:VAR_NAME} and document which env vars the plugin expects. The plugin manifest is checked into git. Anything sensitive in it ends up in your commit history.

Distribution patterns

A few patterns have shown up in the wild since the marketplace opened.

The first, and the one most teams should start with, is the internal team plugin. A platform or DX team builds one plugin that captures the team's standard workflows: deploy, incident triage, release notes generation, on-call helpers. It lives in a private GitHub marketplace. New engineers run two commands during onboarding and have the same Claude Code setup as everyone else. This is where the highest leverage sits, and it is usually a week or less of work for a team that already knows the primitives.

The second pattern is vendor-shipped customer plugins. Companies like Prismatic, Snyk, and a growing list of dev tooling vendors now ship official Claude Code plugins as part of their product. A customer installs the vendor's plugin and gets purpose-built skills, agents, and an MCP dev server tied to their own account. Prismatic's plugin packages skills like CNI Builder, Component Builder, Embed Advisor, the Orby monitor, and a Migration Analyzer, each paired with the MCP access layer it needs. The vendor maintains the plugin. The customer installs once. Integration setup that used to take a day now takes a single command.

The third is community plugins. The unofficial marketplaces (awesome-claude-code-plugins, the various cc-marketplace repos) host thousands of community-contributed plugins for things like Postgres explain-plan analysis or AWS cost interrogation. Quality is uneven. Anything that touches production systems deserves an audit before install, because a plugin can register hooks that run arbitrary shell commands on your machine.

For more on running Claude Code itself inside automated pipelines once your team plugin is installed, see our headless Claude Code in CI/CD guide.

Enterprise controls

The plugin model raises an obvious question: how do you keep a developer from installing a malicious marketplace? Claude Code added blockedMarketplaces and an allowlist mechanism for exactly this.

A managed settings file at the org level can specify:

{
  "allowedMarketplaces": [
    "anthropic/claude-plugins-official",
    "github:example/claude-marketplace"
  ],
  "blockedMarketplaces": [
    "github:sketchy-org/*"
  ]
}

If a marketplace was added on a laptop before the policy was deployed and its source no longer matches the allowlist, Claude Code refuses to install or update plugins from it. The same enforcement applies to blockedMarketplaces. Plugins already installed continue to load, but they cannot be updated until they come from an approved source.

For security-conscious teams, this is the missing layer that made plugins viable. Without it, a single curl-piped install script with a hook that runs arbitrary shell commands would be a serious threat. With it, plugins behave more like internal npm packages with a private registry.

The other guardrail worth turning on: hook approval prompts. A plugin's hooks can execute arbitrary commands on tool use. Claude Code can prompt the user the first time a plugin tries to run a new hook, the same way it prompts for new tool permissions. For shared developer machines, leave this on. For trusted internal plugins, the user can approve once and move on. See our subagents and parallel work patterns post for how this interacts with subagent dispatch, since subagents inherit hook policy from the parent session.

Versioning and updates

Plugins follow standard semver, and the manifest's version field is what shows up in /plugin list. The version is just a tag in your git history when the source is a GitHub repo. Bump it, tag the commit, push. Users pick up the new version with /plugin update.

A subtle gotcha: hot reload is partial. Skills, commands, and agents reload cleanly. Hooks and MCP server configurations require a session restart, because the harness wires those in at session start. If your plugin update changes hook behavior, tell users to restart Claude Code, not just run update.

Breaking changes deserve a major version bump and a CHANGELOG. Plugins that quietly rewire a hook to do something different break trust fast, especially if the hook touches git or production access. Treat each plugin like a small internal SDK, because once a team depends on it, it is one.

Where to start

The smallest possible useful plugin is two files: a plugin.json and one command. Get that working, install it locally with --plugin-dir, confirm the command appears in /plugin list, then expand.

A practical first plugin for most teams: one slash command that runs your project's standard preflight checks, one subagent that knows the names of your services and their owners, one hook that blocks git push --force to main, one MCP server pointed at whatever internal API the team queries most. Roughly a day of work, distributable to the entire team forever after.

The plugin model is still young. Signing and provenance for community plugins is the next obvious gap, and the manifest schema will keep growing. But the distribution mechanism is settled enough now that teams shipping Claude Code internally without plugins are reinventing onboarding the hard way.

About the author

T

Tharindu Perera

Tharindu Perera is a software engineer and solutions architect. He writes Refactix to share patterns from production work across AWS, distributed systems, and AI-driven development.

Follow RefactixLinkedIn·Facebook

Share this article

Topics Covered

Claude Code PluginsClaude Code Plugin MarketplacePlugin.Json ManifestMarketplace.JsonClaude Code MCP PluginClaude Code Plugin Distribution

You Might Also Like

Ready for More?

Explore our comprehensive collection of guides and tutorials to accelerate your tech journey.

Explore All Guides
Weekly Tech Insights

Stay Ahead of the Curve

Join thousands of tech professionals getting weekly insights on AI automation, software architecture, and modern development practices.

No spam, unsubscribe anytimeReal tech insights weekly