--- 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. Do not use when the request is about plugin content (skills, agents, hooks, MCP servers) or 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 - claude-code-subagents-docs - context7-github-en-copilot - 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` is placed in the Copilot manifest by convention; `author.url` is placed in the CC manifest by convention. Both fields are supported by both platforms — do not add them to the other manifest without a deliberate reason. - `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. - `claude plugin tag --push` requires a clean working tree and will fail if there are uncommitted changes. Commit or stash all changes 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 a CC platform field — Copilot has no equivalent. Do not add it to the Copilot manifest. - `skills`, `agents`, `hooks`, `mcpServers` are declared in the Copilot manifest by convention — Copilot requires explicit path declarations while CC auto-discovers content from the plugin root. Both platforms support these fields; omit them from the CC manifest by convention. - Agent files in a plugin's `agents/` directory silently ignore `hooks`, `mcpServers`, and `permissionMode` frontmatter fields. ## 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: `claude plugin validate plugins/`. ## 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 manifest fields** (`.claude-plugin/plugin.json` only): - `displayName` — human-readable name shown in plugin manager; capitalised form of `name` (CC platform field — no Copilot equivalent) - `author.url` — author URL (e.g. Gitea profile URL) (both platforms support this; placed here by convention) **Copilot manifest fields** (`plugin.json` only): - `author.email` — author email (both platforms support this; placed here by convention) - `skills`, `agents`, `hooks`, `mcpServers` — paths; defaults are already set by the script (CC auto-discovers these; Copilot requires explicit declarations) ### 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 platform field (`displayName`) | `.claude-plugin/plugin.json` only — Copilot has no equivalent field | | Copilot platform fields (`category`, `tags`, `extensions`) | `plugin.json` only — not in the CC manifest schema | | CC scaffold convention (`author.url`) | `.claude-plugin/plugin.json` only — both platforms support this field; it is placed here by convention | | Copilot scaffold convention (`author.email`, `skills`, `agents`, `hooks`, `mcpServers`) | `plugin.json` only by convention — CC also supports these fields; CC auto-discovers content from the plugin root rather than requiring explicit path declarations | Never update a shared field in one manifest without updating the other in the same pass. If the target field is not listed in the classification table, read `references/manifest-fields.md` for the full field list and platform support notes. ### 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/ ``` Use `--strict` to promote warnings to errors: `claude plugin validate --strict 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 To preview without tagging or pushing: `claude plugin tag --dry-run`. After explicit confirmation, run from the repo root: ```bash claude plugin tag --push ``` Report the created tag name and confirm the push completed.