Files
holocron/plugins/kyberforge/skills/plugin-author/SKILL.md
Defame1297 4d061bd199 feat(kyberforge): add plugin-author and marketplace-author skills
## 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
2026-06-28 10:45:03 +00:00

169 lines
6.7 KiB
Markdown

---
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 <name> <repo-root>
```
Examples:
```bash
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 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/<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:
```bash
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 --push` for 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:
```bash
claude plugin tag --push
```
Report the created tag name and confirm the push completed.