Claude Code Plugins Guide

Claude Code Plugins allow developers to bundle skills, subagents, hooks, MCP servers, and LSP configurations into installable packages. Plugins provide a structured way to extend Claude Code’s functionality while maintaining clear manifests and proper namespacing.

The plugin architecture requires a .claude-plugin/plugin.json manifest file, with optional directories for skills, agents, commands, hooks, and configurations. Plugins can be tested locally, distributed through marketplaces, and include features like user configuration, persistent data storage, and security controls for sensitive information.

Claude Code Plugins — Creating Claude Code plugins extends the assistant with custom functionality. Build plugins with hooks, commands, MCP servers, and subagents.

Claude Code Plugins Guide — title card

Claude Code Plugins: What You’ll Learn

To understand how plugins fit alongside skills, hooks, and subagents in the broader ecosystem, read our extensibility decision guide.

In this guide to Claude Code Plugins, you’ll work through practical, hands-on steps with real examples. Claude Code Plugins is explained from the ground up so you can apply it immediately in your own projects.

Plugins are the highest-level extension mechanism in Claude Code. They bundle skills, subagents, hooks, MCP servers, and LSP configurations into a single installable package. A team installs one plugin and immediately gets everything configured — no manual setup for each component. This lesson covers the plugin structure, manifest format, distribution mechanisms, and how to build your own.

Plugin Architecture

A plugin is a directory with a specific structure. The only required file is .claude-plugin/plugin.json, the manifest that declares the plugin’s identity. Everything else is optional but follows conventions Claude Code recognizes:

my-plugin/
├── .claude-plugin/
│   └── plugin.json       # Required manifest
├── skills/               # SKILL.md files
│   └── my-skill/
│       └── SKILL.md
├── agents/               # Subagent definitions
│   └── specialist.md
├── commands/             # Legacy command files (also work)
│   └── my-command.md
├── hooks/
│   └── hooks.json        # Plugin-scoped hooks
├── .mcp.json             # MCP server configs
├── .lsp.json             # LSP server configs
├── settings.json         # Default settings
└── bin/
    └── helper.sh

The manifest identifies the plugin and its metadata:

{
  "name": "pr-review",
  "description": "Complete PR review workflow with security and test coverage checks",
  "version": "1.0.0",
  "author": {
    "name": "Your Name"
  },
  "repository": "https://github.com/you/pr-review",
  "license": "MIT"
}

Plugin commands and plugin-provided skills are namespaced as plugin-name:command-name to avoid conflicts with project-level configuration. Invoke them with the full namespaced form, such as /pr-review:check-security.

Manifest Features

The manifest supports several powerful fields for configuring plugin behavior. userConfig declares user-configurable options. Fields marked sensitive: true are stored in the system keychain rather than plain-text settings:

{
  "name": "my-plugin",
  "version": "1.0.0",
  "userConfig": {
    "apiKey": {
      "description": "API key for the integration",
      "sensitive": true
    },
    "region": {
      "description": "Deployment region",
      "default": "us-east-1"
    }
  }
}

Plugins get a persistent data directory via ${CLAUDE_PLUGIN_DATA} (v2.1.78+). This survives across sessions, making it suitable for caches, state files, and databases. Use ${CLAUDE_PLUGIN_ROOT} to reference paths relative to the plugin installation directory — essential for hooks and MCP configurations:

{
  "hooks": {
    "PostToolUse": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node ${CLAUDE_PLUGIN_ROOT}/bin/audit.js"
          }
        ]
      }
    ]
  }
}

Plugin monitors require Claude Code v2.1.105 or later. Declare them under the experimental key in your manifest (experimental.monitors) — the top-level form still works but claude plugin validate will warn, and a future release will require the nested form. The monitors manifest key wires the plugin into the Monitor tool. Point it at a JSON file (or inline the config) and its background watches auto-arm the moment the plugin is enabled at session start, or when one of the plugin’s skills is invoked. This is how a plugin ships “watch CI, flag failures” or “tail the dev server log” behaviour without the user having to set it up:

