Claude Code Plugins: The Complete Guide to Building and Sharing Extensions

Skills, agents, and hooks you add to .claude/ are powerful — but they are locked to one project. Every time you start a new repo you copy the same files, maintain them in multiple places, and drift out of sync. Claude Code plugins solve this: a plugin is a shareable, versioned package that carries all your customisations and can be installed in any project with one command.

This post covers what plugins are, when to use them, and how to build a real one from scratch — a DevOps helper that ships a deployment skill, a pre-deploy safety hook, and an MCP server connection to your Kubernetes cluster.


Plugins vs Standalone Configuration

Claude Code supports two ways to extend it:

ApproachSkill namesBest for
Standalone (.claude/ directory)/deployOne project, personal workflows, quick experiments
Plugins (separate directory with manifest)/devops-helper:deploySharing with team, multiple projects, versioned releases, marketplace distribution

Start with standalone when you are iterating fast on a single project. Convert to a plugin when you want to share the same setup across projects or with teammates — or publish to the Anthropic marketplace.

The main trade-off is skill namespacing. Plugin skills are always prefixed with the plugin name (/devops-helper:deploy) to prevent conflicts when multiple plugins are installed. Standalone skills have no prefix (/deploy).


Plugin Structure

Every plugin is a directory with this layout:

devops-helper/
├── .claude-plugin/
│   └── plugin.json          ← manifest (only file that goes in .claude-plugin/)
├── skills/
│   └── deploy/
│       └── SKILL.md         ← skill definition
├── agents/
│   └── incident-responder.md
├── hooks/
│   └── hooks.json           ← event hooks
├── .mcp.json                ← MCP server config
├── monitors/
│   └── monitors.json        ← background monitors
├── bin/                     ← executables added to PATH
├── settings.json            ← default settings applied when plugin is enabled
└── README.md

The critical rule: only plugin.json goes inside .claude-plugin/. Everything else — skills, agents, hooks — sits at the plugin root. This is the most common structural mistake.

What each component does

ComponentWhat it is
skills/Skills Claude invokes automatically or you call with /plugin:skill-name
agents/Subagent definitions for specialised parallel tasks
hooks/Shell scripts that fire on lifecycle events (PreToolUse, PostToolUse, etc.)
.mcp.jsonMCP server config connecting Claude to external APIs and databases
monitors/Background watchers (log tails, file watchers) that notify Claude as events arrive
bin/Executables added to the Bash tool’s PATH during the session
settings.jsonDefault settings applied when the plugin is enabled

The Plugin Manifest

The manifest at .claude-plugin/plugin.json is the only required file:

{
  "name": "devops-helper",
  "description": "Deployment, Kubernetes, and incident-response tools for DevOps teams",
  "version": "1.0.0",
  "author": {
    "name": "Your Name",
    "email": "you@company.com"
  },
  "homepage": "https://github.com/your-org/devops-helper",
  "repository": "https://github.com/your-org/devops-helper",
  "license": "MIT"
}
FieldPurpose
namePlugin identifier and skill namespace prefix
descriptionShown in the plugin manager when browsing
versionBump to trigger updates for installers. Omit to use git SHA
authorAttribution — useful for marketplace listings
homepage / repositoryLinks shown in the plugin manager

Building a Real Plugin: DevOps Helper

Let’s build a plugin that DevOps teams can install across all their projects. It will include:

  1. A deploy skill — runs deployment with pre-flight checks
  2. A pre-deploy hook — blocks deploys to production without explicit confirmation
  3. A Kubernetes MCP server — gives Claude live cluster access
  4. A background log monitor — streams app errors to Claude automatically

Step 1: Create the structure

mkdir -p devops-helper/.claude-plugin
mkdir -p devops-helper/skills/deploy
mkdir -p devops-helper/skills/rollback
mkdir -p devops-helper/skills/incident-summary
mkdir -p devops-helper/hooks
mkdir -p devops-helper/agents
mkdir -p devops-helper/monitors

Step 2: Write the manifest

{
  "name": "devops-helper",
  "description": "Deployment safety, Kubernetes access, and incident response for DevOps teams",
  "version": "1.0.0",
  "author": {
    "name": "DevOps Team"
  }
}

Step 3: Create the deploy skill

<!-- devops-helper/skills/deploy/SKILL.md -->
---
description: >
  Runs a deployment with pre-flight checks and rollback instructions.
  Auto-invokes when the user asks to deploy, release, or push to production.
user-invocable: true
allowed-tools:
  - Bash
  - Read
---

# Deploy Skill

When the user asks to deploy, follow this sequence:

## 1. Read deployment config
Read `deploy.yaml` or `Makefile` to understand the deployment command. If neither exists, ask the user.

