universal-plugin 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/.cursor-plugin/plugin.json +1 -1
  4. package/LICENSE +21 -0
  5. package/dist/cli.mjs +76 -134
  6. package/package.json +3 -1
  7. package/plugin.json +1 -1
  8. package/readme.md +73 -42
  9. package/skills/doctor/README.md +42 -0
  10. package/skills/doctor/SKILL.md +123 -0
  11. package/skills/doctor/scripts/doctor.mjs +196 -0
  12. package/skills/init/README.md +57 -0
  13. package/skills/init/SKILL.md +200 -0
  14. package/skills/{plugin → init}/references/adopt.md +8 -4
  15. package/skills/init/references/create.md +111 -0
  16. package/skills/init/references/detection.md +62 -0
  17. package/skills/init/references/frontmatter.md +65 -0
  18. package/skills/init/references/standard.md +92 -0
  19. package/skills/init/references/update.md +31 -0
  20. package/skills/init/references/vendors/claude-code.md +44 -0
  21. package/skills/init/references/vendors/codex.md +48 -0
  22. package/skills/init/references/vendors/copilot-cli.md +45 -0
  23. package/skills/init/references/vendors/cursor.md +45 -0
  24. package/skills/init/scripts/init.mjs +11 -0
  25. package/skills/remove-plugin/README.md +38 -0
  26. package/skills/remove-plugin/SKILL.md +87 -0
  27. package/skills/version/README.md +36 -0
  28. package/skills/{plugin/references/version.md → version/SKILL.md} +26 -5
  29. package/skills/version/scripts/version.mjs +11 -0
  30. package/skills/plugin/README.md +0 -37
  31. package/skills/plugin/SKILL.md +0 -105
  32. package/skills/plugin/references/create.md +0 -163
  33. package/skills/plugin/references/delete.md +0 -23
  34. package/skills/plugin/references/inspect.md +0 -21
  35. package/skills/plugin/references/update.md +0 -26
  36. /package/skills/{plugin → init}/assets/templates/agent.md +0 -0
  37. /package/skills/{plugin → init}/assets/templates/command.md +0 -0
  38. /package/skills/{plugin → init}/assets/templates/hooks.json +0 -0
  39. /package/skills/{plugin → init}/assets/templates/plugin.json +0 -0
  40. /package/skills/{plugin → init}/assets/templates/setup-command.md +0 -0
  41. /package/skills/{plugin → init}/assets/templates/skill.md +0 -0
