📦 deps(thirdparty): update snapshots

This commit is contained in:
ci[bot]
2026-05-29 08:33:53 +00:00
parent fdb52f1e96
commit 06e0d13d57
1615 changed files with 232858 additions and 0 deletions
@@ -0,0 +1,89 @@
# Plugin Caching Reference
How Claude Code caches plugins and implications for plugin structure.
## How Plugin Caching Works
When plugins are installed, Claude Code copies them to a cache directory for security. This affects how you structure shared resources.
## Path Traversal Limitation
Paths that traverse outside the plugin root will not work after installation:
```
# BROKEN after install - traverses outside plugin
../../shared-utils/helper.sh
../other-plugin/rules/FORMATTING.md
```
Only files within the plugin directory are copied to the cache.
## Shared Resources Within a Plugin
Organize shared resources inside your plugin:
```
my-plugin/
├── .claude-plugin/
│ └── plugin.json
├── rules/ # Shared rules
│ └── FORMATTING.md
├── scripts/ # Shared scripts
│ └── validate.sh
└── skills/
└── my-skill/
└── SKILL.md # Can reference ../../rules/FORMATTING.md
```
Skills can reference `../../rules/FORMATTING.md` because it stays within the plugin.
## Cross-Plugin Dependencies
If plugins need to share resources across plugin boundaries, you have three options:
### Option 1: Symlinks
Create symlinks within your plugin that point to external files. Symlinks are followed during the copy:
```bash
# Inside your plugin directory
ln -s /path/to/shared-utils ./shared-utils
```
### Option 2: Restructure Marketplace
Set the marketplace source to a parent directory containing all plugins:
```json
{
"name": "my-plugin",
"source": "./",
"description": "Plugin with access to sibling directories",
"commands": ["./plugins/my-plugin/commands/"],
"skills": ["./plugins/my-plugin/skills/"],
"strict": false
}
```
This copies the entire marketplace root, giving plugins access to siblings.
### Option 3: Skill Invocation (Recommended)
Instead of file references, use skill invocation for cross-plugin patterns:
```markdown
## Related Skills
- **outfitter:tdd** - Test-driven development patterns
- **outfitter:debugging** - Systematic debugging methodology
```
Reference skills by `plugin:skill-name` and invoke with the Skill tool.
## Best Practice
**Prefer Option 3** (skill invocation) when possible. It:
- Avoids caching complexity
- Works regardless of installation method
- Maintains clean plugin boundaries
- Enables proper versioning of dependencies
@@ -0,0 +1,406 @@
# Plugin Distribution Reference
Packaging, versioning, and release automation for Claude Code plugins.
## Distribution Checklist
Before distributing:
- [ ] Plugin structure is correct
- [ ] plugin.json is complete and valid
- [ ] All components tested
- [ ] Documentation complete (README, CHANGELOG)
- [ ] License file included
- [ ] Version number updated
- [ ] Git tags created
- [ ] GitHub release published
## Required Files for Distribution
```
my-plugin/
├── plugin.json # Required: metadata
├── README.md # Required: documentation
├── LICENSE # Required: license
├── CHANGELOG.md # Recommended: history
└── [components] # Commands, agents, etc.
```
## README Template
```markdown
# Plugin Name
Brief description of what this plugin does.
## Installation
\`\`\`bash
/plugin marketplace add owner/plugin-repo
/plugin install plugin-name@owner
\`\`\`
Or locally:
\`\`\`bash
/plugin marketplace add ./path/to/plugin
/plugin install plugin-name@plugin-name
\`\`\`
## Features
- Feature 1
- Feature 2
## Usage
### Commands
- `/command-name` - Description
### Agents
Describe custom agents.
## Configuration
Required environment variables:
\`\`\`bash
export VAR_NAME=value
\`\`\`
## Requirements
- Claude Code
- Node.js 18+ (if applicable)
## License
MIT License
```
## CHANGELOG Template
```markdown
# Changelog
Format based on [Keep a Changelog](https://keepachangelog.com/).
## [1.0.0] - 2025-01-20
### Added
- Initial release
- Command X for feature Y
### Changed
- Updated behavior of command A
### Fixed
- Fixed bug in agent B
## [0.1.0] - 2025-01-10
### Added
- Initial development version
```
## Semantic Versioning
**Format:** `MAJOR.MINOR.PATCH`
| Type | When | Example |
|------|------|---------|
| MAJOR | Breaking changes | 1.0.0 -> 2.0.0 |
| MINOR | New features (compatible) | 1.0.0 -> 1.1.0 |
| PATCH | Bug fixes | 1.0.0 -> 1.0.1 |
### Version Bump Workflow
```bash
# 1. Update plugin.json version
# 2. Update CHANGELOG.md
# 3. Commit
git add plugin.json CHANGELOG.md
git commit -m "chore: bump version to 1.1.0"
# 4. Tag
git tag v1.1.0
# 5. Push
git push origin main --tags
```
## Packaging
### ZIP Distribution
**Correct structure:**
```
my-plugin.zip
└── my-plugin/ # Plugin folder at root
├── plugin.json
├── README.md
└── ...
```
### Creating Package
```bash
# From parent directory
zip -r my-plugin.zip my-plugin/ \
-x "*.git*" "*.DS_Store" "node_modules/*" "test/*"
# Verify
unzip -l my-plugin.zip
```
### Package Script
```bash
#!/bin/bash
VERSION=$(jq -r '.version' plugin.json)
PLUGIN_NAME=$(jq -r '.name' plugin.json)
cd ..
zip -r "${PLUGIN_NAME}-v${VERSION}.zip" "${PLUGIN_NAME}/" \
-x "*.git*" "*.github*" "*.DS_Store" "node_modules/*" "test/*"
echo "Created ${PLUGIN_NAME}-v${VERSION}.zip"
```
## GitHub Releases
### Manual Release
```bash
# Tag and push
git tag v1.0.0
git push origin v1.0.0
# Create release
gh release create v1.0.0 \
--title "v1.0.0 - Initial Release" \
--notes "Release notes here"
```
### Release with Artifact
```bash
# Create package
zip -r my-plugin-v1.0.0.zip my-plugin/
# Create release with artifact
gh release create v1.0.0 \
--title "v1.0.0" \
--notes-file CHANGELOG.md \
my-plugin-v1.0.0.zip
```
## CI/CD Integration
### GitHub Actions - Validation
**.github/workflows/validate.yml:**
```yaml
name: Validate Plugin
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate JSON
run: jq empty plugin.json
- name: Check required files
run: |
test -f README.md || exit 1
test -f LICENSE || exit 1
- name: Validate commands
run: |
if [ -d commands ]; then
for f in commands/**/*.md; do
grep -q "^---$" "$f" || exit 1
done
fi
```
### GitHub Actions - Release
**.github/workflows/release.yml:**
```yaml
name: Release Plugin
on:
push:
tags: ['v*']
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate
run: |
test -f plugin.json
test -f README.md
test -f LICENSE
jq empty plugin.json
- name: Get version
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Verify version match
run: |
PLUGIN_VERSION=$(jq -r '.version' plugin.json)
if [ "$PLUGIN_VERSION" != "${{ steps.version.outputs.VERSION }}" ]; then
echo "Version mismatch"
exit 1
fi
- name: Create package
run: |
PLUGIN_NAME=$(jq -r '.name' plugin.json)
cd ..
zip -r "${PLUGIN_NAME}-v${{ steps.version.outputs.VERSION }}.zip" \
"${PLUGIN_NAME}/" -x "*.git*" "*.github*"
mv *.zip "${PLUGIN_NAME}/"
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: '*-v${{ steps.version.outputs.VERSION }}.zip'
generate_release_notes: true
```
## Distribution Methods
### Method 1: GitHub Repository
```bash
# Users install:
/plugin marketplace add username/my-plugin
/plugin install my-plugin@username
```
**Advantages:** Version control, issues, free hosting
### Method 2: Git URL
```bash
# For GitLab, Bitbucket, self-hosted
/plugin marketplace add https://gitlab.com/user/my-plugin.git
```
### Method 3: Marketplace Entry
Add to existing marketplace:
```json
{
"plugins": [
{
"name": "my-plugin",
"source": {
"source": "github",
"repo": "username/my-plugin"
},
"description": "Plugin description",
"version": "1.0.0"
}
]
}
```
### Method 4: Direct Download
Host ZIP and provide instructions:
```bash
wget https://example.com/my-plugin.zip
unzip my-plugin.zip
/plugin marketplace add ./my-plugin
/plugin install my-plugin@my-plugin
```
## Pre-Release Testing
### Beta Release
```bash
# Update to pre-release version
jq '.version = "2.0.0-beta.1"' plugin.json > temp.json
mv temp.json plugin.json
# Tag and release as prerelease
git tag v2.0.0-beta.1
git push origin --tags
gh release create v2.0.0-beta.1 \
--title "v2.0.0-beta.1" \
--prerelease \
--notes "Beta release for testing"
```
## Hotfix Process
```bash
# 1. Create hotfix branch
git checkout -b hotfix/critical-fix
# 2. Fix and test
# 3. Bump patch version
# 4. Merge to main
git checkout main
git merge hotfix/critical-fix
# 5. Tag and release
git tag v1.0.1
git push origin main --tags
gh release create v1.0.1 \
--title "v1.0.1 - Critical Fix" \
--latest
```
## Version Bump Script
```bash
#!/bin/bash
BUMP_TYPE="${1:-patch}"
CURRENT=$(jq -r '.version' plugin.json)
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT"
case $BUMP_TYPE in
major) MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 ;;
minor) MINOR=$((MINOR + 1)); PATCH=0 ;;
patch) PATCH=$((PATCH + 1)) ;;
esac
NEW="${MAJOR}.${MINOR}.${PATCH}"
jq --arg v "$NEW" '.version = $v' plugin.json > temp.json
mv temp.json plugin.json
echo "Bumped to $NEW"
```
Usage:
```bash
./bump-version.sh patch # 1.0.0 -> 1.0.1
./bump-version.sh minor # 1.0.1 -> 1.1.0
./bump-version.sh major # 1.1.0 -> 2.0.0
```
@@ -0,0 +1,633 @@
# Marketplace Reference
Complete schema, hosting strategies, and team configuration for Claude Code plugin marketplaces.
## What is a Marketplace?
A marketplace is a catalog of plugins defined in `.claude-plugin/marketplace.json` that enables:
- Plugin discovery
- One-command installation
- Version management
- Team distribution
## Marketplace Schema
### Required Fields
| Field | Type | Description |
|-------|------|-------------|
| `name` | string | Marketplace identifier (kebab-case, no spaces) |
| `owner` | object | Maintainer information |
| `plugins` | array | List of plugin entries |
### Owner Fields
| Field | Required | Description |
|-------|----------|-------------|
| `owner.name` | Yes | Name of maintainer or team |
| `owner.email` | No | Contact email |
### Reserved Names
The following marketplace names are reserved and cannot be used:
- `claude-code-marketplace`
- `claude-code-plugins`
- `claude-plugins-official`
- `anthropic-marketplace`
- `anthropic-plugins`
- `agent-skills`
- `life-sciences`
Names that impersonate official marketplaces (like `official-claude-plugins` or `anthropic-tools-v2`) are also blocked.
### Optional Metadata
| Field | Type | Description |
|-------|------|-------------|
| `metadata.description` | string | Brief marketplace description |
| `metadata.version` | string | Marketplace version |
| `metadata.pluginRoot` | string | Documentation hint for where plugins live. Does NOT affect schema validation—always use explicit `./` prefix in source paths. |
### Complete Example
For local plugins (relative paths), use `strict: false` to consolidate metadata. Always use explicit `./` prefix for source paths:
```json
{
"name": "company-tools",
"owner": {
"name": "Engineering Team",
"email": "eng@company.com"
},
"metadata": {
"description": "Internal development tools",
"version": "2.0.0"
},
"strict": false,
"plugins": [
{
"name": "code-formatter",
"source": "./code-formatter",
"version": "1.0.0",
"description": "Auto-format code on save",
"license": "MIT"
},
{
"name": "deployment-tools",
"source": "./deployment",
"version": "2.1.0",
"description": "Deploy to staging and production",
"license": "MIT"
}
]
}
```
With `strict: false`, plugins don't need their own `.claude-plugin/plugin.json`—the marketplace is the single source of truth.
## Plugin Entry Schema
### Local Plugins (Consolidated)
For plugins in the same repo as the marketplace, define all metadata in the marketplace entry:
```json
{
"name": "code-formatter",
"source": "./code-formatter",
"version": "1.0.0",
"description": "Auto-format code on save",
"license": "MIT",
"keywords": ["formatting", "linting"]
}
```
Set `strict: false` at the marketplace level. Plugins don't need their own `.claude-plugin/plugin.json`.
**Benefits:** Single source of truth, prevents version/metadata drift between marketplace and plugin manifests.
### External Plugins (Distributed)
For plugins in external repos, use minimal entries—let the external repo own its manifest:
```json
{
"name": "enterprise-tools",
"source": {
"source": "github",
"repo": "company/enterprise-plugin"
}
}
```
The external repo should have its own `.claude-plugin/plugin.json` with metadata.
**Why:** External plugins may be used outside your marketplace. They should be self-contained.
### Entry Fields
**Required:**
| Field | Type | Description |
|-------|------|-------------|
| `name` | string | Plugin identifier (kebab-case, no spaces) |
| `source` | string\|object | Where to fetch plugin (relative path, GitHub, or git URL) |
**Standard metadata** (optional):
| Field | Type | Description |
|-------|------|-------------|
| `description` | string | Brief plugin description |
| `version` | string | Plugin version |
| `author` | object | Author info (`name` required, `email` optional) |
| `homepage` | string | Documentation URL |
| `repository` | string | Source code URL |
| `license` | string | SPDX identifier (MIT, Apache-2.0) |
| `keywords` | array | Tags for discovery |
| `category` | string | Plugin category |
| `tags` | array | Additional searchability tags |
**Behavior control:**
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `strict` | boolean | `true` | When `false`, plugins don't need their own `.claude-plugin/plugin.json`—marketplace defines everything. Use for local plugins (relative paths). When `true`, plugins must have their own manifest. |
**When to use each mode:**
| Pattern | `strict` | Use when |
|---------|----------|----------|
| Consolidated | `false` | All plugins are local (relative paths in same repo) |
| Distributed | `true` | Plugins are external repos that may be used elsewhere |
| Mixed | `false` | Local plugins consolidated, external plugins own their manifests |
**Component configuration** (optional):
| Field | Type | Description |
|-------|------|-------------|
| `commands` | string\|array | Custom paths to command files or directories |
| `agents` | string\|array | Custom paths to agent files |
| `hooks` | string\|object | Hook configuration or path to hooks file |
| `mcpServers` | string\|object | MCP server configuration or path to MCP config |
| `lspServers` | string\|object | LSP server configuration or path to LSP config |
## Plugin Source Types
### Relative Path
For plugins in the same repository, always use explicit `./` prefix paths:
**Plugins at repo root:**
```json
{
"plugins": [
{"name": "my-plugin", "source": "./my-plugin"},
{"name": "another", "source": "./another"}
]
}
```
**Plugins in a subdirectory:**
```json
{
"plugins": [
{"name": "my-plugin", "source": "./packages/my-plugin"},
{"name": "another", "source": "./packages/another"}
]
}
```
The schema requires the `./` prefix for relative paths. Bare names like `"source": "my-plugin"` fail validation.
### GitHub Repository
```json
{
"source": {
"source": "github",
"repo": "owner/plugin-repo"
}
}
```
With specific version:
```json
{
"source": {
"source": "github",
"repo": "owner/plugin-repo",
"ref": "v1.5.0"
}
}
```
Pin to exact commit:
```json
{
"source": {
"source": "github",
"repo": "owner/plugin-repo",
"ref": "v2.0.0",
"sha": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0"
}
}
```
Monorepo pattern (plugin in a subdirectory):
```json
{
"source": {
"source": "github",
"repo": "owner/my-project",
"path": "./packages/claude-plugin"
}
}
```
Use `path` when the plugin lives alongside application code in a monorepo. Common patterns:
| Monorepo Structure | `path` Value |
|--------------------|--------------|
| `packages/claude-plugin/` | `./packages/claude-plugin` |
| `.claude-plugin/` at root | (omit — this is the default) |
| `tools/claude-plugin/` | `./tools/claude-plugin` |
| Field | Type | Description |
|-------|------|-------------|
| `repo` | string | Required. GitHub repository in `owner/repo` format |
| `path` | string | Optional. Subdirectory containing `.claude-plugin/plugin.json` |
| `ref` | string | Optional. Branch name or tag (omit to use default branch) |
| `sha` | string | Optional. Full 40-character commit SHA for exact version pinning |
### Git URL
For GitLab, Bitbucket, or self-hosted:
```json
{
"source": {
"source": "url",
"url": "https://gitlab.com/team/plugin.git"
}
}
```
With specific branch or SHA pinning:
```json
{
"source": {
"source": "url",
"url": "https://gitlab.com/team/plugin.git",
"ref": "develop",
"sha": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0"
}
}
```
| Field | Type | Description |
|-------|------|-------------|
| `url` | string | Required. Full git repository URL (must end with `.git`) |
| `path` | string | Optional. Subdirectory containing `.claude-plugin/plugin.json` |
| `ref` | string | Optional. Branch name or tag (omit to use default branch) |
| `sha` | string | Optional. Full 40-character commit SHA for exact version pinning |
### Private Repository Authentication
Claude Code supports installing plugins from private repositories. Set the appropriate authentication token in your environment:
| Provider | Environment Variables | Notes |
|----------|----------------------|-------|
| GitHub | `GITHUB_TOKEN` or `GH_TOKEN` | Personal access token or GitHub App token |
| GitLab | `GITLAB_TOKEN` or `GL_TOKEN` | Personal access token or project token |
| Bitbucket | `BITBUCKET_TOKEN` | App password or repository access token |
Set the token in your shell configuration (`.bashrc`, `.zshrc`) or pass it when running Claude Code:
```bash
export GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx
```
Authentication tokens are only used when a repository requires authentication. Public repositories work without tokens.
## Marketplace Types
### Team/Organization
```json
{
"name": "company-internal",
"owner": {
"name": "Engineering",
"email": "eng@company.com"
},
"metadata": {
"description": "Internal development tools"
},
"plugins": [
{"name": "deploy-tools", "source": "./plugins/deploy"},
{"name": "compliance", "source": "./plugins/compliance"}
]
}
```
**Hosting:** Private GitHub repo or internal Git
### Project-Specific
```json
{
"name": "project-tools",
"owner": {
"name": "Project Team",
"email": "project@company.com"
},
"plugins": [
{"name": "project-workflow", "source": "./plugins/workflow"}
]
}
```
**Hosting:** In project at `.claude-plugin/marketplace.json`
### Public/Community
```json
{
"name": "awesome-plugins",
"owner": {
"name": "Community"
},
"metadata": {
"description": "Curated Claude Code plugins"
},
"plugins": [
{
"name": "markdown-tools",
"source": {"source": "github", "repo": "user/markdown-tools"},
"license": "MIT"
}
]
}
```
## Team Configuration
### Automatic Installation
Configure in `.claude/settings.json`:
```json
{
"extraKnownMarketplaces": {
"team-tools": {
"source": {
"source": "github",
"repo": "company/claude-plugins"
}
}
}
}
```
Automatically installed when team members trust the folder.
### Multi-Environment
```json
{
"extraKnownMarketplaces": {
"development": {
"source": {
"source": "github",
"repo": "company/plugins",
"ref": "develop"
}
},
"production": {
"source": {
"source": "github",
"repo": "company/plugins"
}
}
}
}
```
Use `ref` to point development at a non-default branch. Production uses the default branch (no `ref` needed).
## Marketplace Commands
### Adding Marketplaces
```bash
# GitHub (short form)
/plugin marketplace add owner/repo
# GitHub (full URL)
/plugin marketplace add https://github.com/owner/repo
# Git repository
/plugin marketplace add https://gitlab.com/company/plugins.git
# Local directory
/plugin marketplace add ./path/to/marketplace
# Remote JSON URL
/plugin marketplace add https://example.com/marketplace.json
```
### Management
```bash
# List marketplaces
/plugin marketplace list
# Update specific
/plugin marketplace update marketplace-name
# Update all
/plugin marketplace update --all
# Remove (also uninstalls plugins)
/plugin marketplace remove marketplace-name
# View details
/plugin marketplace info marketplace-name
```
### Plugin Installation
```bash
# From marketplace
/plugin install plugin-name@marketplace-name
# Specific version
/plugin install plugin-name@marketplace-name@1.2.0
# List available
/plugin list marketplace-name
# Search across marketplaces
/plugin search keyword
```
## Validation
### Validate JSON
```bash
# Syntax check
jq empty .claude-plugin/marketplace.json
# Required fields
jq -e '.name, .owner, .plugins' .claude-plugin/marketplace.json
# Plugin entries
jq -e '.plugins[] | .name, .source' .claude-plugin/marketplace.json
```
### Validate Sources
```bash
# Check relative paths
for plugin in $(jq -r '.plugins[] | select(.source | type == "string") | .source' .claude-plugin/marketplace.json); do
if [[ ! -d "$plugin" ]]; then
echo "Missing: $plugin"
fi
done
# Check GitHub repos
for repo in $(jq -r '.plugins[] | select(.source.source == "github") | .source.repo' .claude-plugin/marketplace.json); do
gh repo view "$repo" > /dev/null || echo "Invalid: $repo"
done
```
## Hosting Strategies
### GitHub (Recommended)
**Advantages:**
- Version control
- Issue tracking
- Collaboration
- Free hosting
- Easy sharing
**Setup:**
1. Create repository
2. Add `.claude-plugin/marketplace.json`
3. Push
4. Share: `/plugin marketplace add owner/repo`
### GitLab/Bitbucket
```bash
/plugin marketplace add https://gitlab.com/company/plugins.git
```
**Advantages:**
- Self-hosted options
- Enterprise integration
### Local Development
```bash
/plugin marketplace add ./my-marketplace
```
**Advantages:**
- Fast iteration
- No network required
- Easy testing
## CI/CD Integration
### GitHub Actions
```yaml
name: Validate Marketplace
on:
push:
paths: ['.claude-plugin/marketplace.json']
pull_request:
paths: ['.claude-plugin/marketplace.json']
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate JSON
run: jq empty .claude-plugin/marketplace.json
- name: Check fields
run: jq -e '.name, .owner.name, .plugins' .claude-plugin/marketplace.json
- name: Check sources
run: |
for plugin in $(jq -r '.plugins[] | select(.source | type == "string") | .source' .claude-plugin/marketplace.json); do
if [[ ! -d "$plugin" ]]; then
echo "Missing: $plugin"
exit 1
fi
done
```
## Best Practices
### Organization
- Group related plugins together
- Use categories for discovery
- Maintain consistent naming
- Document plugin purposes
### Versioning
- Use semantic versioning
- Track versions in entries
- Maintain CHANGELOG
- Tag releases in Git
### Security
- Review plugins before adding
- Verify sources
- Document requirements
- Use private repos for sensitive tools
### Maintenance
- Keep versions updated
- Remove deprecated plugins
- Test after updates
- Monitor feedback
## Troubleshooting
**Marketplace not loading:**
- Verify URL accessible
- Check `.claude-plugin/marketplace.json` exists
- Validate JSON syntax
- Confirm access for private repos
**Plugin installation failures:**
- Verify source URLs accessible
- Check plugin directories exist
- Test sources manually
- Review error messages
**Team configuration not working:**
- Verify `.claude/settings.json` syntax
- Check marketplace sources accessible
- Ensure folder trusted
- Restart Claude Code
@@ -0,0 +1,502 @@
# Plugin Structure Reference
Complete directory layout and configuration schemas for Claude Code plugins.
## Plugin Structure
How you structure plugins depends on how they're distributed.
### Single Plugin (Standalone)
Standalone plugins need their own `.claude-plugin/plugin.json`:
```
my-plugin/
├── .claude-plugin/
│ └── plugin.json # Plugin manifest (required)
├── commands/
├── agents/
├── hooks/
│ └── hooks.json # Auto-discovered hooks (or inline in plugin.json)
└── README.md
```
### Marketplace with Local Plugins (Consolidated)
When all plugins live in the same repo as the marketplace, use `strict: false` to consolidate metadata in `marketplace.json`. Plugins don't need their own manifests:
```
my-marketplace/
├── .claude-plugin/
│ └── marketplace.json # All metadata here (strict: false)
├── plugin-a/
│ ├── commands/
│ ├── agents/
│ └── README.md
├── plugin-b/
│ ├── skills/
│ └── README.md
└── README.md
```
**Benefits:** Single source of truth, no version drift, simpler structure.
### Marketplace with External Plugins (Distributed)
When referencing plugins from external repos (GitHub, GitLab, etc.), let each plugin own its manifest:
```
my-marketplace/
├── .claude-plugin/
│ └── marketplace.json # Points to external repos
└── README.md
# External repos each have:
external-plugin/
├── .claude-plugin/
│ └── plugin.json # Plugin owns its manifest
├── commands/
└── README.md
```
**Key principle:** External plugins are self-contained. The marketplace.json points to them via `source` but doesn't define their metadata.
### Mixed Approach
Marketplaces can combine both patterns—consolidated for local plugins, distributed for external:
```json
{
"strict": false,
"plugins": [
{"name": "local-plugin", "source": "./local-plugin", "version": "1.0.0"},
{"name": "external-plugin", "source": {"source": "github", "repo": "owner/plugin"}}
]
}
```
## Directory Structure
### Minimal Standalone Plugin
```
my-plugin/
├── .claude-plugin/
│ └── plugin.json # Required: metadata
└── README.md # Required for distribution
```
### Complete Standalone Plugin
```
my-plugin/
├── .claude-plugin/
│ └── plugin.json # Plugin metadata
├── README.md # Documentation
├── CHANGELOG.md # Version history
├── LICENSE # License file
├── .gitignore # Git ignore patterns
├── commands/ # Slash commands
│ ├── core/ # Core commands
│ │ └── help.md
│ └── advanced/ # Advanced features
│ └── deploy.md
├── agents/ # Custom agents
│ ├── reviewer.md
│ └── analyzer.md
├── skills/ # Reusable skills
│ └── my-skill/
│ └── SKILL.md
├── hooks/ # Event hooks
│ └── hooks.json # Auto-discovered (required format)
├── servers/ # MCP servers
│ └── my-server/
│ ├── server.py
│ └── pyproject.toml
└── scripts/ # Utility scripts
└── setup.sh
```
## plugin.json Schema
### Required Fields
| Field | Type | Description | Example |
|-------|------|-------------|---------|
| `name` | string | Unique identifier (kebab-case, no spaces) | `"deployment-tools"` |
### Recommended Metadata Fields
| Field | Type | Description |
|-------|------|-------------|
| `version` | string | Semantic version (e.g., "1.0.0") |
| `description` | string | Brief plugin description |
### Optional Standard Fields
| Field | Type | Description |
|-------|------|-------------|
| `author` | object | Creator information |
| `author.name` | string | Author name |
| `author.email` | string | Author email |
| `homepage` | string | Documentation URL |
| `repository` | string | Source code URL |
| `license` | string | SPDX identifier (MIT, Apache-2.0) |
| `keywords` | array | Search tags |
| `category` | string | Plugin category |
| `tags` | array | Additional searchability tags |
### Component Configuration Fields
| Field | Type | Description |
|-------|------|-------------|
| `commands` | string\|array | Custom paths to command files or directories |
| `agents` | string\|array | Custom paths to agent files |
| `hooks` | string\|object | Hook config path or inline config |
| `mcpServers` | string\|object | MCP config path or inline config |
| `lspServers` | string\|object | LSP config path or inline config |
### Behavior Control
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `strict` | boolean | `true` | Set at marketplace level. When `false`, local plugins don't need `.claude-plugin/plugin.json`—marketplace defines all metadata. Use `false` for consolidated local plugins, `true` (or omit) for external plugins. |
> **Note:** Hooks can be defined inline in plugin.json OR in a separate `hooks/hooks.json` file.
### Complete Example
```json
{
"name": "enterprise-tools",
"version": "2.1.0",
"description": "Enterprise workflow automation tools",
"author": {
"name": "Enterprise Team",
"email": "team@company.com"
},
"homepage": "https://docs.company.com/plugins",
"repository": "https://github.com/company/enterprise-tools",
"license": "MIT",
"keywords": ["enterprise", "workflow", "automation"],
"category": "productivity",
"commands": [
"./commands/core/",
"./commands/enterprise/"
],
"agents": [
"./agents/security-reviewer.md",
"./agents/compliance-checker.md"
],
"mcpServers": {
"database": {
"command": "${CLAUDE_PLUGIN_ROOT}/servers/db-server",
"args": ["--config", "${CLAUDE_PLUGIN_ROOT}/config.json"],
"env": {
"DB_HOST": "${DATABASE_HOST}",
"DB_PASSWORD": "${DATABASE_PASSWORD}"
}
}
}
}
```
> **Note:** Hooks can be inlined in plugin.json (add a `"hooks"` key) or defined in `hooks/hooks.json`. See [Event Hooks](#event-hooks) below.
## Slash Commands
### Command File Structure
Commands are markdown files with YAML frontmatter in `commands/`.
```markdown
---
description: "Brief description shown in /help"
---
Command instructions here.
Use {{0}}, {{1}} for parameters.
```
### Parameter Syntax
| Syntax | Description | Example |
|--------|-------------|---------|
| `{{0}}` | First parameter | `/cmd value` |
| `{{1}}` | Second parameter | `/cmd val1 val2` |
| `{{0:name}}` | Named (documentation) | `{{0:environment}}` |
| `{{...}}` | All remaining | `/cmd arg1 arg2 arg3` |
### Example Command
```markdown
---
description: "Deploy to specified environment"
---
Deploy application to {{0:environment}}.
Steps:
1. Validate environment configuration
2. Run pre-deployment checks
3. Deploy application
4. Verify deployment
```
## Custom Agents
### Agent File Structure
Agents are markdown files with YAML frontmatter in `agents/`.
```markdown
---
description: "What this agent specializes in"
capabilities: ["task1", "task2", "task3"]
allowed-tools: Read, Grep, Glob
---
# Agent Name
Detailed description of the agent's role, expertise, and when Claude should invoke it.
## Capabilities
- Specific task the agent excels at
- Another specialized capability
- When to use this agent vs others
## Context and examples
Provide examples of when this agent should be used.
```
### Agent Frontmatter Fields
| Field | Type | Description |
|-------|------|-------------|
| `description` | string | Brief explanation of what the agent does |
| `capabilities` | array | List of tasks the agent can perform (aids discovery) |
| `allowed-tools` | string | Comma-separated list of allowed tools (optional) |
### Tool Restrictions
| Restriction | Tools | Use Case |
|-------------|-------|----------|
| Read-only | `Read, Grep, Glob` | Analysis only |
| With execution | `Read, Grep, Glob, Bash` | Analysis + commands |
| No restriction | (omit field) | Full capabilities |
## Event Hooks
Two ways to define hooks in a plugin:
1. **Inline in plugin.json** — Add a `"hooks"` key directly
2. **File-based** — Auto-discovered from `hooks/hooks.json`
### Option 1: Inline in plugin.json
```json
{
"name": "my-plugin",
"version": "1.0.0",
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh"
}
]
}
]
}
}
```
### Option 2: Separate hooks.json File
```
my-plugin/
├── .claude-plugin/
│ └── plugin.json # Can also have hooks inline here
└── hooks/
└── hooks.json # Auto-discovered if present
```
### Hook Types
| Type | When | Use Cases |
|------|------|-----------|
| `PreToolUse` | Before tool | Validation, permissions |
| `PostToolUse` | After tool | Logging, formatting |
| `UserPromptSubmit` | Before prompt | Input validation |
| `Stop` | After response | Cleanup, notifications |
| `SessionStart` | Session begins | Context loading |
| `SessionEnd` | Session ends | Cleanup |
### hooks/hooks.json Format
When using a separate file, it requires a root-level `"hooks"` wrapper:
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh",
"timeout": 10
}
]
}
],
"PostToolUse": [
{
"matcher": "Write(*.ts)",
"hooks": [
{
"type": "command",
"command": "biome check --write \"$file\"",
"timeout": 30
}
]
}
]
}
}
```
### Key Points
- Hooks can be inline in plugin.json OR in `hooks/hooks.json`
- Both formats use a `"hooks"` object containing event types
- Use `${CLAUDE_PLUGIN_ROOT}` for paths relative to plugin
- Use `$file` for the affected file path in PostToolUse
### Hook Script Interface
**Input (stdin):**
```json
{
"session_id": "abc123",
"transcript_path": "/path/to/transcript.jsonl",
"cwd": "/current/working/directory",
"hook_event_name": "PreToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "/project/src/file.ts",
"content": "export const foo = 'bar';"
}
}
```
**Output (stdout):**
Allow:
```json
{"allowed": true}
```
Block:
```json
{
"allowed": false,
"message": "Validation failed: reason"
}
```
Modify:
```json
{
"allowed": true,
"modified_parameters": {
"content": "modified content"
}
}
```
### Example Hook Script
```bash
#!/usr/bin/env bash
input=$(cat)
file_path=$(echo "$input" | jq -r '.tool_input.file_path')
content=$(echo "$input" | jq -r '.tool_input.content')
# Check for secrets
if echo "$content" | grep -qiE 'api[_-]?key.*=.*[a-zA-Z0-9]{16,}'; then
echo '{"allowed": false, "message": "Potential secret detected"}'
exit 0
fi
echo '{"allowed": true}'
```
## MCP Servers
### Server Configuration
```json
{
"mcpServers": {
"server-name": {
"command": "${CLAUDE_PLUGIN_ROOT}/servers/my-server",
"args": ["--flag", "value"],
"env": {
"API_KEY": "${MY_API_KEY}"
}
}
}
}
```
### Variable Substitution
| Variable | Resolves To |
|----------|-------------|
| `${CLAUDE_PLUGIN_ROOT}` | Plugin installation directory |
| `${VAR_NAME}` | Environment variable |
### Python MCP Server Example
```python
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my-server")
@mcp.tool()
async def my_tool(param: str) -> str:
"""Tool description"""
return f"Result: {param}"
if __name__ == "__main__":
mcp.run(transport='stdio')
```
## Platform Considerations
### macOS
- Config: `~/Library/Application Support/Claude/`
- Logs: `~/Library/Logs/Claude/`
### Windows
- Config: `%APPDATA%\Claude\`
- Use forward slashes or double backslashes
### Linux
- Config: `~/.config/claude/`
- Check shebang and permissions