{
  "name": "ci-watcher",
  "version": "1.0.0",
  "experimental": {
    "monitors": "./monitors.json"
  }
}

When the manifest sets a custom monitors path, the default monitors/monitors.json location is no longer scanned — specify the default explicitly if you still want it loaded alongside your custom file.

LSP support adds real-time language server protocol integration. Put a .lsp.json in the plugin root to configure language servers that provide instant diagnostics, go-to-definition, and symbol search as Claude edits files:

{
  "typescript": {
    "command": "typescript-language-server",
    "args": ["--stdio"],
    "extensionToLanguage": {
      ".ts": "typescript",
      ".tsx": "typescriptreact"
    }
  }
}

Distribution and Development

Test a plugin locally with the --plugin-dir flag before distributing. It loads the plugin for that session only — no installation:

claude --plugin-dir ./my-plugin
# Test multiple plugins simultaneously:
claude --plugin-dir ./my-plugin --plugin-dir ./another-plugin

For plugins hosted as .zip archives, --plugin-url fetches and installs them for the current session without permanent installation. Repeat the flag for multiple plugins:

claude --plugin-url https://example.com/my-plugin.zip
claude --plugin-url https://example.com/a.zip --plugin-url https://example.com/b.zip

Only use --plugin-url with URLs you trust — loading remote archives executes third-party code on your machine.

Use /reload-plugins to hot-reload plugin files during development without restarting the session. This re-reads all manifests, skills, agents, hooks, and MCP configurations instantly.

The /plugin Discover and Browse screens now show a full inventory of what a plugin will install before you commit to it — commands, agents, skills, hooks, and any MCP or LSP servers it ships. This makes vetting a marketplace plugin a one-screen decision: you can confirm a pr-review plugin isn’t quietly registering MCP servers or hooks you didn’t expect, or check that a deploy plugin actually ships the skill you came for. Browse lists what’s already installed with the same breakdown; Discover does the same for the marketplace catalog. The preview is informational only — the plugin still has to be installed before any of its components run.

Plugin distribution follows a marketplace model. The official Anthropic marketplace is claude-code-plugins-official. Add additional marketplaces with /plugin marketplace add owner/repo-name. Install plugins with /plugin install plugin-name or claude plugin install plugin-name@marketplace:

# Install from official marketplace
/plugin install pr-review

# Install from GitHub
/plugin install github:username/my-plugin

# Install from local path (for testing)
/plugin install ./path/to/plugin

When a plugin source is a GitHub owner/repo shorthand, Claude Code defaults to cloning over SSH. That breaks in CI runners, containers, or any environment without a configured SSH key for github.com. Set CLAUDE_CODE_PLUGIN_PREFER_HTTPS=1 to force HTTPS cloning instead — the rest of the install flow stays identical:

# Force HTTPS for plugin clones in CI
CLAUDE_CODE_PLUGIN_PREFER_HTTPS=1 claude plugin install owner/repo

For enterprise environments, managed-mcp.json controls which MCP servers plugins can use. The enabledPlugins, extraKnownMarketplaces, strictKnownMarketplaces, and blockedMarketplaces settings in managed policy control which plugins and marketplaces are allowed organization-wide. Plugin subagents have restricted frontmatter — they cannot define hooks, mcpServers, or permissionMode to prevent privilege escalation.

Useful lifecycle commands include claude plugin list, claude plugin enable, claude plugin disable, claude plugin uninstall, claude plugin validate, claude plugin prune (new in v2.1.121, aliased autoremove) which removes auto-installed plugin dependencies that no other installed plugin still requires — plugins you installed directly are never touched; to uninstall a plugin and clean up its dependencies in one step, run claude plugin uninstall <plugin> --prune. claude plugin details <name> shows a plugin’s component inventory grouped as Skills, Agents, Hooks, MCP servers, and LSP servers, along with an estimate of how many tokens it adds to each session.

And claude plugin tag (new in v2.1.118) creates a release git tag with version validation. Marketplaces can source plugins from GitHub, git URLs, local paths, npm, or other supported package sources.