@@ -0,0 +1,111 @@
1
+ # Create a universal plugin
2
+
3
+ Scaffold a new plugin from one canonical `plugin.json` and derive a manifest per chosen vendor.
4
+
5
+ ## Step 1 — Gather plugin identity
6
+
7
+ Ask for what is missing. Every field lands at the canonical top level.
8
+
9
+ | Field | Required | Notes |
10
+ |-------|----------|-------|
11
+ | `name` | Yes | kebab-case, 1–64 chars, `a-z 0-9 - .` only |
12
+ | `description` | Recommended | one sentence; **required** when targeting Codex |
13
+ | `version` | If publishing | semver; **required** when targeting Codex |
14
+ | `author.name` | Recommended | person or org name |
15
+ | `homepage` | Optional | docs or landing page URL |
16
+ | `repository` | Optional | source repo URL |
17
+ | `license` | Optional | SPDX identifier, e.g. `MIT` |
18
+ | `keywords` | Optional | discovery tags; array of strings |
19
+
20
+ ## Step 2 — Choose vendor targets
21
+
22
+ Ask which runtimes to support; default to all four if the user is unsure. Each choice becomes an
23
+ entry in both `vendors` and `harnesses` under
24
+ `extensions["org.cyberuni.universal-plugin"]`.
25
+
26
+ | Vendor ID | Derived manifest | Read before enabling |
27
+ |-----------|------------------|----------------------|
28
+ | `claude-code` | `.claude-plugin/plugin.json` | [`vendors/claude-code.md`](./vendors/claude-code.md) |
29
+ | `cursor` | `.cursor-plugin/plugin.json` | [`vendors/cursor.md`](./vendors/cursor.md) |
30
+ | `codex` | `.codex-plugin/plugin.json` | [`vendors/codex.md`](./vendors/codex.md) |
31
+ | `copilot-cli` | none — reads root `plugin.json` | [`vendors/copilot-cli.md`](./vendors/copilot-cli.md) |
32
+
33
+ ## Step 3 — Choose components
34
+
35
+ Infer from context; ask only if ambiguous. [`standard.md`](./standard.md) has the component table and
36
+ the layout they go in; `governance show plugin-design` decides which component a given need calls
37
+ for. The universal minimum is `skills/<name>/SKILL.md` plus `.mcp.json`.
38
+
39
+ ## Step 4 — Scaffold
40
+
41
+ ```bash
42
+ node scripts/init.mjs --name <plugin-name> --vendor claude-code --vendor cursor --scaffold
43
+ ```
44
+
45
+ Resolve `scripts/init.mjs` against this skill's directory; it runs the CLI that shipped beside it.
46
+ `npx universal-plugin plugin init` is the fallback. Add `--npm` when an npm package ships the plugin,
47
+ which also wires that `package.json`'s `files` to carry the derived manifests.
48
+
49
+ `init` writes a minimal manifest — `$schema`, `name`, and the vendor list. Fill in the Step 1
50
+ metadata and the `harnesses` overrides by hand afterwards; [`standard.md`](./standard.md) shows the
51
+ finished shape.
52
+
53
+ Then create the component files from `../assets/templates/`:
54
+
55
+ | File to create | Template |
56
+ |----------------|----------|
57
+ | `skills/<name>/SKILL.md` | `assets/templates/skill.md` |
58
+ | `commands/<name>.md` | `assets/templates/command.md` |
59
+ | `agents/<name>.md` | `assets/templates/agent.md` |
60
+ | `hooks/hooks.json` | `assets/templates/hooks.json` |
61
+ | `commands/setup.md` (only with `rules/`) | `assets/templates/setup-command.md` |
62
+
63
+ ## Step 5 — Fill in the harness overrides
64
+
65
+ Only fields one runtime understands go here; shared metadata stays at the top level. See each
66
+ `vendors/<vendor>.md` for what that vendor accepts, and note that a `copilot-cli` entry has no
67
+ delivery path at all.
68
+
69
+ ```json
70
+ "harnesses": {
71
+ "claude-code": {},
72
+ "cursor": { "publisher": "<org>", "category": "<category>", "tags": ["<tag>"] },
73
+ "codex": { "interface": { "displayName": "<Human Name>", "category": "<category>" } },
74
+ "copilot-cli": {}
75
+ }
76
+ ```
77
+
78
+ ## Step 6 — Audit the skills
79
+
80
+ Run the mechanical validator from the aced **improve-skill** skill:
81
+
82
+ ```bash
83
+ node "<path to aced improve-skill>/scripts/validate.mts" --path skills/<skill-name>
84
+ ```
85
+
86
+ Fix every CRITICAL finding, then invoke the **audit-skill** skill for the full review.
87
+ [`frontmatter.md`](./frontmatter.md) covers what has to hold across runtimes.
88
+
89
+ ## Step 7 — Build
90
+
91
+ ```bash
92
+ npx universal-plugin plugin build
93
+ ```
94
+
95
+ Useful flags: `--dry-run` to see the plan, `--verbose` for field-by-field decisions, `--vendor <id>`
96
+ for one target, `--clean` to delete derived manifests first.
97
+
98
+ Read the warnings. An unknown vendor id, an undeliverable Copilot override, and a failed Codex prompt
99
+ write all surface there rather than as errors.
100
+
101
+ ## Step 8 — Install locally to test
102
+
103
+ ```bash
104
+ ln -sf "$(pwd)" ~/.claude/plugins/local/<plugin-name> # Claude Code
105
+ ln -sf "$(pwd)" ~/.cursor/plugins/local/<plugin-name> # Cursor → Developer: Reload Window
106
+ ```
107
+
108
+ ## Next
109
+
110
+ Shipping it on npm → `migrate-plugin`. Listing it in a marketplace → `publish-plugin`. Releasing a
111
+ number → `/universal-plugin:version`.
@@ -0,0 +1,62 @@
1
+ # Detection
2
+
3
+ What to look for during the survey, and where each finding belongs.
4
+
5
+ ```bash
6
+ ls -d .claude-plugin .cursor-plugin .codex-plugin .github/plugin .plugin 2>/dev/null
7
+ test -f plugin.json && cat plugin.json
8
+ find . -name SKILL.md -not -path '*/node_modules/*' -not -path './.git/*'
9
+ ls .mcp.json .lsp.json hooks/ commands/ agents/ rules/ output-styles/ 2>/dev/null
10
+ ```
11
+
12
+ | What you find | What it means | Bucket |
13
+ | --- | --- | --- |
14
+ | root `plugin.json` with `$schema` on `agent-plugins.org` **and** an `extensions` object | already on the open standard | canonical |
15
+ | `.claude-plugin/`, `.cursor-plugin/`, `.codex-plugin/` manifest **below** a canonical root | build output | derived |
16
+ | a vendor manifest with **no** canonical root `plugin.json` | a vendor-specific plugin | adoptable |
17
+ | root `plugin.json` with neither `$schema` nor `extensions` | a legacy single-vendor manifest now sitting on the canonical path | adoptable |
18
+ | publicly-shipped skills and no manifest of any kind | skills shipped without a plugin | adoptable |
19
+ | `harnesses["copilot-cli"]` carrying fields | no delivery path — the canonical schema is closed | undeliverable |
20
+ | `.claude/skills/`, `.agents/skills/`, `.cursor/rules/` | the project's own tooling | not a plugin |
21
+ | `.github/plugin/plugin.json` | a path older builds wrote; shadowed by root and no longer generated | stale, safe to delete |
22
+
23
+ For every vendor manifest found, record its path and **every field it sets**. Adoption reproduces
24
+ all of it, and the Phase 5 diff is checked field by field.
25
+
26
+ ## Which skills count as public
27
+
28
+ Only a skill the project *distributes* belongs to a plugin.
29
+
30
+ | Location | Public? |
31
+ |----------|---------|
32
+ | `skills/<name>/SKILL.md` at the plugin root | Yes |
33
+ | `<package>/skills/<name>/SKILL.md` where `package.json` `files` ships it | Yes |
34
+ | `.claude/skills/`, `.agents/skills/`, `.cursor/rules/` | **No** — repo-private tooling |
35
+
36
+ If the only skills are in private locations, say nothing about adoption. A repository that configures
37
+ its own agents is not a plugin waiting to happen; `buddy-agent-harness:init` is the skill for that
38
+ side of the line.
39
+
40
+ ## Making the adoption offer
41
+
42
+ State what you found, what adoption buys, and let the user decline:
43
+
44
+ > This project has a Claude Code plugin manifest but no canonical `plugin.json`. I can convert it to
45
+ > the open Agent Plugins Specification, so one manifest drives Cursor, Codex, and Copilot CLI too —
46
+ > Claude Code keeps working exactly as it does now. Want me to?
47
+
48
+ Offer once. If the user declines, or their request was already something specific and unrelated
49
+ (inspecting status, removing manifests), drop it and do what they asked.
50
+
51
+ ## Choosing vendors
52
+
53
+ Ask which runtimes the plugin targets; default to all four when the user is unsure. Enabling a vendor
54
+ costs a derived manifest and nothing else — except Codex, which additionally requires `version` and
55
+ `description` on the canonical manifest and fails the build without them.
56
+
57
+ Enabling Copilot CLI writes no file at all. Say so, rather than letting the user read a missing
58
+ manifest as a broken build.
59
+
60
+ Detecting a vendor directory means there is configuration to reconcile. It does not by itself mean
61
+ the user wants that vendor maintained — say which vendors you are enabling and why, and let them
62
+ correct the part that is actually variable.
@@ -0,0 +1,65 @@
1
+ # Skill frontmatter across runtimes
2
+
3
+ A plugin's skills are the one component every runtime reads, so their frontmatter is where
4
+ cross-vendor behavior is won or lost. Each runtime parses the fields it knows and silently drops the
5
+ rest.
6
+
7
+ ## Required, everywhere
8
+
9
+ ```yaml
10
+ ---
11
+ name: release-checklist
12
+ description: Runs the release checklist. Use when cutting a release or publishing a package version.
13
+ ---
14
+ ```
15
+
16
+ - `name` — 1–64 characters, lowercase letters, digits, hyphens. **Match the parent directory name**;
17
+ Claude Code resolves the command from the directory and treats `name` as a label, so matching them
18
+ removes the discrepancy.
19
+ - `description` — say what the skill does *and* when to use it. This is the only text most runtimes
20
+ see when deciding whether to load it.
21
+
22
+ Two failures actually cost you the skill: a missing `description`, and YAML that does not parse. The
23
+ usual cause of the second is an unquoted colon — quote any description containing one.
24
+
25
+ ## `invocation-policy` — the field this build acts on
26
+
27
+ universal-plugin reads `invocation-policy` from each `SKILL.md` and projects it per vendor:
28
+
29
+ | Value | Meaning | What the build does |
30
+ | --- | --- | --- |
31
+ | `both` (default) | user- and model-invocable | nothing |
32
+ | `user` | explicit invocation only | writes `disable-model-invocation: true` into the skill's frontmatter |
33
+ | `model` | model-invocable only, not user-facing | writes `user-invocable: false`, and emits no Codex prompt |
34
+
35
+ Two consequences worth knowing before you run a build:
36
+
37
+ - **The build rewrites the authored `SKILL.md`** to carry those flags. That file is both source and
38
+ artifact for this one field. Expect it in the diff; it is not a stray edit.
39
+ - Any value other than `user`, `model`, or `both` **fails the build** rather than being ignored.
40
+
41
+ ## Which runtime understands which field
42
+
43
+ | Field | Recognized by |
44
+ | --- | --- |
45
+ | `name`, `description` | all |
46
+ | `license`, `metadata`, `compatibility` | accepted broadly, largely ignored |
47
+ | `allowed-tools` | most |
48
+ | `disable-model-invocation` | Claude Code, Cursor |
49
+ | `context: fork`, `agent:` | Claude Code only |
50
+ | `paths`, legacy `globs` | Cursor only |
51
+ | `model` | Copilot CLI only |
52
+ | `argument-hint`, `arguments` | Claude Code only |
53
+
54
+ `argument-hint` and `arguments` are the one group that fails loudly rather than quietly: claude.ai
55
+ uploads and the Skills API reject fields outside the standard set. A skill that takes arguments and
56
+ also ships through those paths cannot use them — and does not need to, because no runtime but Claude
57
+ Code substitutes anything anyway. Claude Code appends what the caller typed as `ARGUMENTS: <value>`
58
+ when the body has no `$ARGUMENTS`, so a body that says how to read the invocation works everywhere,
59
+ while a `$ARGUMENTS` placeholder resolves on one runtime and stays literal on the rest.
60
+
61
+ ## The rule that follows
62
+
63
+ Anything that must hold on every runtime belongs in the Markdown body, not only in a vendor-specific
64
+ field. The body is the one part every runtime reads. Treat vendor frontmatter as an optimization
65
+ layered on instructions that already work without it.
@@ -0,0 +1,92 @@
1
+ # The canonical baseline
2
+
3
+ What every universal plugin has, before any vendor-specific work.
4
+
5
+ ## The one authored file
6
+
7
+ Root `plugin.json`, on the Agent Plugins Specification v1.0.0 schema. Everything else a vendor reads
8
+ is derived from it.
9
+
10
+ ```json
11
+ {
12
+ "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
13
+ "name": "my-plugin",
14
+ "version": "1.0.0",
15
+ "description": "One sentence saying what the plugin does.",
16
+ "author": { "name": "<author>" },
17
+ "extensions": {
18
+ "org.cyberuni.universal-plugin": {
19
+ "vendors": ["claude-code", "cursor", "codex", "copilot-cli"],
20
+ "skills": "./skills/",
21
+ "harnesses": {
22
+ "claude-code": {},
23
+ "cursor": {},
24
+ "codex": {},
25
+ "copilot-cli": {}
26
+ }
27
+ }
28
+ }
29
+ }
30
+ ```
31
+
32
+ The spec's top level holds the shared metadata. Everything universal-plugin needs to run a build
33
+ lives under one namespaced key, `extensions["org.cyberuni.universal-plugin"]`:
34
+
35
+ | Key | Holds |
36
+ | --- | --- |
37
+ | `vendors` | the build targets. When absent, the `harnesses` keys are the targets |
38
+ | `harnesses` | per-vendor overrides, keyed by vendor id. `{}` opts in with no overrides |
39
+ | `packagePath` | the npm package whose `package.json` carries the same version |
40
+ | component paths (`skills`, `commands`, `agents`, `hooks`, …) | where each component lives |
41
+
42
+ `vendors` and `harnesses` are separate on purpose: `vendors` says what to build, `harnesses` says
43
+ what each build gets. A vendor listed in `vendors` with no `harnesses` entry still builds; a
44
+ `harnesses` entry with no `vendors` list builds only while `vendors` is absent.
45
+
46
+ ## Directory layout
47
+
48
+ ```
49
+ <plugin-root>/
50
+ ├── plugin.json ← canonical definition (source of truth)
51
+ ├── skills/<name>/SKILL.md
52
+ ├── commands/<name>.md
53
+ ├── agents/<name>.md
54
+ ├── rules/<name>.mdc (Cursor-only guidance)
55
+ ├── hooks/hooks.json
56
+ ├── .mcp.json
57
+ └── README.md
58
+ ```
59
+
60
+ `plugin init --scaffold` creates the standard `skills/`, `agents/`, `governances/`, and `commands/`
61
+ directories. Create the rest only when the plugin has content for them.
62
+
63
+ ## Components
64
+
65
+ | Component | Field | Directory | Reaches |
66
+ |-----------|-------|-----------|---------|
67
+ | Skills | `skills` | `skills/<name>/SKILL.md` | every vendor |
68
+ | MCP servers | `mcpServers` | `.mcp.json` | every vendor |
69
+ | Commands | `commands` | `commands/<name>.md` | Claude Code, Cursor, Copilot CLI |
70
+ | Agents | `agents` | `agents/<name>.md` | Claude Code, Cursor, Copilot CLI |
71
+ | Hooks | `hooks` | `hooks/hooks.json` | partial — event names differ by case, and the build does not translate them |
72
+ | LSP servers | `lspServers` | `.lsp.json` | Claude Code, Cursor |
73
+ | Rules | `rules` | `rules/<name>.mdc` | Cursor only |
74
+ | Output styles | `outputStyles` | `output-styles/` | Claude Code only |
75
+
76
+ The universal minimum — reaching every runtime with no vendor manifest at all — is
77
+ `skills/<name>/SKILL.md` plus `.mcp.json`. Reach for a narrower component only when the plugin needs
78
+ what only that component does; `governance show plugin-design` is the authority on that choice.
79
+
80
+ ## Constraints
81
+
82
+ - **Never hand-edit a derived manifest.** `plugin build` owns `.claude-plugin/plugin.json` and its
83
+ siblings; an edit there survives until the next build and no longer.
84
+ - **Never hand-edit a `version` field.** That move belongs to `/universal-plugin:version`.
85
+ - **The canonical schema is closed.** A vendor-only field cannot be added at the top level; it goes
86
+ under that vendor's `harnesses` entry or nowhere.
87
+ - Root `plugin.json` is not a build artifact. It is both the source of truth and the file Copilot CLI
88
+ reads, so deleting it takes out both.
89
+
90
+ ## Next
91
+
92
+ Read only the `vendors/<vendor>.md` files for the runtimes being enabled. `SKILL.md` has the table.
@@ -0,0 +1,31 @@
1
+ # Update a universal plugin
2
+
3
+ Change which vendors or components an existing plugin declares. Every path ends with a rebuild:
4
+
5
+ ```bash
6
+ npx universal-plugin plugin build
7
+ ```
8
+
9
+ ## Add a vendor
10
+
11
+ 1. Add the vendor id to `extensions["org.cyberuni.universal-plugin"].vendors` in root
12
+ `plugin.json`, and add its key to `extensions["org.cyberuni.universal-plugin"].harnesses`.
13
+ 2. Populate vendor-specific fields — see that vendor's [`vendors/<vendor>.md`](./vendors/).
14
+ 3. If the vendor requires extra fields (`codex`: `version`, `description`), add them to the canonical
15
+ top level first — the build fails loudly without them.
16
+ 4. Rebuild for the new vendor: `plugin build --vendor <id>`.
17
+
18
+ ## Remove a vendor
19
+
20
+ 1. Remove the vendor id from `extensions["org.cyberuni.universal-plugin"].vendors` and its key from
21
+ `harnesses`.
22
+ 2. Delete the generated manifest at its output path. `copilot-cli` has none — removing it is a
23
+ manifest edit and nothing else.
24
+
25
+ ## Add or remove a component
26
+
27
+ 1. Add or remove the component field under `extensions["org.cyberuni.universal-plugin"]` in root
28
+ `plugin.json` (e.g. `"commands": "./commands/"`). [`standard.md`](./standard.md) has the component
29
+ table and which runtimes each one reaches.
30
+ 2. Scaffold or delete the corresponding files.
31
+ 3. Rebuild to regenerate all vendor manifests.
@@ -0,0 +1,44 @@
1
+ # Claude Code
2
+
3
+ Reads `.claude-plugin/plugin.json`. **The build derives it** — never hand-edit it.
4
+
5
+ ```bash
6
+ npx universal-plugin plugin build --vendor claude-code
7
+ ```
8
+
9
+ ## What lands in the derived manifest
10
+
11
+ The shared metadata from the canonical top level, plus the component paths, plus whatever
12
+ `extensions["org.cyberuni.universal-plugin"].harnesses["claude-code"]` sets. `$schema`, `extensions`,
13
+ `vendors`, `packagePath`, and `harnesses` are universal-plugin's own orchestration — they never
14
+ appear in a vendor manifest.
15
+
16
+ An empty `"claude-code": {}` is the normal case: it opts into the build with no overrides.
17
+
18
+ ## Extra requirements
19
+
20
+ None beyond `name`. Claude Code loads a manifest that carries only the shared metadata.
21
+
22
+ ## Skills
23
+
24
+ Claude Code reads the skills the manifest's `skills` path names. The build additionally rewrites each
25
+ `SKILL.md`'s frontmatter when the skill declares `invocation-policy` — `disable-model-invocation:
26
+ true` for `user`, `user-invocable: false` for `model`. See [`../frontmatter.md`](../frontmatter.md).
27
+
28
+ ## Hooks
29
+
30
+ Claude Code hook events are **PascalCase** (`SessionStart`, `PreToolUse`, `PostToolUse`, `Stop`,
31
+ `UserPromptSubmit`). Cursor and Copilot CLI use camelCase; Codex is PascalCase like Claude Code.
32
+
33
+ **The build does not translate event names.** It copies the `hooks` path through to every derived
34
+ manifest as declared, so one `hooks/hooks.json` cannot currently satisfy both casings. Author hooks
35
+ for the runtimes that share a casing, and say plainly which runtimes a hooks block does not reach
36
+ rather than implying portability the build does not deliver.
37
+
38
+ Source: `.research/hook-event-survey/conclusion.md` (June 2026) — re-verify against vendor docs
39
+ before relying on it.
40
+
41
+ ## Leave alone
42
+
43
+ Output styles are Claude Code-only, and hook blocks in `.claude/settings.json` are settings, not
44
+ plugin content. Report them; do not convert them.
@@ -0,0 +1,48 @@
1
+ # Codex
2
+
3
+ Reads `.codex-plugin/plugin.json`. **The build derives it** — never hand-edit it.
4
+
5
+ ```bash
6
+ npx universal-plugin plugin build --vendor codex
7
+ ```
8
+
9
+ ## Extra requirements — the build enforces these
10
+
11
+ Targeting Codex requires `version` **and** `description` on the canonical manifest. Without either,
12
+ `plugin build` fails loudly and writes nothing:
13
+
14
+ ```
15
+ plugin.json validation failed:
16
+ - description is required when targeting codex
17
+ - version is required when targeting codex
18
+ ```
19
+
20
+ The check is scoped to the vendors actually being built, so a Codex block that is not a selected
21
+ target never blocks a build of the others.
22
+
23
+ ## Vendor-specific fields
24
+
25
+ Codex's presentation metadata goes under its `harnesses` entry:
26
+
27
+ ```json
28
+ "codex": {
29
+ "interface": {
30
+ "displayName": "<Human Name>",
31
+ "category": "<category>"
32
+ }
33
+ }
34
+ ```
35
+
36
+ ## Skills
37
+
38
+ For every skill that is not `invocation-policy: model`, the build also writes
39
+ `~/.codex/prompts/<name>.md` — the skill body, as a Codex prompt.
40
+
41
+ Two things follow. It writes **outside the repository**, into the current machine's home directory,
42
+ so it is not part of the plugin's tracked output and does not travel with a clone. And it is
43
+ **best-effort**: a failure there becomes a build warning, not a failed build. Read the warnings.
44
+
45
+ ## Hooks
46
+
47
+ Codex hook events are **PascalCase**, like Claude Code's. The build does not translate event names —
48
+ see [`claude-code.md`](./claude-code.md).
@@ -0,0 +1,45 @@
1
+ # GitHub Copilot CLI
2
+
3
+ Reads the **canonical root `plugin.json` directly**. The build derives nothing for it and writes no
4
+ file — `plugin build` reports it with status `canonical`, which is success, not a skipped target.
5
+
6
+ ## Why nothing is derived
7
+
8
+ Copilot CLI searches four paths and takes the first match:
9
+
10
+ ```
11
+ .plugin/plugin.json → plugin.json → .github/plugin/plugin.json → .claude-plugin/plugin.json
12
+ ```
13
+
14
+ Root `plugin.json` — the canonical manifest — is second, so it always shadows the two below it. It
15
+ has consumed Open Plugin Spec v1 manifests since v1.0.74, so it already serves the canonical manifest
16
+ as-is.
17
+
18
+ Earlier builds wrote `.github/plugin/plugin.json`. That path loses to root by construction and was
19
+ never read; a leftover copy is stale and safe to delete.
20
+
21
+ ## Vendor-specific fields cannot be delivered
22
+
23
+ A `harnesses["copilot-cli"]` entry has nowhere to go. The canonical schema is closed
24
+ (`additionalProperties: false`), so a Copilot-only field cannot ride along in root, and there is no
25
+ derived file to put it in. The build warns:
26
+
27
+ ```
28
+ harnesses.copilot-cli sets category, tags, but copilot-cli reads the canonical plugin.json
29
+ directly — these fields are not delivered
30
+ ```
31
+
32
+ Treat that warning as a decision to make, not noise: either the field belongs to a vendor that has a
33
+ derived manifest, or it does not ship. Do not invent a path for it.
34
+
35
+ ## Do not
36
+
37
+ - **Do not delete root `plugin.json` to "clean up" a Copilot target.** It is the source of truth and
38
+ the Copilot manifest at once.
39
+ - Do not write `.plugin/plugin.json`. It outranks root, so it would silently shadow the canonical
40
+ manifest with a copy nothing regenerates.
41
+
42
+ ## Hooks
43
+
44
+ Copilot CLI hook events are **camelCase**. The build does not translate event names — see
45
+ [`claude-code.md`](./claude-code.md).
@@ -0,0 +1,45 @@
1
+ # Cursor
2
+
3
+ Reads `.cursor-plugin/plugin.json`. **The build derives it** — never hand-edit it.
4
+
5
+ ```bash
6
+ npx universal-plugin plugin build --vendor cursor
7
+ ```
8
+
9
+ ## Extra requirements
10
+
11
+ None beyond `name`.
12
+
13
+ ## Vendor-specific fields
14
+
15
+ Cursor's catalog metadata goes under its `harnesses` entry, not at the canonical top level:
16
+
17
+ ```json
18
+ "cursor": {
19
+ "publisher": "<org>",
20
+ "category": "<category>",
21
+ "tags": ["<tag>"]
22
+ }
23
+ ```
24
+
25
+ ## Skills
26
+
27
+ Cursor reads `SKILL.md` straight from the path the manifest's `skills` field names, and lets the user
28
+ invoke a skill by typing `/` and searching for it. **The build derives no per-skill artifact for
29
+ Cursor** — a mirrored `.cursor/commands/*.md` would be a second copy of the same body. Explicit-only
30
+ invocation is expressed natively through `disable-model-invocation`, which the build already writes
31
+ into the shared `SKILL.md`.
32
+
33
+ ## Rules are Cursor-only
34
+
35
+ `rules/<name>.mdc` reaches Cursor and nothing else. Reach for a rule only when the plugin genuinely
36
+ needs always-on guidance in Cursor; anything a task can load on demand belongs in a skill, where every
37
+ runtime sees it. `governance show plugin-design` is the authority on that call.
38
+
39
+ `.mdc` and `.md` are not interchangeable, and path-scoping has no equivalent in the other runtimes —
40
+ never generate rules from a skill or a skill from a rule.
41
+
42
+ ## Hooks
43
+
44
+ Cursor hook events are **camelCase** (`sessionStart`). The build does not translate event names — see
45
+ [`claude-code.md`](./claude-code.md).
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ // Runs `universal-plugin plugin init` from the CLI that ships beside this skill, so a scaffold
3
+ // never depends on a network fetch or on which version `npx` happens to resolve.
4
+ import { dirname, join } from 'node:path'
5
+ import { fileURLToPath } from 'node:url'
6
+
7
+ // <package>/skills/<skill>/scripts/init.mjs: four levels up is the package root.
8
+ const packageRoot = dirname(dirname(dirname(dirname(fileURLToPath(import.meta.url)))))
9
+
10
+ process.argv.splice(2, 0, 'plugin', 'init')
11
+ await import(join(packageRoot, 'bin', 'universal-plugin.mjs'))
@@ -0,0 +1,38 @@
1
+ # remove-plugin skill
2
+
3
+ Remove a universal plugin's artifacts — from cleaning a build output to taking the plugin out of a
4
+ project entirely.
5
+
6
+ ## Three removals, not one
7
+
8
+ They are not equally reversible, and the skill establishes which one is being asked for before
9
+ deleting anything:
10
+
11
+ | Ask | Removes | Reversible by |
12
+ | --- | --- | --- |
13
+ | clean the build output | derived vendor manifests | `plugin build` |
14
+ | drop a vendor | one manifest, and its declaration | re-adding the vendor, then a build |
15
+ | remove the plugin | the canonical manifest and every component | nothing |
16
+
17
+ Only the last is irreversible, and only it needs a confirmation.
18
+
19
+ ## What it will not do
20
+
21
+ Root `plugin.json` is never deleted as cleanup. It is the canonical source of truth *and* the
22
+ manifest GitHub Copilot CLI reads, so removing it takes out the source and a live target at once.
23
+
24
+ Dropping a vendor is a manifest edit first: deleting only the file leaves the vendor declared, and
25
+ the next build writes it straight back. That edit routes to `init`.
26
+
27
+ Deleting a published plugin's source does not unpublish it. The skill says so rather than implying
28
+ the removal reached consumers.
29
+
30
+ ## Why there is no delete script
31
+
32
+ `plugin build --clean` already removes exactly what the manifest declares and nothing it does not.
33
+ Anything beyond that is a judgment call about authored content, which is the part that should stay
34
+ in front of a human.
35
+
36
+ ## References
37
+
38
+ - [Spec](https://github.com/cyberuni/universal-plugin/blob/main/packages/universal-plugin/.agents/spec/spec.md)