CtrlK
BlogDocsLog inGet started
Tessl Logo

claude-code-plugin-development

This skill should be used when the user asks to "create a plugin", "build a plugin", "write a plugin", or wants to bundle agents, hooks, commands, skills, or MCP servers into a distributable Claude Code plugin.

Overall
score

18%

Does it follow best practices?

Validation for skill structure

Validation failed for this skill
This skill has errors that need to be fixed before it can move to Implementation and Activation review.
SKILL.md
Review
Evals

Claude Code Plugin Development

Create distributable plugins that bundle commands, agents, skills, hooks, MCP servers, and LSP servers.

Official docs: https://code.claude.com/docs/en/plugins-reference

Quick Reference

You MUST read these references for detailed schemas and examples:

Plugin Structure

my-plugin/
├── .claude-plugin/
│   └── plugin.json          # Required manifest
├── commands/                 # Slash commands (.md files)
├── agents/                   # Subagents (.md files)
├── skills/                   # Skills (subdirs with SKILL.md)
├── hooks/
│   └── hooks.json           # Hook configuration
├── .mcp.json                # MCP server definitions
├── .lsp.json                # LSP server configurations
└── scripts/                 # Hook and utility scripts

Important: Components go at plugin root, NOT inside .claude-plugin/. Only plugin.json belongs in .claude-plugin/.

Marketplace Structure

A marketplace can contain multiple plugins. The marketplace root has its own .claude-plugin/marketplace.json:

my-marketplace/
├── .claude-plugin/
│   └── marketplace.json     # Lists all plugins in this marketplace
├── plugins/
│   ├── plugin-a/
│   │   ├── .claude-plugin/
│   │   │   └── plugin.json
│   │   └── skills/
│   └── plugin-b/
│       ├── .claude-plugin/
│       │   └── plugin.json
│       └── commands/

marketplace.json

{
  "name": "my-marketplace",
  "owner": {
    "name": "author-name"
  },
  "plugins": [
    {
      "name": "plugin-a",
      "source": "./plugins/plugin-a",
      "description": "First plugin description",
      "version": "1.0.0"
    },
    {
      "name": "plugin-b",
      "source": "./plugins/plugin-b",
      "description": "Second plugin description",
      "version": "0.2.0"
    }
  ]
}

Critical: When adding a new plugin to a marketplace:

  1. Add it to marketplace.json or it won't be installable
  2. If using release-please, add a jsonpath entry to the config for the new plugin's version

Minimal plugin.json

{
  "name": "my-plugin",
  "version": "1.0.0",
  "description": "Brief plugin description"
}

Installation Scopes

ScopeLocationUse case
user~/.claude/settings.jsonPersonal plugins (default)
project.claude/settings.jsonTeam plugins via version control
local.claude/settings.local.jsonProject-specific, gitignored
managedmanaged-settings.jsonRead-only managed plugins

Environment Variables

Use ${CLAUDE_PLUGIN_ROOT} for paths in hooks and MCP configs:

{
  "command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh"
}

Plugin Components Summary

ComponentLocationFormat
Commandscommands/Markdown with frontmatter
Agentsagents/Markdown with frontmatter
Skillsskills/*/SKILL.mdDirectories with SKILL.md
Hookshooks/hooks.jsonJSON configuration
MCP servers.mcp.jsonMCP server config
LSP servers.lsp.jsonLanguage server config

CLI Quick Reference

# Install
claude plugin install <plugin>@<marketplace> --scope user

# Manage
claude plugin enable <plugin>
claude plugin disable <plugin>
claude plugin update <plugin>
claude plugin uninstall <plugin>

# Debug
claude --debug

Permissions

Problem: Using ! backticks to run plugin scripts fails with permission error:

Error: Bash command permission check failed for pattern
"!`${CLAUDE_PLUGIN_ROOT}/scripts/my-script.sh 2>&1 || true`":
This Bash command contains multiple operations.

Cause: ! backticks have their own permission model separate from allowed-tools. Complex commands or scripts fail.

Solution: Use the Bash tool instead of ! backticks for scripts:

---
allowed-tools: Bash(${CLAUDE_PLUGIN_ROOT}/scripts/my-script.sh:*)
---

Run the script:
    ```bash
    ${CLAUDE_PLUGIN_ROOT}/scripts/my-script.sh
    ```

Simple git commands still work with ! backticks: !git branch --show-current``

Common Issues

Plugin installed but commands don't appear?

The plugin may be disabled. Check ~/.claude/settings.json:

"enabledPlugins": {
  "my-plugin@my-marketplace": false  // ← Disabled!
}

Fix with: claude plugin enable my-plugin@my-marketplace then restart Claude Code.

Local changes not picked up?

Use claude plugin update <plugin> or do a full reinstall:

claude plugin marketplace remove my-marketplace
claude plugin marketplace add ./
claude plugin install my-plugin@my-marketplace

Important

After creating or modifying plugins, inform the user:

Plugin changes take effect immediately after installation. Use claude --debug to verify plugin loading.

Checklist

Before finalizing a plugin:

  • plugin.json has name, version, description
  • Components at plugin root (not in .claude-plugin/)
  • All paths use ${CLAUDE_PLUGIN_ROOT} variable
  • Scripts are executable (chmod +x)
  • If part of a marketplace, plugin is listed in marketplace.json
  • If using release-please, add jsonpath for new plugin version in config
  • Test with claude --debug to verify loading
Repository
github.com/dwmkerr/claude-toolkit
Last updated
Created

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.