## 2. Pre-flight checks
Run these before any deploy:
```bash
# Check current branch
git branch --show-current

# Check for uncommitted changes
git status --porcelain

# Run tests
npm test --silent 2>&1 | tail -10

If tests fail or there are uncommitted changes, stop and report. Do not deploy.

3. Identify target environment

Parse $ARGUMENTS for the environment name (staging, production, etc.).

  • Default to staging if none specified
  • If production is specified, ask the user to confirm: “Deploying to production. Type YES to confirm.”

4. Deploy

Run the deployment command. Stream output. Capture exit code.

5. Verify

After deploy, verify the service is healthy:

# Check rollout status (Kubernetes)
kubectl rollout status deployment/$SERVICE_NAME -n $NAMESPACE --timeout=120s

# Or check the health endpoint
curl -sf $HEALTH_URL || echo "Health check failed"

6. Report

Summarise: what was deployed, to which environment, any warnings, and the health check result. If deploy failed: run the rollback skill immediately and report what happened.


### Step 4: Create the rollback skill

```markdown
<!-- devops-helper/skills/rollback/SKILL.md -->
---
description: Rolls back the last deployment. Use when a deploy fails or causes issues.
user-invocable: true
allowed-tools:
  - Bash
---

# Rollback Skill

## Steps

1. Identify the last stable deployment:
```bash
kubectl rollout history deployment/$SERVICE_NAME -n $NAMESPACE
  1. Roll back:
kubectl rollout undo deployment/$SERVICE_NAME -n $NAMESPACE
  1. Wait and verify:
kubectl rollout status deployment/$SERVICE_NAME -n $NAMESPACE --timeout=60s
  1. Report: whether rollback succeeded, which revision is now active, and recommend investigating what caused the failed deploy.

### Step 5: Create the incident summary skill

```markdown
<!-- devops-helper/skills/incident-summary/SKILL.md -->
---
description: >
  Generates an incident summary from logs and recent changes.
  Auto-invokes when the user mentions an incident, outage, or asks what went wrong.
user-invocable: true
allowed-tools:
  - Bash
  - Read
---

# Incident Summary Skill

Generate a structured incident summary. Collect:

1. **Timeline**: Run `git log --since="6 hours ago" --oneline` — what changed recently?
2. **Errors**: Read recent error logs from `logs/error.log` or run `kubectl logs --tail=100 -l app=$SERVICE`
3. **Impact**: Ask the user to describe impact if not obvious from logs

Write a summary in this format:

Incident Summary — [DATE]

Status: Ongoing / Resolved

Impact: [What broke, how many users affected]

Timeline:

  • HH:MM — [event]
  • HH:MM — [event]

Root cause: [One sentence]

Fix applied: [What was done]

Action items:

  • [Follow-up task]

Keep it factual, under 300 words, suitable for a post-mortem or Slack channel update.

Step 6: Add a pre-deploy safety hook

The hook blocks deploys to production unless the user explicitly confirms. It intercepts the Bash tool and checks if the command matches a deploy pattern targeting production:

// devops-helper/hooks/hooks.json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "devops-helper/hooks/pre-deploy-check.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "devops-helper/hooks/log-commands.sh"
          }
        ]
      }
    ]
  }
}
#!/bin/bash
# devops-helper/hooks/pre-deploy-check.sh
input=$(cat)
cmd=$(echo "$input" | jq -r '.tool_input.command // ""')

# Check for production deploy patterns
PROD_PATTERNS="prod|production|--env=prod"

if echo "$cmd" | grep -qiE "(deploy|release|kubectl apply|helm upgrade)" && \
   echo "$cmd" | grep -qiE "$PROD_PATTERNS"; then

  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "ask",
      permissionDecisionReason: "Production deployment detected. Confirm this is intentional before proceeding."
    }
  }'
  exit 0
fi

exit 0
#!/bin/bash
# devops-helper/hooks/log-commands.sh
# Append every Bash command to an audit log
input=$(cat)
cmd=$(echo "$input" | jq -r '.tool_input.command // ""')
ts=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

echo "[$ts] $cmd" >> "${AUDIT_LOG:-/tmp/claude-commands.log}"
exit 0

Step 7: Add a Kubernetes MCP server

The .mcp.json file at the plugin root connects Claude to your cluster:

{
  "mcpServers": {
    "kubernetes": {
      "command": "npx",
      "args": ["-y", "@anthropic/mcp-server-kubernetes"],
      "env": {
        "KUBECONFIG": "${KUBECONFIG:-~/.kube/config}"
      }
    },
    "pagerduty": {
      "command": "npx",
      "args": ["-y", "@anthropic/mcp-server-pagerduty"],
      "env": {
        "PAGERDUTY_API_KEY": "${PAGERDUTY_API_KEY}"
      }
    }
  }
}

With this in place, Claude can run kubectl commands, read pod logs, and check deployment status via MCP tools — without you manually setting up shell access.

Step 8: Add a background error log monitor

The monitor streams new error log lines to Claude during the session:

// devops-helper/monitors/monitors.json
[
  {
    "name": "app-errors",
    "command": "tail -F logs/error.log 2>/dev/null || echo 'No error.log found'",
    "description": "Application error log — new lines are delivered to Claude automatically"
  }
]

Claude receives each new log line as a notification, letting it flag new errors without you having to ask.

