universal-plugin 0.2.1 → 0.3.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 (38) hide show
  1. package/.claude-plugin/plugin.json +15 -0
  2. package/.codex-plugin/plugin.json +14 -0
  3. package/.cursor-plugin/plugin.json +14 -0
  4. package/agents/agentskills-specialist.md +132 -0
  5. package/bin/upx.mjs +6 -0
  6. package/dist/cli.mjs +1330 -255
  7. package/dist/run.mjs +271 -0
  8. package/governances/plugin-design.md +22 -17
  9. package/governances/slash-invocation.md +30 -0
  10. package/package.json +14 -5
  11. package/plugin.json +18 -0
  12. package/readme.md +37 -3
  13. package/skills/adopt-upx/README.md +38 -0
  14. package/skills/adopt-upx/SKILL.md +120 -0
  15. package/skills/adopt-upx/scripts/rewrite-upx.mjs +168 -0
  16. package/skills/migrate-plugin/SKILL.md +106 -0
  17. package/skills/migrate-plugin/evals/evals.json +11 -0
  18. package/skills/migrate-plugin/evals/trigger-queries.json +35 -0
  19. package/skills/plugin/README.md +37 -0
  20. package/skills/plugin/SKILL.md +105 -0
  21. package/skills/plugin/assets/templates/agent.md +7 -0
  22. package/skills/plugin/assets/templates/command.md +9 -0
  23. package/skills/plugin/assets/templates/hooks.json +9 -0
  24. package/skills/plugin/assets/templates/plugin.json +19 -0
  25. package/skills/plugin/assets/templates/setup-command.md +15 -0
  26. package/skills/plugin/assets/templates/skill.md +15 -0
  27. package/skills/plugin/references/adopt.md +114 -0
  28. package/skills/plugin/references/create.md +163 -0
  29. package/skills/plugin/references/delete.md +23 -0
  30. package/skills/plugin/references/inspect.md +21 -0
  31. package/skills/plugin/references/update.md +26 -0
  32. package/skills/plugin/references/version.md +97 -0
  33. package/skills/publish-plugin/SKILL.md +246 -0
  34. package/skills/publish-plugin/evals/evals.json +23 -0
  35. package/skills/publish-plugin/references/vendor-requirements.md +38 -0
  36. package/skills/upgrade-plugin/README.md +23 -0
  37. package/skills/upgrade-plugin/SKILL.md +86 -0
  38. package/LICENSE +0 -21
