## Why Plugin and marketplace management had no governed authoring path. Creating or updating a plugin required knowing the dual-manifest convention, version parity rules, and directory skeleton by memory — nothing enforced consistency or guided the process. `/plugin-author` closes that gap by owning the full plugin scaffold lifecycle: create, update, rename, and release. `/marketplace-author` handles the marketplace-facing side: register, deregister, and update plugin entries in `marketplace.json`. ADR-0016 codifies the version parity convention (identical `version` in both `plugin.json` and `.claude-plugin/plugin.json`) that `/plugin-author` now enforces. The two plugin.json files in this repo are backfilled to comply (keys also sorted to pass the pretty-format-json hook). CONTEXT.md gains glossary entries for "plugin scaffold" and "version parity" so future agents have shared vocabulary for these concepts. ## Implementation Notes `/plugin-author` ships a `scripts/new-plugin.sh` scaffold script that generates the directory skeleton and both manifests in one shot; the skill calls the script rather than generating files ad hoc so the scaffold is reviewable and repeatable. Version parity is an invariant, not a suggestion — the skill will fail loudly on create/update if the two versions would diverge. ADR: docs/adr/0016-plugin-version-parity.md
6.7 KiB
name, description, allowed-tools, metadata
| name | description | allowed-tools | metadata | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| plugin-author | 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. | Bash Read Write Edit |
|
Gotchas
- Both manifests must carry identical
versionvalues — version parity is a hard invariant (ADR-0016). Never update version in one manifest without updating the other in the same edit pass. author.emailbelongs in the Copilot manifest (plugin.json);author.urlbelongs in the CC manifest (.claude-plugin/plugin.json). Do not swap them.claude plugin tag --pushis irreversible: it creates a git tag and pushes it to remote. Always present the HITL gate and wait for explicit confirmation before running it.namein 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 isplugin.jsonat the plugin root. displayNameis CC-only — do not add it to the Copilot manifest.skills,agents,hooks,mcpServersare 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 scripts/new-plugin.sh <name> <repo-root>
Examples:
bash scripts/new-plugin.sh my-tools /root/ai-development
bash scripts/new-plugin.sh data-tools .
The script creates under <repo-root>/plugins/<name>/:
plugin.json— Copilot manifest withFILL_IN_*placeholders.claude-plugin/plugin.json— CC manifest withFILL_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 providesversion— SemVer; defaults to1.0.0; must be identical in both manifestsauthor.name— author display namelicense— 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 ofnameauthor.url— author URL (e.g. Gitea profile URL)
Copilot-only fields (plugin.json only):
author.email— author emailskills,agents,hooks,mcpServers— paths; defaults are already set by the script
Step 3 — Validate
Check:
nameidentical in both manifests, kebab-case, no reserved prefixesdescriptionidentical in both manifests, non-emptyversionidentical in both manifests (version parity — ADR-0016)author.nameidentical in both manifestslicenseidentical in both manifests- No
FILL_IN_*placeholders remain displayNamepresent in CC manifest onlyauthor.urlin CC manifest,author.emailin Copilot manifest
UPDATE flow
Step 1 — Read both manifests
Read plugins/<name>/plugin.json and plugins/<name>/.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:
claude plugin validate plugins/<name>
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 --pushfor plugin<name>, which will create git tag<name>--v<version>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:
claude plugin tag --push
Report the created tag name and confirm the push completed.