Skip to content

Commit ba7228e

Browse files
feat: build one Agent Plugins package for several clients
The codex target builds an Agent Plugins package with one client profile and one marketplace, and the agent-plugins target builds packages with none. Codex, Copilot, VS Code and Cursor all read the format, so a plugin built once can serve them all, given each client's marketplace file and client-only files. Add `clients` to the agent-plugins target (DEVPLAT-1558, ADR 0002): - `clients: { codex: {}, copilot: {} }` writes each client's marketplace: Codex .agents/plugins/marketplace.json, Copilot .github/plugin/marketplace.json. `clients.<client>.manifest` and `plugins.<name>.clients.<client>.entry` are deep-merged into them. The shared `entry` and target `manifest` are config errors on agent-plugins that name the client-scoped field instead. - Client-only kinds a listed client loads are selected by default and written to its extension directory: Copilot agents go to com.github.copilot/agents/, with .md, .markdown and .mdc renamed to NAME.agent.md. Any other file in agents/, or two files that land on the same path, fail the build. - A client-only kind that no listed client loads stays a config error, and the message names the client that would load it. A file of such a kind that arrives another way, such as additionalFiles, fails the build. Client names are checked strictly, a client set to undefined counts as not listed, and `clients` is rejected on other targets. - validate checks each client marketplace present: entries, including structured local Codex sources, must point at a package whose plugin.json has the same name. Copilot needs a marketplace owner, and its agents need NAME.agent.md names and valid frontmatter. - src/package-clients.ts holds each client's namespace, marketplace, file placement and validation, with citations to the client docs. - The engine gains two optional hooks, clientMarketplaces and placeFile. Other targets don't set them, and Glean's claude, cursor and codex output is byte-identical (191 files). Verified end to end with the Glean plugin: Copilot CLI 1.0.100 and Codex 0.160.1 both install it from their marketplace in the same output.
1 parent 9ca5066 commit ba7228e

13 files changed

Lines changed: 1407 additions & 78 deletions

File tree