claude plugin enable and claude plugin disable toggle an installed plugin on or off without removing it. Both accept a <plugin> name (or <plugin>@<marketplace> to disambiguate) and a --scope of user, project, or local (default: user). Disabling at project scope writes the choice into .claude/settings.json so the whole team picks it up; user scope keeps it personal:

# Personal: turn off a noisy plugin just for you
claude plugin disable formatter@anthropics/claude-code-plugins

# Team: keep the plugin in settings but turn it off project-wide
claude plugin disable formatter --scope project

# Re-enable later without touching its install or version
claude plugin enable formatter --scope project

The inline plugin pattern (source: 'settings' in v2.1.80+) lets you embed a plugin definition directly in a settings file without a separate repository. This is useful for small team-internal tools that don’t warrant a full git repository:

{
  "pluginMarketplaces": [
    {
      "name": "internal-tools",
      "source": "settings",
      "plugins": [
        {
          "name": "code-standards",
          "source": "./local-plugins/code-standards"
        }
      ]
    }
  ]
}

Real-World Plugin Examples

Here are production-ready plugin examples you can use as templates:

Example 1: Plugin Manifest

The .claude-plugin/plugin.json file is the core manifest every plugin requires:

{
  "name": "devops-automation",
  "version": "1.0.0",
  "description": "Complete DevOps automation for deployment, monitoring, and incident response",
  "author": { "name": "Community" },
  "license": "MIT"
}

Example 2: Plugin Hook (Pre-Deployment Validation)

Hooks live in hooks/hooks.json within the plugin directory. Here’s a Node.js pre-deployment hook:

In headless mode, plugins load automatically and their tools become available for CI/CD automation.
#!/usr/bin/env node
// Pre-deployment hook - validates environment before deployment
async function preDeploy() {
  console.log('Running pre-deployment checks...');
  const { execSync } = require('child_process');

  try {
    execSync('which kubectl', { stdio: 'pipe' });
  } catch (error) {
    console.error('kubectl not found. Please install Kubernetes CLI.');
    process.exit(1);
  }

  try {
    execSync('kubectl cluster-info', { stdio: 'pipe' });
  } catch (error) {
    console.error('Not connected to Kubernetes cluster');
    process.exit(1);
  }

  console.log('Pre-deployment checks passed');
}

preDeploy().catch(error => {
  console.error('Pre-deploy hook failed:', error);
  process.exit(1);
});

Example 3: Plugin Command and Directory Structure

Commands live in commands/ and are invoked with namespace syntax (/devops-automation:deploy):

---
name: Deploy
description: Deploy application to production or staging
---

# Deploy Application

Execute deployment workflow:
1. Run pre-deployment checks
2. Build application
3. Run tests
4. Deploy to target environment
5. Run health checks
6. Notify team on Slack

Complete plugin directory structure:

devops-automation/
  .claude-plugin/
    plugin.json          # Required manifest
  commands/
    deploy.md            # /devops-automation:deploy
    rollback.md          # /devops-automation:rollback
    status.md            # /devops-automation:status
    incident.md          # /devops-automation:incident
  hooks/
    hooks.json           # Hook configurations
  agents/
    deployment-specialist.md
    incident-commander.md
    alert-analyzer.md
  scripts/
    deploy.sh
    rollback.sh
    health-check.sh
  mcp/
    kubernetes-config.json

Pro Tips

  • Use plugins for bundling, not for single features. If you only need one slash command or one subagent, set it up standalone. Reach for a plugin when you want to bundle multiple components, share with a team, or distribute publicly.
  • Test locally before publishing. Use claude --plugin-dir ./my-plugin to load a plugin from a local path and verify every component works—commands, subagents, hooks, and MCP servers—before submitting to a marketplace.
  • Hot-reload during development. After editing plugin files, run /reload-plugins instead of restarting Claude Code. It re-reads all manifests and configurations instantly.
  • Respect plugin subagent security restrictions. Plugin subagents cannot define hooks, mcpServers, or permissionMode. This prevents privilege escalation—design your agents within these constraints.
  • Version your plugins with semver and tag releases. Use claude plugin tag v1.0.0 to create validated release tags. This ensures reproducible installs and lets users pin specific versions for stability.

