## Why
The manifest-fields tables in both skills used imprecise labels ("CC-only",
"Copilot-only") that conflated two distinct reasons a field appears in only
one manifest: platform constraint (the other tool does not support the field
at all) versus repo convention (both tools support it, but the scaffold places
it in one manifest by design). This caused agents to treat convention
boundaries as hard platform constraints, producing unnecessary errors when
updating manifests for dual-tool repos.
Provenance was also incomplete: sources.md files were missing entries for
sources that had been consulted and were already contributing to SKILL.md
and manifest-fields.md content, making the evidence chain unverifiable.
## Implementation Notes
Field classification now uses three explicit categories — shared, platform
(one tool does not support the field), and convention (both tools support it;
scaffold places it in one manifest by design). The distinction matters because
convention fields may legitimately appear in the other manifest when there is
a deliberate reason; platform fields may not.
New gotchas added to plugin-author: agent files silently ignore hooks,
mcpServers, and permissionMode frontmatter; claude plugin tag --push requires
a clean working tree; --dry-run preview before tagging; --strict flag on
validate. New gotchas in marketplace-author: metadata object as Copilot CLI
canonical location for top-level fields; strict: false for dual-tool plugins;
sha takes precedence over ref for pinning; --strict flag on validate.
tests/ removed from plugin-author because new-plugin.sh has no branching
logic warranting a bats suite at this stage.
## Impact
Skill prompt changes only — no runtime code affected. Agents using these
skills will now correctly distinguish convention from constraint when deciding
which manifest to update for a given field.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8.3 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. Do not use when the request is about plugin content (skills, agents, hooks, MCP servers) or 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.emailis placed in the Copilot manifest by convention;author.urlis 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 --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.claude plugin tag --pushrequires a clean working tree and will fail if there are uncommitted changes. Commit or stash all changes 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 a CC platform field — Copilot has no equivalent. Do not add it to the Copilot manifest.skills,agents,hooks,mcpServersare 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 ignorehooks,mcpServers, andpermissionModefrontmatter 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/<name>.
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 manifest fields (.claude-plugin/plugin.json only):
displayName— human-readable name shown in plugin manager; capitalised form ofname(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:
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 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:
claude plugin validate plugins/<name>
Use --strict to promote warnings to errors: claude plugin validate --strict 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
To preview without tagging or pushing: claude plugin tag --dry-run.
After explicit confirmation, run from the repo root:
claude plugin tag --push
Report the created tag name and confirm the push completed.