@@ -0,0 +1,120 @@
1
+ ---
2
+ name: adopt-upx
3
+ description: Use this skill when the user wants to make their skills use upx — the fast local-first package runner shipped by universal-plugin. Trigger on phrases like "make my skills use upx", "adopt the upx runner", "speed up npx calls", "switch to upx", or "rewrite npx pins to upx". Rewrites `npx <pkg>@<version>` references to a caret range on `upx` (`^<major>`, or `^0.<minor>` for a 0.x pin) across one skill, a named set, or every skill in the project.
4
+ ---
5
+
6
+ # Adopt upx
7
+
8
+ Rewrites `npx <pkg>@<version>` references inside `SKILL.md` files to a caret range on `upx` — the
9
+ fast local-first runner shipped by `universal-plugin` (see the package
10
+ [`readme.md`](../../readme.md#upx--the-fast-package-runner) for the `upx` contract).
11
+
12
+ ## When to use
13
+
14
+ The user wants their project's skills to shell out via `upx` instead of `npx`, for the ~10× speed
15
+ win on repeated calls. This is an opt-in migration, not a default — see Tradeoff below before
16
+ running it broadly.
17
+
18
+ ## Prerequisites
19
+
20
+ Install the runner:
21
+
22
+ ```bash
23
+ npm i -g universal-plugin
24
+ ```
25
+
26
+ This puts the `upx` bin on PATH. Verify:
27
+
28
+ ```bash
29
+ upx --help
30
+ ```
31
+
32
+ If `upx` isn't found after install, stop and fix PATH before rewriting anything — a rewritten
33
+ skill with no `upx` on PATH breaks for that user (see Tradeoff).
34
+
35
+ ## Rewrite rule
36
+
37
+ `npx <pkg>@<version>` → `upx <pkg>@^<major>` — a caret range on the major version, not the exact
38
+ pin. That's the point: one global `upx` install then satisfies every skill's call to that CLI at
39
+ that major, instead of `npx` re-resolving+spawning per exact version every time.
40
+
41
+ **`0.x` versions are special.** Under semver a `0.x` minor bump is a breaking change, so `^0`
42
+ (= `>=0.0.0 <1.0.0`) is far too loose — it would match across incompatible `0.x` lines. A `0.x` pin
43
+ is rewritten to `upx <pkg>@^0.<minor>` instead (e.g. `pkg@0.2.3` → `upx pkg@^0.2`, matching only the
44
+ `0.2.x` line). `^<major>` applies only to `>=1.0.0`.
45
+
46
+ Left alone (never rewritten):
47
+
48
+ - **Non-semver placeholders** — `npx universal-plugin@<version>` (angle-bracket doc placeholders
49
+ aren't real pins)
50
+ - **Dist-tags** — `npx pkg@next`, `npx pkg@latest` (not a range `upx` can match against an
51
+ installed version; these already go straight to `npx` inside `upx` itself on a miss)
52
+ - **Already-`upx` references** — nothing to do
53
+ - **Any skill marked `pin-exempt: true`** in its frontmatter — its version strings are
54
+ documentation/illustration, not real invocations. This mirrors how `plugin bundle` treats
55
+ pin-exempt skills; `upgrade-plugin` is a live example.
56
+
57
+ ## Choose scope
58
+
59
+ Ask the user (or infer from their request) which of the three scopes applies:
60
+
61
+ | Scope | How to invoke |
62
+ |---|---|
63
+ | **A specific skill** | Pass its path: `skills/my-skill` (dir) or `skills/my-skill/SKILL.md` |
64
+ | **A named set** | Pass multiple paths and/or a glob: `skills/a skills/b "skills/foo-*"` |
65
+ | **All skills in the project** | Pass `--all` — walks the whole project for every `SKILL.md`, skipping `node_modules`, `.git`, `dist`, `build`, `.turbo` |
66
+
67
+ ## Run the rewrite
68
+
69
+ The mechanism is `scripts/rewrite-upx.mjs` in this skill directory — run it directly, don't
70
+ hand-edit files:
71
+
72
+ ```bash
73
+ # One skill
74
+ node "<this skill's dir>/scripts/rewrite-upx.mjs" skills/my-skill
75
+
76
+ # A named set (paths and/or globs)
77
+ node "<this skill's dir>/scripts/rewrite-upx.mjs" skills/my-skill skills/other-skill "skills/team-*"
78
+
79
+ # Every skill in the project
80
+ node "<this skill's dir>/scripts/rewrite-upx.mjs" --all
81
+ ```
82
+
83
+ Preview without writing:
84
+
85
+ ```bash
86
+ node "<this skill's dir>/scripts/rewrite-upx.mjs" --all --dry-run
87
+ ```
88
+
89
+ The script reports, per file, how many references it rewrote and which skills it skipped as
90
+ pin-exempt, plus a final tally. It is **idempotent** — re-running over already-rewritten files is
91
+ a no-op (there's no `npx` left to match), so it's safe to run again after adding new skills.
92
+
93
+ ## Tradeoff — say this out loud to the user
94
+
95
+ A skill rewritten to `upx` now depends on the `upx` bin being on that environment's PATH.
96
+ `npx` always ships with npm — every Node environment has it. `upx` does not — it only exists after
97
+ `npm i -g universal-plugin`. So this is a deliberate opt-in for environments where
98
+ `universal-plugin` is installed globally, not a safe-by-default swap.
99
+
100
+ Mitigating factor: `upx` itself falls back to plain `npx` on a miss (no local/global install
101
+ satisfies the range) — but that fallback only fires if the `upx` bin is present to run in the
102
+ first place. If `upx` isn't on PATH at all, the shell fails to find the command before `upx`'s own
103
+ fallback logic ever gets a chance to run.
104
+
105
+ ## Verify
106
+
107
+ 1. Re-run the script over the same scope — it should report `0 file(s) rewritten` (idempotent).
108
+ 2. Spot-check a rewritten skill: the pin should read `upx <pkg>@^<major>` (or `upx <pkg>@^0.<minor>`
109
+ for a 0.x package), not a concrete version.
110
+ 3. Confirm any pin-exempt skills (e.g. `upgrade-plugin`) were skipped, not rewritten.
111
+ 4. If the project has a skill validator (`validate-skill` / `improve-skill`), run it over each
112
+ touched skill to confirm the rewrite didn't break frontmatter or Markdown structure.
113
+
114
+ ## Commit
115
+
116
+ Follow project commit discipline — one commit for this rewrite:
117
+
118
+ ```text
119
+ chore(skills): adopt upx runner for <scope>
120
+ ```
@@ -0,0 +1,168 @@
1
+ #!/usr/bin/env node
2
+ // Rewrites `npx <pkg>@<version>` references inside SKILL.md files to the fast local-first
3
+ // `upx <pkg>@^<major>` form. See ../SKILL.md for the full contract; this is the mechanism.
4
+ //
5
+ // Usage:
6
+ // node rewrite-upx.mjs --all # every SKILL.md under cwd
7
+ // node rewrite-upx.mjs skills/my-skill # one skill (dir or SKILL.md path)
8
+ // node rewrite-upx.mjs skills/a skills/b/SKILL.md skills/c-* # a named set (paths + globs)
9
+ // node rewrite-upx.mjs --all --dry-run # report only, write nothing
10
+ //
11
+ // Rewrite rule: `npx <pkg>@<concrete-semver>` -> `upx <pkg>@^<major>` (caret on the major, so
12
+ // one global `upx` install serves many pinned callers). A `0.x` pin instead becomes
13
+ // `upx <pkg>@^0.<minor>` — under semver a `0.x` minor bump is breaking, so `^0` would be far too
14
+ // loose. Left alone:
15
+ // - `@<placeholder>` (non-semver, e.g. `@<version>`) — not a real pin
16
+ // - dist-tags (e.g. `@next`, `@latest`) — upx can't range-match these, they go to npx anyway
17
+ // - any occurrence already using `upx` — nothing to rewrite
18
+ // - any SKILL.md whose frontmatter declares `pin-exempt: true` — its versions are illustration
19
+ // (the same convention the plugin bundler uses)
20
+ //
21
+ // Idempotent: a second run finds no more `npx <pkg>@<semver>` occurrences to rewrite.
22
+
23
+ import { readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'
24
+ import { join, resolve } from 'node:path'
25
+
26
+ const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.turbo'])
27
+
28
+ const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---/
29
+ const PIN_EXEMPT_PATTERN = /(^|\n)\s*pin-exempt:\s*true\s*(\n|$)/
30
+
31
+ // Matches `npx <pkg>@<version>` — mirrors the pattern `plugin bundle` uses for pin rewriting,
32
+ // but only for the `npx` runner word (upx refs are already fast, nothing to do). The package
33
+ // class includes `@` and `/` so a scoped package (`@acme/cli@1.2.3`) matches; greedy matching
34
+ // backtracks to the LAST `@`, which separates the version.
35
+ const NPX_REF_PATTERN = /\bnpx(\s+(?:--yes\s+|-y\s+)?)([@a-z0-9/._-]+)@([^\s`'")]+)/g
36
+
37
+ const SEMVER_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/
38
+
39
+ function isPinExempt(content) {
40
+ const match = FRONTMATTER_PATTERN.exec(content)
41
+ if (!match) return false
42
+ return PIN_EXEMPT_PATTERN.test(match[1])
43
+ }
44
+
45
+ // `>=1.0.0` → `^<major>` (any release in that major). A `0.x` version is special: under semver a
46
+ // `0.x` minor bump is a breaking change, so `^0` (= `>=0.0.0 <1.0.0`) is far too loose — pin the
47
+ // minor instead with `^0.<minor>` (= that `0.<minor>.x` line only).
48
+ function caretRange(version) {
49
+ const [major, minor] = version.split('.')
50
+ return major === '0' ? `^0.${minor}` : `^${major}`
51
+ }
52
+
53
+ function rewriteContent(content) {
54
+ let changed = 0
55
+ const next = content.replace(NPX_REF_PATTERN, (whole, ws, pkg, version) => {
56
+ if (!SEMVER_PATTERN.test(version)) return whole // placeholder or dist-tag — leave alone
57
+ changed++
58
+ return `upx${ws}${pkg}@${caretRange(version)}`
59
+ })
60
+ return { next, changed }
61
+ }
62
+
63
+ function findSkillFiles(root) {
64
+ const out = []
65
+ const st = statSync(root, { throwIfNoEntry: false })
66
+ if (!st) return out
67
+ if (st.isFile()) {
68
+ if (root.endsWith('SKILL.md')) out.push(root)
69
+ return out
70
+ }
71
+ if (st.isDirectory()) {
72
+ const direct = join(root, 'SKILL.md')
73
+ if (statSync(direct, { throwIfNoEntry: false })?.isFile()) {
74
+ out.push(direct)
75
+ return out // a skill dir given directly — don't also recurse into it
76
+ }
77
+ for (const entry of readdirSync(root, { withFileTypes: true })) {
78
+ if (entry.isDirectory()) {
79
+ if (SKIP_DIRS.has(entry.name)) continue
80
+ out.push(...findSkillFiles(join(root, entry.name)))
81
+ }
82
+ }
83
+ }
84
+ return out
85
+ }
86
+
87
+ // Minimal glob: only `*` within a single path segment (no `**`). Enough for named-set patterns
88
+ // like `skills/foo-*` or `skills/*/SKILL.md`.
89
+ function expandGlob(pattern) {
90
+ if (!pattern.includes('*')) return null
91
+ const segments = pattern.split('/')
92
+ let bases = ['.']
93
+ for (const seg of segments) {
94
+ if (!seg.includes('*')) {
95
+ bases = bases.map((b) => join(b, seg))
96
+ continue
97
+ }
98
+ const re = new RegExp('^' + seg.split('*').map(escapeRegExp).join('.*') + '$')
99
+ const next = []
100
+ for (const b of bases) {
101
+ const st = statSync(b, { throwIfNoEntry: false })
102
+ if (!st?.isDirectory()) continue
103
+ for (const entry of readdirSync(b)) {
104
+ if (re.test(entry)) next.push(join(b, entry))
105
+ }
106
+ }
107
+ bases = next
108
+ }
109
+ return bases
110
+ }
111
+
112
+ function escapeRegExp(value) {
113
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
114
+ }
115
+
116
+ function resolveTargets(args) {
117
+ const all = args.includes('--all')
118
+ const dryRun = args.includes('--dry-run')
119
+ const positional = args.filter((a) => a !== '--all' && a !== '--dry-run')
120
+
121
+ if (all) return { files: findSkillFiles('.'), dryRun }
122
+
123
+ const files = []
124
+ for (const arg of positional) {
125
+ const globbed = expandGlob(arg)
126
+ if (globbed) {
127
+ for (const g of globbed) files.push(...findSkillFiles(g))
128
+ } else {
129
+ files.push(...findSkillFiles(arg))
130
+ }
131
+ }
132
+ return { files: [...new Set(files)], dryRun }
133
+ }
134
+
135
+ function main() {
136
+ const args = process.argv.slice(2)
137
+ if (args.length === 0) {
138
+ console.error('usage: rewrite-upx.mjs (--all | <path-or-glob>...) [--dry-run]')
139
+ process.exit(1)
140
+ }
141
+
142
+ const { files, dryRun } = resolveTargets(args)
143
+ if (files.length === 0) {
144
+ console.error('no SKILL.md files matched — nothing to do')
145
+ process.exit(0)
146
+ }
147
+
148
+ let touched = 0
149
+ let skippedExempt = 0
150
+ for (const file of files) {
151
+ const abs = resolve(file)
152
+ const content = readFileSync(abs, 'utf8')
153
+ if (isPinExempt(content)) {
154
+ skippedExempt++
155
+ console.log(`skip (pin-exempt): ${file}`)
156
+ continue
157
+ }
158
+ const { next, changed } = rewriteContent(content)
159
+ if (changed === 0) continue
160
+ touched++
161
+ console.log(`${dryRun ? '[dry-run] ' : ''}rewrite (${changed}): ${file}`)
162
+ if (!dryRun) writeFileSync(abs, next, 'utf8')
163
+ }
164
+
165
+ console.log(`\n${touched} file(s) rewritten, ${skippedExempt} skipped (pin-exempt), ${files.length} scanned.`)
166
+ }
167
+
168
+ main()
@@ -0,0 +1,106 @@
1
+ ---
2
+ name: migrate-plugin
3
+ description: "Move a repository-root universal agent plugin into its npm package so the package distributes its manifest, vendor manifests, skills, and agents. Use this skill when packaging an existing plugin for npm, relocating a top-level plugin into a package, or fixing a package that omits plugin assets, even if the user says only 'ship this plugin through npm' or 'move the plugin into the package.'"
4
+ ---
5
+
6
+ # Migrate Universal Plugin to npm
7
+
8
+ ## Scope
9
+
10
+ Move one existing universal plugin from a repository root into its owning npm
11
+ package. The package becomes the plugin root and must contain every runtime
12
+ artifact it needs after installation.
13
+
14
+ This skill does not create a plugin from scratch, publish a package, or move
15
+ project-local agent configuration unrelated to the plugin.
16
+
17
+ ## 1. Inspect and plan
18
+
19
+ Identify the destination package directory and read its `package.json`.
20
+ Before changing manifest fields or component compatibility behavior, consult the
21
+ [Agent Plugins Specification](https://github.com/agentplugins/agent-plugins-spec)
22
+ and its versioned specification: it is the canonical reference for the current
23
+ standard. Keep an existing schema version pinned unless the user explicitly
24
+ requests a standards upgrade.
25
+ Inventory these root-level plugin assets when they exist:
26
+
27
+ - `plugin.json`
28
+ - vendor manifest directories for Claude Code, Cursor, Codex, and Copilot CLI
29
+ - `skills/`, `agents/`, `commands/`, `hooks/`, `rules/`, `output-styles/`
30
+ - `.mcp.json`, `.lsp.json`, and plugin-owned `assets/`
31
+
32
+ Leave project configuration in place unless it is required solely to maintain
33
+ the moved plugin. In particular, do not move `.agents/skills/`, plans, or a
34
+ marketplace catalog such as `.claude/marketplace.json`.
35
+
36
+ Before modifying files, report the exact source-to-destination mapping and any
37
+ destination collisions. Ask for confirmation if a destination contains a
38
+ different file that would be overwritten.
39
+
40
+ ## 2. Move the plugin root
41
+
42
+ Move each inventoried asset under the package directory, preserving its path.
43
+ A package receives these relative paths:
44
+
45
+ ```text
46
+ the canonical manifest
47
+ vendor manifests
48
+ skills
49
+ agents
50
+ ```
51
+
52
+ The source root must no longer retain duplicate distributable plugin assets.
53
+ Do not move a project-local skill merely because it is under `.agents/skills/`.
54
+
55
+ ## 3. Configure npm packaging
56
+
57
+ Add every moved plugin artifact to the destination package's `package.json`
58
+ `files` allowlist. At minimum, include the canonical manifest, each present
59
+ vendor manifest directory, and every present component directory. A typical
60
+ configuration is:
61
+
62
+ ```json
63
+ {
64
+ "files": [
65
+ "bin",
66
+ "dist",
67
+ "plugin.json",
68
+ ".claude-plugin",
69
+ ".cursor-plugin",
70
+ ".codex-plugin",
71
+ "skills",
72
+ "agents"
73
+ ]
74
+ }
75
+ ```
76
+
77
+ Retain existing package entries such as `bin`, `dist`, and `governances`.
78
+ Never replace the allowlist wholesale.
79
+
80
+ ## 4. Preserve release synchronization
81
+
82
+ If the repository runs `universal-plugin publish sync-version`, move its
83
+ plugin-specific configuration beside the new `plugin.json` and change
84
+ `packagePath` to `"."`. Update the root release script to run the command from
85
+ the destination package, for example:
86
+
87
+ ```sh
88
+ pnpm exec universal-plugin publish sync-version --root .
89
+ ```
90
+
91
+ Update any checked-in skill lockfile that records an absolute source path for a
92
+ moved skill. Do not modify unrelated agent configuration.
93
+
94
+ ## 5. Verify the result
95
+
96
+ 1. Run the package's focused tests and typecheck/lint commands.
97
+ 2. Run `npm pack --dry-run` from the destination package. Confirm it lists
98
+ `plugin.json`, every required vendor manifest, `skills/`, and `agents/`.
99
+ 3. If the manifest declares build targets, run `universal-plugin plugin build`
100
+ from the destination package and confirm generated paths stay inside it.
101
+ 4. Search the repository for stale references to the old top-level asset paths.
102
+ 5. Review the diff to confirm no project-local `.agents` content or marketplace
103
+ catalog was included in the package.
104
+
105
+ Report the package path, files added to the npm tarball, checks run, and any
106
+ intentionally retained root-local files.
@@ -0,0 +1,11 @@
1
+ {
2
+ "skill_name": "migrate-plugin",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "Move the top-level universal plugin into packages/universal-plugin so npm distributes it.",
7
+ "expected_output": "Inventories and relocates only distributable plugin assets, adds them to package.json files, updates version synchronization, verifies npm pack --dry-run, and preserves project-local .agents content.",
8
+ "files": []
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "skill_name": "migrate-plugin",
3
+ "trigger_queries": [
4
+ {
5
+ "id": 1,
6
+ "query": "Move our root plugin.json and skills into packages/my-plugin so npm ships them.",
7
+ "should_trigger": true,
8
+ "split": "train"
9
+ },
10
+ {
11
+ "id": 2,
12
+ "query": "Our npm package publishes the CLI but not its Claude and Codex plugin assets. Fix the package layout.",
13
+ "should_trigger": true,
14
+ "split": "train"
15
+ },
16
+ {
17
+ "id": 3,
18
+ "query": "Ship this universal agent plugin through npm instead of from the monorepo root.",
19
+ "should_trigger": true,
20
+ "split": "val"
21
+ },
22
+ {
23
+ "id": 4,
24
+ "query": "Upgrade all npx universal-plugin pins to version 0.3.0.",
25
+ "should_trigger": false,
26
+ "split": "train"
27
+ },
28
+ {
29
+ "id": 5,
30
+ "query": "Create a new universal plugin from scratch for Claude Code and Cursor.",
31
+ "should_trigger": false,
32
+ "split": "val"
33
+ }
34
+ ]
35
+ }
@@ -0,0 +1,37 @@
1
+ # plugin skill
2
+
3
+ A skill for creating, inspecting, updating, and deleting universal AI coding agent plugins that target multiple runtimes from a single source of truth.
4
+
5
+ ## Supported runtimes
6
+
7
+ | Vendor | Manifest path |
8
+ | ----------- | ---------------------------- |
9
+ | Claude Code | `.claude-plugin/plugin.json` |
10
+ | Cursor | `.cursor-plugin/plugin.json` |
11
+ | Codex | `.codex-plugin/plugin.json` |
12
+ | Copilot CLI | root `plugin.json` (the canonical manifest; nothing derived) |
13
+
14
+ Universal minimum (no vendor manifest needed): `skills/<name>/SKILL.md` or `.mcp.json`. The canonical source of truth is root `plugin.json`.
15
+
16
+ ## Operations
17
+
18
+ `SKILL.md` is a gateway: it detects what the project already contains, then routes to one operation
19
+ reference and only that one gets read.
20
+
21
+ | Operation | Reference | What it covers |
22
+ | --------- | --------- | -------------- |
23
+ | Create | [`references/create.md`](./references/create.md) | scaffold a new plugin with chosen vendors and components |
24
+ | Adopt | [`references/adopt.md`](./references/adopt.md) | put an existing vendor-specific plugin, or already-shipped skills, onto the open standard |
25
+ | Inspect | [`references/inspect.md`](./references/inspect.md) | show build status for each declared vendor |
26
+ | Update | [`references/update.md`](./references/update.md) | add/remove vendors or components |
27
+ | Delete | [`references/delete.md`](./references/delete.md) | remove generated manifests or the whole plugin |
28
+
29
+ On invocation the gateway checks for existing vendor manifests and publicly-shipped skills, and
30
+ offers adoption when it finds either without a canonical `plugin.json`. Repo-private agent config
31
+ (`.claude/skills/`, `.agents/skills/`) is deliberately excluded — it is not something to package.
32
+
33
+ ## References
34
+
35
+ - [Spec](https://github.com/cyberuni/universal-plugin/blob/main/packages/universal-plugin/.agents/spec/spec.md)
36
+ - [Schema](https://raw.githubusercontent.com/cyberuni/universal-plugin/refs/heads/main/schema/v1.json)
37
+ - [Examples](https://github.com/cyberuni/universal-plugin/tree/main/examples)
@@ -0,0 +1,105 @@
1
+ ---
2
+ name: plugin
3
+ description: Use this skill when creating, inspecting, updating, versioning, or deleting a universal agent plugin that targets multiple AI coding agent runtimes — Claude Code, Cursor, Codex, GitHub Copilot CLI. Also use it to convert a vendor-specific plugin, or a project that already ships skills, onto the open Agent Plugins Specification, or to move a plugin's version — for asks like "make my Claude Code plugin work in Cursor", "convert this to the open plugin standard", "turn these skills into a plugin", "bump my plugin's version", "release a new version of this plugin", or "set the plugin version to 1.0.0".
4
+ ---
5
+
6
+ # Universal Plugin
7
+
8
+ Gateway skill. Identify which operation the user wants, load that operation's reference, and follow
9
+ it.
10
+
11
+ ## When to use
12
+
13
+ When the user wants to create, inspect, update, version, or delete a plugin targeting Claude Code,
14
+ Cursor, Codex, and/or GitHub Copilot CLI from a single source of truth.
15
+
16
+ ## Prerequisites
17
+
18
+ Load governance before starting any operation:
19
+
20
+ ```bash
21
+ npx universal-plugin governance show plugin-design
22
+ ```
23
+
24
+ Until the CLI is available, read `governances/plugin-design.md` from this plugin's installation
25
+ directory. It is the authoritative source for component selection rules and anti-patterns.
26
+
27
+ ## Step 0 — Detect what is already here
28
+
29
+ Run this before routing. What the project already contains often changes which operation is
30
+ actually right — a "create a plugin" request in a repo that already ships skills is an *adopt*, not
31
+ a create.
32
+
33
+ ```bash
34
+ ls -d .claude-plugin .cursor-plugin .codex-plugin .github/plugin .plugin 2>/dev/null
35
+ test -f plugin.json && head -20 plugin.json
36
+ find . -name SKILL.md -not -path '*/node_modules/*' -not -path './.git/*'
37
+ ```
38
+
39
+ Read the signals:
40
+
41
+ | What you find | What it means | Do this |
42
+ |---------------|---------------|---------|
43
+ | Root `plugin.json` with `$schema` on `agent-plugins.org` **and** an `extensions` object | Already on the open standard | Nothing to offer — route normally |
44
+ | A vendor manifest (`.claude-plugin/`, `.cursor-plugin/`, `.codex-plugin/`, `.github/plugin/`) with **no** canonical root `plugin.json` | A vendor-specific plugin | **Offer to adopt** |
45
+ | Root `plugin.json` with no `$schema`/`extensions` | Legacy single-vendor manifest | **Offer to adopt** |
46
+ | Public skills (see below) and no plugin manifest at all | Skills shipped without a plugin | **Offer to adopt** |
47
+ | None of the above | Greenfield | Route normally |
48
+
49
+ ### Which skills count as public
50
+
51
+ Only offer on skills the project **distributes**. Repo-local agent configuration is not a plugin,
52
+ and offering to package it is wrong.
53
+
54
+ | Location | Public? |
55
+ |----------|---------|
56
+ | `skills/<name>/SKILL.md` at the repo root | Yes |
57
+ | `<package>/skills/<name>/SKILL.md` where `package.json` `files` ships it | Yes |
58
+ | `.claude/skills/`, `.agents/skills/`, `.cursor/rules/` | **No** — repo-private tooling |
59
+
60
+ If the only skills are in private locations, say nothing about adoption.
61
+
62
+ ### Making the offer
63
+
64
+ State what you found, what adoption would give them, and let them decline:
65
+
66
+ > This repo has a Claude Code plugin manifest but no canonical `plugin.json`. I can convert it to
67
+ > the open Agent Plugins Specification, which would let one manifest drive Cursor, Codex, and
68
+ > Copilot CLI too — Claude Code keeps working exactly as it does now. Want me to?
69
+
70
+ Offer once. If the user declines, or their request is already a specific unrelated operation
71
+ (deleting manifests, inspecting status), drop it and do what they asked.
72
+
73
+ ## Route
74
+
75
+ Read exactly the reference for the operation at hand — do not load all six.
76
+
77
+ | The user wants to… | Reference |
78
+ |--------------------|-----------|
79
+ | Scaffold a new plugin, add vendors/components to a fresh one, or build vendor manifests | [`references/create.md`](./references/create.md) |
80
+ | Put an existing vendor-specific plugin, or already-shipped skills, onto the open standard | [`references/adopt.md`](./references/adopt.md) |
81
+ | See what a plugin declares and which vendor manifests are built or stale | [`references/inspect.md`](./references/inspect.md) |
82
+ | Add or remove a vendor, or add or remove a component, on an existing plugin | [`references/update.md`](./references/update.md) |
83
+ | Bump or set the plugin's version, or cut a release of it | [`references/version.md`](./references/version.md) |
84
+ | Remove generated manifests, or remove the whole plugin | [`references/delete.md`](./references/delete.md) |
85
+
86
+ If the request spans more than one operation (for example "add Codex and rebuild"), load each
87
+ reference in turn as you reach that part of the work.
88
+
89
+ If the operation is unclear, ask which the user means rather than guessing.
90
+
91
+ ## Related skills
92
+
93
+ | Task | Skill |
94
+ |------|-------|
95
+ | Move a repo-root plugin into its npm package | `migrate-plugin` |
96
+ | Publish a packaged plugin to the marketplace | `publish-plugin` |
97
+ | Bump the pinned `universal-plugin@<version>` the project *calls* (not the plugin's own version) | `upgrade-plugin` |
98
+ | Rewrite `npx` pins to the `upx` runner | `adopt-upx` |
99
+
100
+ ## References
101
+
102
+ - Governance: `npx cyberplace governance show plugin-design`
103
+ - Spec: https://github.com/cyberuni/universal-plugin/blob/main/packages/universal-plugin/.agents/spec/spec.md
104
+ - Schema: https://raw.githubusercontent.com/cyberuni/universal-plugin/refs/heads/main/schema/v1.json
105
+ - Examples: https://github.com/cyberuni/universal-plugin/tree/main/examples
@@ -0,0 +1,7 @@
1
+ ---
2
+ name: <agent-name>
3
+ description: Use this agent to <when to invoke>.
4
+ model: sonnet
5
+ ---
6
+
7
+ <agent instructions>
@@ -0,0 +1,9 @@
1
+ ---
2
+ description: <Short description shown in help>
3
+ argument-hint: [optional-arg]
4
+ allowed-tools: [Read, Bash]
5
+ ---
6
+
7
+ # <Command Title>
8
+
9
+ <instructions>
@@ -0,0 +1,9 @@
1
+ {
2
+ "description": "<plugin-name> hooks",
3
+ "hooks": {
4
+ "PreToolUse": [],
5
+ "PostToolUse": [],
6
+ "Stop": [],
7
+ "UserPromptSubmit": []
8
+ }
9
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
+ "name": "<plugin-name>",
4
+ "version": "1.0.0",
5
+ "description": "<description>",
6
+ "author": { "name": "<author>" },
7
+ "extensions": {
8
+ "org.cyberuni.universal-plugin": {
9
+ "vendors": ["claude-code", "cursor", "codex", "copilot-cli"],
10
+ "skills": "./skills/",
11
+ "harnesses": {
12
+ "claude-code": {},
13
+ "cursor": {},
14
+ "codex": {},
15
+ "copilot-cli": {}
16
+ }
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,15 @@
1
+ ---
2
+ description: Post-install setup — merge always-on plugin guidance into project AGENTS.md
3
+ ---
4
+
5
+ # Plugin Setup
6
+
7
+ Run once after installing the plugin.
8
+
9
+ ## Instructions
10
+
11
+ 1. Read all `.mdc` files under this plugin's `rules/` directory
12
+ 2. Strip YAML frontmatter from each file
13
+ 3. Append the remaining content as a new `## <plugin-name>` section in the project's `AGENTS.md`
14
+ 4. Confirm the merge completed
15
+ 5. The `rules/*.mdc` files are now redundant. Delete them if desired.
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: <skill-name>
3
+ description: Use this skill when <trigger>. <One-line summary.>
4
+ ---
5
+
6
+ # <Title>
7
+
8
+ ## When to use
9
+
10
+ <conditions>
11
+
12
+ ## Instructions
13
+
14
+ 1. First step
15
+ 2. Second step