Hands-On Challenge

Build, test, and locally install a minimal plugin that bundles a slash command and a subagent.

Task

Create a “lint-fixer” plugin with one slash command (/lint-fix) and one read-only subagent (lint-reviewer), then load it with --plugin-dir and verify both components are available.

Steps

  1. Create the directory structure: lint-fixer/.claude-plugin/plugin.json, lint-fixer/commands/lint-fix.md, and lint-fixer/agents/lint-reviewer.md.
  2. Write plugin.json with name, version, description, and author fields.
  3. Write lint-fix.md as a slash command that runs the project's linter and auto-fixes issues (use YAML frontmatter with name and description).
  4. Write lint-reviewer.md as a subagent with tools: Read, Grep and a prompt focused on code style and lint rule violations.
  5. Launch Claude Code with claude --plugin-dir ./lint-fixer.
  6. Verify by typing /lint-fix and asking “use the lint-reviewer subagent to check this file.”

Expected Outcome

A valid plugin directory that loads without errors, a working /lint-fix slash command, and a lint-reviewer subagent visible in /agents—all testable locally before publishing.

Hint

Plugin subagents run in a restricted sandbox—the hooks, mcpServers, and permissionMode frontmatter keys are not allowed for security reasons. Test locally with --plugin-dir before publishing. After editing files, use /reload-plugins to hot-reload without restarting the session.


Knowledge Check

Test your understanding of Claude Code plugins:

Q1: What is the core manifest file for a plugin and where does it live?

A) plugin.yaml in the root directory
B) .claude-plugin/plugin.json
C) package.json with a “claude” key
D) .claude/plugin.md

Correct answer: B — The plugin manifest lives at .claude-plugin/plugin.json with required fields: name, description, version, author.

Q2: How do you test a plugin locally before publishing?

A) Use /plugin test ./my-plugin
B) Use claude --plugin-dir ./my-plugin
C) Use claude plugin validate ./my-plugin
D) Copy it to ~/.claude/plugins/

Correct answer: B — The --plugin-dir flag loads a plugin from a local directory for testing.

Q3: What environment variable references the plugin’s installation directory?

A) $PLUGIN_HOME
B) ${CLAUDE_PLUGIN_ROOT}
C) $PLUGIN_DIR
D) ${CLAUDE_PLUGIN_PATH}

Correct answer: B${CLAUDE_PLUGIN_ROOT} resolves to the plugin’s installed directory for portable path references.

Q4: A plugin has a command called “check-security” in the “pr-review” plugin. How does a user invoke it?

A) /check-security
B) /pr-review:check-security
C) /plugin pr-review check-security
D) /pr-review/check-security

Correct answer: B — Plugin commands use a plugin-name:command-name namespace.

Q5: Which components can a plugin bundle?

A) Only commands and settings
B) Commands, agents, skills, hooks, MCP servers, LSP config, settings, templates, scripts
C) Only commands, hooks, and MCP servers
D) Only skills and agents

Correct answer: B — Plugins can bundle commands/, agents/, skills/, hooks/, .mcp.json, .lsp.json, settings.json, templates/, scripts/.

Test Your Knowledge

/5

Lesson 12 Quiz: Plugins

Test your knowledge of Claude Code plugins - structure, installation, and lifecycle management.

1 / 5

A plugin has a command called 'check-security' in the 'pr-review' plugin. How does a user invoke it?

2 / 5

What is the main advantage of a plugin over standalone skills/hooks/MCP?

3 / 5

What environment variable is available inside plugin hooks and MCP configs to reference the plugin's installation directory?

4 / 5

Which components can a plugin bundle?

5 / 5

What is the core manifest file for a plugin and where does it live?

Your score is

0%

Additional Resources

ResourceTypeWhat You'll Learn
Official Plugins DocumentationDocsPlugin structure, manifest format, and the full lifecycle from install to update
Discover PluginsGuideBrowsing and installing from the official marketplace
Plugin MarketplacesGuideCreating private marketplaces, source types (GitHub, npm, pip), and enterprise restrictions
Plugins ReferenceReferenceComplete field reference for plugin.json, hooks, and bundled components
Claude Code ChangelogChangelogAuto-load without marketplace (v2.1.157), plugin init, dependency enforcement (v2.1.143)

