Thank you for your interest in contributing. This guide covers how to add new plugins, modify existing ones, and work with the CI/CD pipeline.
- Claude Code (for testing plugins)
jqon your PATH- ShellCheck (for linting hook scripts)
claude-code-plugins/
├── .claude-plugin/
│ └── marketplace.json # Central plugin registry
├── .github/
│ ├── scripts/
│ │ ├── validate-plugins.sh # PR validation script
│ │ ├── detect-changes.sh # Change detection for CI
│ │ └── bump-plugin.sh # Auto version bumping
│ └── workflows/
│ ├── pr.yml # PR validation
│ ├── release.yml # Auto-release on main
│ └── tag-release.yml # GitHub release creation
└── plugins/
├── claude-switcher/ # Account switching plugin
├── git-master/ # Git workflow control plugin
└── opaq/ # Credential security plugin
plugins/<your-plugin>/
├── .claude-plugin/
│ └── plugin.json
└── skills/
└── <skill-name>/
└── SKILL.md
Create plugins/<your-plugin>/.claude-plugin/plugin.json:
{
"name": "<your-plugin>",
"version": "0.1.0",
"description": "Short description of what the plugin does.",
"skills": "./skills/"
}If your plugin uses hooks, add:
{
"name": "<your-plugin>",
"version": "0.1.0",
"description": "Short description of what the plugin does.",
"skills": "./skills/",
"hooks": "./hooks/hooks.json"
}Create plugins/<your-plugin>/skills/<skill-name>/SKILL.md with YAML frontmatter:
---
name: <skill-name>
description: When this skill should activate. Be specific about trigger conditions.
---
# Skill Title
Instructions for Claude on how to use this skill.Frontmatter fields:
| Field | Required | Description |
|---|---|---|
name |
Yes | Skill identifier |
description |
Yes | Trigger conditions — when should Claude use this? |
user-invocable |
No | Set to true if invoked via /skill-name |
argument-hint |
No | Hint shown to the user (e.g., @file.md or description) |
disable-model-invocation |
No | Set to true to prevent automatic activation |
Add an entry to .claude-plugin/marketplace.json:
{
"name": "<your-plugin>",
"source": "./plugins/<your-plugin>",
"description": "Same description as plugin.json",
"version": "0.1.0",
"author": { "name": "your-name" },
"homepage": "https://github.com/...",
"repository": "https://github.com/moukrea/claude-code-plugins",
"license": "MIT",
"keywords": ["relevant", "keywords"],
"category": "security|productivity|developer-tools|..."
}The version in marketplace.json must match the version in plugin.json.
Run the validation script before submitting a PR:
.github/scripts/validate-plugins.shThis checks:
- JSON syntax of
marketplace.jsonand allplugin.jsonfiles - Required fields present
- Version consistency between marketplace and plugin manifests
- ShellCheck passes on all
.shfiles - SKILL.md files have YAML frontmatter
Hooks are shell scripts that intercept Claude's tool calls. They receive JSON on stdin and must output JSON.
| Event | When it fires |
|---|---|
PreToolUse |
Before Claude executes a tool (Bash, Write, Edit, etc.) |
SessionStart |
When a new Claude Code session begins |
{
"tool_name": "Bash",
"tool_input": {
"command": "the command claude wants to run"
}
}To block a tool call:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Explain why this was blocked."
}
}To allow and modify a tool call:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"updatedInput": { "command": "modified command" }
}
}To allow without changes, exit with code 0 and no output.
- Use
#!/usr/bin/env bashandset -euo pipefail - Read input with
INPUT=$(cat)and parse withjq - Keep scripts focused — one responsibility per hook
- All scripts must pass ShellCheck
This project uses Conventional Commits. The CI pipeline uses commit messages to auto-bump plugin versions:
| Prefix | Version Bump | Example |
|---|---|---|
feat: |
Minor | feat(opaq): add JSON output to search |
fix:, perf: |
Patch | fix(craft): handle empty spec files |
BREAKING CHANGE: |
Major | feat(opaq)!: change hook output format |
Scope your commits to a plugin name when the change is plugin-specific.
- Fork the repository and create a branch from
main - Make your changes
- Run
.github/scripts/validate-plugins.shand ensure it passes - Run
shellcheckon any new or modified shell scripts - Write a clear PR description
- Submit the PR
The CI pipeline will automatically run validation on your PR.
Plugin versions are managed automatically by the CI pipeline:
- On merge to
main,bump-plugin.shanalyzes commit messages since the last tag - Versions are bumped per-plugin based on Conventional Commit prefixes
- Tags follow the format
<plugin-name>-v<version>(e.g.,opaq-v0.2.0) - GitHub releases are created automatically from tags
Do not manually edit version numbers in plugin.json or marketplace.json — the pipeline handles it.