‎CONFORMANCE.md‎

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ against a temp fixture via [`bintastic`](https://github.com/scalvert/bintastic).
4444
deliberately **not** used here: Copilot derives from the Claude marketplace but
4545
extends entries (e.g. `mcpServers` as a `.mcp.json` path), which Claude's stricter
4646
schema rejects. Because it shares the Claude marketplace path, the `claude` and
47-
`copilot` targets need separate output roots.
47+
`copilot` targets need separate output roots. An `agent-plugins` target with
48+
`clients.copilot` also writes `.github/plugin/marketplace.json`, so it needs an
49+
output root separate from the `copilot` target's.
4850
- **antigravity** — covered structurally by the cross-target build test in
4951
`tests/core.test.ts` (required `plugin.json` fields present; optional
5052
`mcp_config.json` written when MCP servers are present). Antigravity CLI does
@@ -55,7 +57,13 @@ against a temp fixture via [`bintastic`](https://github.com/scalvert/bintastic).
5557
validator (`src/agent-plugins.ts`) re-implements the closed-schema checks
5658
without ajv, plus the semantic rules a JSON Schema can't express: skill names
5759
per the Agent Skills specification and matching their directory, and MCP
58-
server rules from spec §7.2 and §9 (`src/mcp.ts`).
60+
server rules from spec §7.2 and §9 (`src/mcp.ts`). With `clients`, the same
61+
package oracle applies. The Codex marketplace uses the codex checks below,
62+
and the Copilot marketplace and `com.github.copilot/agents/` layout are
63+
asserted structurally against the
64+
[Copilot CLI plugin reference](https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-plugin-reference)
65+
(retrieved 2026-10-20), which publishes no schema. Client facts and their
66+
citations live in `src/package-clients.ts`.
5967
- **codex** — the package half uses the Agent Plugins oracle above. The
6068
marketplace half is asserted structurally in `tests/conformance.test.ts` and
6169
`tests/core.test.ts` against the
@@ -74,8 +82,9 @@ against a temp fixture via [`bintastic`](https://github.com/scalvert/bintastic).
7482
added via `entry` is a structured object with an inner `source` discriminator
7583
(e.g. `{ source: "git-subdir", url, path, ref }`), validated by shape rather
7684
than requiring a local directory to exist. No published JSON Schema exists.
77-
Codex shares no marketplace path with the other targets, so it needs no
78-
separate output root.
85+
Among the native targets, Codex shares no marketplace path, but an
86+
`agent-plugins` target with `clients.codex` writes the same
87+
`.agents/plugins/marketplace.json`, so the two need separate output roots.
7988

8089
## Update-check hook facts
8190

‎CONTEXT.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ _Avoid_: portable plugin, AP plugin
3333
A client's additions to a package: its extension namespace, the manifest data under it, and the files in its extension directory.
3434
_Avoid_: overlay, flavor
3535

36+
**Package client**:
37+
A client listed in the `agent-plugins` target's `clients`. One package serves every package client; each also gets its own marketplace file.
38+
_Avoid_: sub-target, flavor
39+
3640
**Extension namespace**:
3741
The reverse-domain key a client owns inside a package, such as `com.openai`.
3842
_Avoid_: vendor key, client key

‎README.md‎

Lines changed: 100 additions & 44 deletions
Large diffs are not rendered by default.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
status: proposed
3+
---
4+
5+
# One package for several clients
6+
7+
Codex, GitHub Copilot, VS Code and Cursor all read Agent Plugins packages. A
8+
plugin built once as a package can serve all of them, if each client also gets
9+
its marketplace file and any client-only files. Before this change, the
10+
`codex` target built a package with one client's profile and marketplace, and
11+
the `agent-plugins` target built packages with none.
12+
13+
We add `clients` to the `agent-plugins` target instead of adding a target per
14+
client or a list of clients to `codex`. Each listed client contributes:
15+
16+
- a marketplace file at the path it reads (Codex
17+
`.agents/plugins/marketplace.json`, Copilot `.github/plugin/marketplace.json`),
18+
- its client-only content kinds, written to its extension directory (Copilot
19+
agents in `com.github.copilot/agents/`, renamed to `NAME.agent.md`).
20+
21+
The package itself (`plugin.json`, `mcp.json`, `skills/`) is identical for
22+
every client, and the spec requires clients to ignore other clients'
23+
namespaces. So the output has no per-client copies of the package that could
24+
drift.
25+
26+
Manifest data for a client goes under `manifest.extensions["<namespace>"]`
27+
explicitly. The `codex` target moves non-portable top-level fields into
28+
`com.openai` automatically, because it serves one client. A package that
29+
serves several clients can't know which one a field is for, so that stays a
30+
build error.
31+
32+
The `codex` target stays for builds that serve only Codex, including
33+
`format: "legacy"`. Claude Code doesn't read Agent Plugins, so it isn't a
34+
package client; adding its manifest to the same directory is separate work.

‎skills/authoring-pluginpack-config/SKILL.md‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,16 @@ so author it once. Don't add a per-target copy just to change
9393
(root `plugin.json` + `mcp.json`). Codex-only manifest fields such as
9494
`interface` move under `extensions["com.openai"]` automatically. Set
9595
`format: "legacy"` on the codex target only to keep the old
96-
`.codex-plugin/plugin.json` layout. The standalone `agent-plugins` target emits
97-
portable packages with no marketplace; it can't include `agents`, `commands`,
98-
`rules`, or `hooks`. Skill names must be lowercase letters, digits, and hyphens
99-
and match their directory, or Agent Plugins clients skip them.
96+
`.codex-plugin/plugin.json` layout. The `agent-plugins` target emits
97+
portable packages. Without `clients` it writes no marketplace and can't include
98+
`agents`, `commands`, `rules`, or `hooks`. With `clients: { codex: {}, copilot:
99+
{} }` it builds each package once and writes each client's marketplace. Listing
100+
`copilot` allows `agents`, which go to `com.github.copilot/agents/NAME.agent.md`;
101+
no client allows `commands`, `rules`, or `hooks`. Put client manifest data
102+
under `manifest.extensions["<namespace>"]`, and Codex `policy`/`category` under
103+
`plugins.<name>.clients.codex.entry`. Skill names must be lowercase letters,
104+
digits, and hyphens and match their directory, or Agent Plugins clients skip
105+
them.
100106

101107
## Verify
102108

0 commit comments

Comments
 (0)