What should a plugin bundle?

Related hooks, commands, servers, and subagents behind one clear manifest, so users see exactly what it adds.

How do I keep a plugin trustworthy?

Scope its permissions to the minimum the feature needs and document everything it touches.

How do I handle plugin updates?

Version like any dependency, write down breaking changes, and test each release in a throwaway project first.

Putting It All Together

A well-built plugin is a small act of generosity to everyone who installs it. By bundling related features behind a clear manifest, scoping permissions tightly, and versioning changes honestly, you give users something they can adopt with confidence instead of something they have to reverse-engineer before they dare enable it.

Claude Code Plugins: Frequently Asked Questions

What does one actually add to Claude Code?

Plugins bundle related hooks, commands, MCP servers, and subagents behind a single manifest, so anyone installing one can see exactly what it adds and what it is allowed to do before enabling it.

How should permissions be scoped?

Scope permissions to the minimum a feature actually needs — something that only formats code has no business reaching the network. Tight boundaries make it easier to trust and less likely to cause surprises.

Why does versioning matter?

Treating it like any dependency, with tagged releases and documented breaking changes, lets you test each new release safely. Quietly changing behavior between updates erodes trust faster than shipping fewer features.

What is the most common documentation mistake?

Skipping the required namespace. Commands only work as name:command-name, but docs often show the bare /command form, so new users get “command not found” and assume it is broken.

How can I test one safely before publishing it?

Load it locally with the –plugin-dir flag before sharing it. A two-minute local test catches broken hook paths, missing frontmatter fields, or commands that silently fail to register.

Claude Code Plugins gives you a solid, repeatable workflow. Bookmark this Claude Code Plugins guide and revisit the steps whenever you need them.

Claude Code Plugins key concepts

Anatomy of a Well-Built Plugin

A good plugin reads like a small, well-organised product. It bundles related hooks, commands, servers, and subagents behind a single clear manifest, so anyone installing it can see exactly what it adds and what it is allowed to do before they enable it.

Scope permissions to the minimum the feature needs. A plugin that only formats code has no business reaching the network, and keeping that boundary tight makes the plugin easier to trust, easier to review, and far less likely to cause surprises in someone else’s workflow.

Version it like any dependency. Tag releases, write down breaking changes, and test each version in a throwaway project before rolling it out widely. A plugin that quietly changes behaviour between updates erodes trust faster than one that ships fewer features but never surprises its users.

Claude Code Plugins: Common Mistakes to Avoid

Most plugin problems trace back to a handful of habits that are easy to fall into while a plugin still works fine on your own machine. Watch for these before you publish or hand a plugin to a team.

  • Skipping the namespace when documenting commands. A plugin’s commands only work as plugin-name:command-name, but READMEs and internal docs often show the bare /command form copied from a standalone slash command example. New users type it, get “command not found,” and assume the plugin is broken.
  • Hardcoding absolute paths instead of ${CLAUDE_PLUGIN_ROOT}. A hook or MCP config that references ./bin/audit.js or a fixed local path works on the author’s machine and breaks the moment someone else installs the plugin, because the install directory is different for every user.
  • Storing secrets in plain settings instead of marking them sensitive: true. Skipping this in userConfig means an API key ends up in a plain-text settings file that could be committed to a shared repo, instead of the system keychain where sensitive fields belong.
  • Never testing with --plugin-dir before publishing. A plugin that “should work” based on the manifest alone often has a broken hook path, a missing frontmatter field, or a command that silently fails to register — problems that a two-minute local load with claude --plugin-dir ./my-plugin catches immediately.

Claude Code Plugins: Best Practices

  • Bundle related hooks, commands, MCP servers, and subagents into a single plugin.
  • Keep a clear manifest so users know exactly what the plugin adds.
  • Version plugins and document breaking changes.
  • Scope plugin permissions to the minimum the feature needs.
  • Test plugins in a throwaway project before rolling them out widely.
Claude Code Plugins best practices