Final plugin structure

devops-helper/
├── .claude-plugin/
│   └── plugin.json
├── skills/
│   ├── deploy/
│   │   └── SKILL.md
│   ├── rollback/
│   │   └── SKILL.md
│   └── incident-summary/
│       └── SKILL.md
├── hooks/
│   ├── hooks.json
│   ├── pre-deploy-check.sh
│   └── log-commands.sh
├── monitors/
│   └── monitors.json
├── .mcp.json
└── README.md

Testing Your Plugin

Test locally without installing using --plugin-dir:

# Load from directory
claude --plugin-dir ./devops-helper

# Load from a zip archive (Claude Code v2.1.128+)
claude --plugin-dir ./devops-helper.zip

# Load multiple plugins at once
claude --plugin-dir ./devops-helper --plugin-dir ./other-plugin

Inside the session, verify everything loaded:

# List skills
/help

# Test the deploy skill
/devops-helper:deploy staging

# Test the rollback skill
/devops-helper:rollback

# Check agents are visible
/agents

After making changes, reload without restarting:

/reload-plugins

If something does not work, check the structure first — the most common issue is placing skills/ or hooks/ inside .claude-plugin/ instead of the plugin root.


Installing Plugins

Once the plugin is in a git repository, anyone can install it:

# From GitHub
claude plugin add github:your-org/devops-helper

# From the official Anthropic marketplace
claude plugin add @anthropic/deploy-helper

# Project-scoped install (only active in this repo)
claude plugin add github:your-org/devops-helper --project

Managing installed plugins:

claude plugin list                              # see what's installed
claude plugin update github:your-org/devops-helper
claude plugin update --all                      # update everything
claude plugin remove github:your-org/devops-helper

Or use the in-app plugin manager:

/plugin

The /plugin command opens a browser with Discover, Installed, and Updates tabs.


Converting Existing Config to a Plugin

If you have skills and hooks in .claude/ already, migration is straightforward:

# 1. Create plugin structure
mkdir -p my-plugin/.claude-plugin

# 2. Write manifest
cat > my-plugin/.claude-plugin/plugin.json << 'EOF'
{
  "name": "my-plugin",
  "description": "Migrated from standalone .claude/ config",
  "version": "1.0.0"
}
EOF

# 3. Copy existing components
cp -r .claude/skills  my-plugin/
cp -r .claude/agents  my-plugin/
cp -r .claude/commands my-plugin/

# 4. Migrate hooks
mkdir my-plugin/hooks
# Copy the hooks object from .claude/settings.json into my-plugin/hooks/hooks.json

What changes after migration:

Before (standalone)After (plugin)
/deploy/my-plugin:deploy
Copy files per projectclaude plugin add github:you/my-plugin
Manual updatesclaude plugin update --all
Only in one projectAvailable everywhere

Publishing to the Anthropic Marketplace

When your plugin is ready to share publicly:

  1. Push to a public GitHub repository
  2. Add a README.md with installation instructions and a usage guide
  3. Submit via the in-app form:
    • Claude.ai: Settings → Plugins → Submit
    • Platform console: platform.claude.com/plugins/submit

Once listed, users can install with /plugin install your-plugin-name or claude plugin add @your-org/your-plugin.

For team-internal distribution, host the plugin in a private GitHub repo and configure the team marketplace URL in project settings — no public listing required.


When to Build a Plugin

flowchart TD
    Q1{Do you need this\nacross multiple projects?} -->|Yes| Q2{Share with\nothers?}
    Q1 -->|No| Standalone[Standalone .claude/ config]
    Q2 -->|Yes| Plugin[Build a plugin]
    Q2 -->|No| Q3{More than one\nproject?}
    Q3 -->|Yes| Plugin
    Q3 -->|No| Standalone

Build a plugin when:

  • You want the same skills and hooks in every project without copying files
  • You are building tools for a team and want them to install with one command
  • You want version control over your tooling (bump version to push updates)
  • You want to publish to the Anthropic marketplace for the community

Stick with standalone when:

  • The configuration is specific to one project and will never be reused
  • You are experimenting and not sure if the skill is worth keeping
  • You want short skill names without namespace prefixes

The practical path: build standalone first, convert to a plugin once the skill proves its value.


Plugin Ideas to Build Next

PluginWhat it does
git-helperPR description writer, commit message generator, branch namer
test-enforcerAuto-run tests on edit, enforce coverage thresholds, generate missing tests
security-scannerIDOR checker, injection auditor, pre-commit security review
doc-writerGenerate README, API docs, changelogs from code
infra-opsTerraform plan reviewer, cost estimator, drift detector
incident-botPost-mortem template filler, on-call summary, PagerDuty integration

Each of these follows the same pattern: a few skill files, an optional hook, and an MCP server connection if external data is needed.

Abhay

Abhay Pratap Singh

DevOps Engineer passionate about automation, cloud infrastructure, and self-hosted tools. I write about Kubernetes, Terraform, DNS, and everything in between.