--- name: plugin-author description: > Use when the user wants to create a new plugin scaffold ("create a plugin for X", "new plugin called Y"), update plugin configuration ("change the description", "add keyword", "bump version"), or release a plugin version ("release", "tag", "publish"). Manages both Claude Code (.claude-plugin/plugin.json) and Copilot CLI (plugin.json) manifests in one pass. Explicitly out of scope: plugin content (skills, agents, hooks, MCP servers) and marketplace.json entries — use /marketplace-author for those. allowed-tools: Bash Read Write Edit metadata: category: factory source_keys: - context7-websites-code-claude - claude-code-plugins-docs - github-cli-plugin-reference - github-plugins-creating - github-plugins-finding-installing --- ## Gotchas - Both manifests must carry identical `version` values — version parity is a hard invariant (ADR-0016). Never update version in one manifest without updating the other in the same edit pass. - `author.email` belongs in the Copilot manifest (`plugin.json`); `author.url` belongs in the CC manifest (`.claude-plugin/plugin.json`). Do not swap them. - `claude plugin tag --push` is irreversible: it creates a git tag and pushes it to remote. Always present the HITL gate and wait for explicit confirmation before running it. - `name` in both manifests must be kebab-case and must not use reserved prefixes: `anthropic-*`, `claude-*`, `agent-skills`, `official-claude-plugins`. - Copilot manifest lookup order: `.plugin/plugin.json` → `plugin.json` → `.github/plugin/plugin.json` → `.claude-plugin/plugin.json`. The canonical location for the Copilot manifest in this repo is `plugin.json` at the plugin root. - `displayName` is CC-only — do not add it to the Copilot manifest. - `skills`, `agents`, `hooks`, `mcpServers` are Copilot-only fields — do not add them to the CC manifest. ## Route Determine which flow before touching the filesystem. Read both manifest files if the plugin directory exists. - **Plugin directory does not exist** → follow **CREATE flow** - **Plugin directory exists + version/release intent** ("release", "tag", "bump", "publish", "version") → follow **RELEASE flow** - **Plugin directory exists + field change intent** ("update description", "add keyword", "change author") → follow **UPDATE flow** - **Ambiguous** → ask: "Did you mean to create a new plugin, update its configuration, or release a version?" Validate runs automatically before tagging (in RELEASE flow) and can be invoked explicitly at any time. ## CREATE flow ### Prerequisites Before touching the filesystem, confirm you have: - [ ] Plugin name (kebab-case, e.g. `my-tools`) - [ ] Repo root (absolute path or `.` for current directory) If either is missing, stop and ask before proceeding. ### Step 1 — Scaffold Run the scaffold script: ```bash bash scripts/new-plugin.sh ``` Examples: ```bash bash scripts/new-plugin.sh my-tools /root/ai-development bash scripts/new-plugin.sh data-tools . ``` The script creates under `/plugins//`: - `plugin.json` — Copilot manifest with `FILL_IN_*` placeholders - `.claude-plugin/plugin.json` — CC manifest with `FILL_IN_*` placeholders - Empty skeleton directories: `skills/`, `agents/`, `hooks/`, `bin/` Each file/dir is a no-op if it already exists. ### Step 2 — Fill in placeholders Open both manifest files and replace every `FILL_IN_*` placeholder. **Fields shared by both manifests** (must be identical in both): - `name` — kebab-case plugin identifier (already set by script; verify it is correct) - `description` — one or two sentences; what the plugin provides - `version` — SemVer; defaults to `1.0.0`; must be identical in both manifests - `author.name` — author display name - `license` — SPDX identifier (default: `MIT`) - `keywords` — search/discovery tags (default: `[]`) **CC-only fields** (`.claude-plugin/plugin.json` only): - `displayName` — human-readable name shown in plugin manager; capitalised form of `name` - `author.url` — author URL (e.g. Gitea profile URL) **Copilot-only fields** (`plugin.json` only): - `author.email` — author email - `skills`, `agents`, `hooks`, `mcpServers` — paths; defaults are already set by the script ### Step 3 — Validate Check: - [ ] `name` identical in both manifests, kebab-case, no reserved prefixes - [ ] `description` identical in both manifests, non-empty - [ ] `version` identical in both manifests (version parity — ADR-0016) - [ ] `author.name` identical in both manifests - [ ] `license` identical in both manifests - [ ] No `FILL_IN_*` placeholders remain - [ ] `displayName` present in CC manifest only - [ ] `author.url` in CC manifest, `author.email` in Copilot manifest ## UPDATE flow ### Step 1 — Read both manifests Read `plugins//plugin.json` and `plugins//.claude-plugin/plugin.json`. Identify the current field values. ### Step 2 — Classify each change For every field the user wants to change: | Change type | What to update | |---|---| | Shared field (`name`, `description`, `version`, `author.name`, `license`, `keywords`) | Both manifests in the same edit pass | | CC-only (`displayName`, `author.url`) | `.claude-plugin/plugin.json` only | | Copilot-only (`author.email`, `skills`, `agents`, `hooks`, `mcpServers`, `category`, `tags`, `extensions`) | `plugin.json` only | Never update a shared field in one manifest without updating the other in the same pass. ### Step 3 — Announce and apply State which fields change and which files are affected. Then apply. For `version` changes not part of a release, bump both manifests in the same edit. ### Step 4 — Validate Re-run the validation checklist from CREATE flow Step 3 on both files. ## RELEASE flow ### Step 1 — Confirm version If the user has not stated the new SemVer version, ask: "What version are you releasing?" Do not proceed until you have the version. ### Step 2 — Bump version in both manifests Update `version` in both `plugin.json` and `.claude-plugin/plugin.json` in the same edit pass. Confirm they are identical after the edit. ### Step 3 — Validate Run: ```bash claude plugin validate plugins/ ``` Stop and report errors if validation fails. Do not proceed to tagging until validation passes. ### Step 4 — HITL gate State exactly: > "I will run `claude plugin tag --push` for plugin ``, which will create git tag `--v` and push it to remote. This is irreversible. Confirm?" Do not call the tool until the user explicitly confirms in the conversation. ### Step 5 — Tag and release After explicit confirmation, run from the repo root: ```bash claude plugin tag --push ``` Report the created tag name and confirm the push completed.