From 4c00270e50be1cefe12da62800f16ec861f7f6a3 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Mon, 7 Sep 2026 01:28:31 +0000 Subject: [PATCH 1/4] feat(portable): record Swival, Junie, and Cascade as skill readers --- .../portable-client-records-instruction.md | 5 + .../adapters/capabilities/portable-1.0.0.json | 170 ++++++++++++++++++ .../tests/install-surface.test.ts | 5 + .../tests/portable-adapter.test.ts | 3 + 4 files changed, 183 insertions(+) create mode 100644 .changeset/portable-client-records-instruction.md diff --git a/.changeset/portable-client-records-instruction.md b/.changeset/portable-client-records-instruction.md new file mode 100644 index 000000000..648976308 --- /dev/null +++ b/.changeset/portable-client-records-instruction.md @@ -0,0 +1,5 @@ +--- +"agent-bundle": patch +--- + +Record the three instruction-and-skill hosts in the pinned portable capability table: Swival reads the emitted `skills/` tree in place through `--skills-dir` and reads the emitted `mcp.json` only when it is named with `--mcp-config`; JetBrains Junie reads the same tree once it is registered with `--skill-location` or `skill-locations`; and Cascade (Devin Desktop) reads a skill directory copied into one of its own roots, with its MCP configuration kept in `~/.codeium/windsurf/mcp_config.json` and its Devin Local agent profile deferring to the separately recorded Devin CLI. Each record names the manifest, MCP, placeholder, and hook surfaces these hosts do not read, with the dated page that says so. (#PR) diff --git a/packages/agent-bundle/src/adapters/capabilities/portable-1.0.0.json b/packages/agent-bundle/src/adapters/capabilities/portable-1.0.0.json index c833249c7..81287543e 100644 --- a/packages/agent-bundle/src/adapters/capabilities/portable-1.0.0.json +++ b/packages/agent-bundle/src/adapters/capabilities/portable-1.0.0.json @@ -1729,6 +1729,176 @@ "state": "unavailable" } } + }, + "swival": { + "name": "Swival", + "issue": 703, + "observed": "docs retrieved 2026-09-06; no product version is published on the documentation pages", + "tier": "skills", + "install": { + "source": "local-directory", + "actions": [ + { + "role": "register", + "command": "swival --skills-dir /skills \"\"" + }, + { + "role": "inspect", + "command": "swival skills list" + } + ], + "location": "the emitted skills/ tree is read where it lies; `skills_dir` in swival.toml makes the same extra directory persistent, and `swival skills add` copies a cloned repository's skills into .swival/skills/ instead" + }, + "discovery": { + "required": [ + "mcp.json", + "skills" + ], + "shadowedBy": [], + "evidence": [ + "2026-09-06: https://swival.dev/pages/skills.html publishes the discovery order — \".swival/skills/ — Swival-specific project skills (highest precedence)\", \".agents/skills/ — common cross-agent standard\", \"--skills-dir paths — explicit extra directories\", then the two global roots — and states \"Every immediate subdirectory that contains SKILL.md is treated as a skill\", which is the shape this projection emits under skills/.", + "2026-09-06: the same page states \"Each --skills-dir path can point directly at one skill directory that contains SKILL.md, or at a parent directory where nested subdirectories contain skill files\", so the emitted skills/ directory is read in place with no copy.", + "2026-09-06: https://swival.dev/pages/mcp.html states \"--mcp-config FILE provides an explicit path to an MCP JSON config file. When set, this replaces the default .swival/mcp.json lookup\", so the emitted mcp.json is read only when it is named explicitly.", + "2026-09-06: no page documents a plugin manifest, a package layout, or an install form that reads a root plugin.json, so nothing here claims one." + ] + }, + "surfaces": { + "manifest": { + "reason": "2026-09-06: Swival discovers skill directories and MCP configuration and publishes no plugin manifest of any kind (https://swival.dev/pages/skills.html, https://swival.dev/pages/mcp.html), so the emitted root plugin.json is read by nothing there.", + "state": "unavailable" + }, + "skills": { + "evidence": [ + "2026-09-06: https://swival.dev/pages/skills.html requires exactly what this projection emits — a directory per skill containing SKILL.md whose frontmatter carries `name` and `description`, with \"The name field must be lowercase alphanumeric with hyphens, must match the directory name\" — and reads an extra parent directory named with --skills-dir." + ], + "state": "supported" + }, + "mcp": { + "evidence": [ + "2026-09-06: https://swival.dev/pages/mcp.html states \".swival/mcp.json ... uses the same format as other MCP-compatible tools\" with \"command, args, env for stdio, and url, headers for SSE\", and that an explicit file is read with --mcp-config FILE." + ], + "reason": "2026-09-06: the emitted document is read only when it is passed as --mcp-config /mcp.json, and only two transports are documented — \"Each server needs either command (for stdio transport) or url (for SSE transport), but not both\". No page states what Swival does with the spec's `type` discriminator or with a streamable-http server, and a TOML server of the same name \"always win[s] by server name over JSON servers\".", + "state": "degraded" + }, + "placeholders": { + "reason": "2026-09-06: no ${PLUGIN_ROOT} or ${PLUGIN_DATA} expansion is documented for Swival MCP configuration, and the documented substitution surface is the skill body and its own directory path, so the reserved behavior of Agent Plugins 1.0.0 §9.1 is not provided.", + "state": "unavailable" + }, + "hooks": { + "reason": "2026-09-06: Agent Plugins 1.0.0 defines no hooks, so this projection emits no hooks document for Swival to read.", + "state": "unavailable" + } + } + }, + "cascade": { + "name": "Cascade (Devin Desktop)", + "issue": 704, + "observed": "docs.devin.ai/desktop retrieved 2026-09-06; Windsurf renamed to Devin Desktop, Cascade documented as the legacy agent beside the Devin Local agent", + "tier": "skills", + "install": { + "source": "local-directory", + "actions": [ + { + "role": "install", + "command": "cp -R skills/ .agents/skills/" + } + ], + "location": ".windsurf/skills// (workspace) or ~/.codeium/windsurf/skills// (global); .agents/skills/ and ~/.agents/skills/ are read for cross-agent compatibility, which is where the emitted tree is copied" + }, + "discovery": { + "required": [ + "skills" + ], + "shadowedBy": [], + "evidence": [ + "2026-09-06: https://docs.devin.ai/desktop/cascade/skills states \"For cross-agent compatibility, Devin Desktop also discovers skills in .agents/skills/ and ~/.agents/skills/\", and requires \"a SKILL.md file with YAML frontmatter\" per skill directory — the shape this projection emits.", + "2026-09-06: the same page's scope table names .windsurf/skills/ and ~/.codeium/windsurf/skills/ as the discovery roots; the emitted package root is not one of them, so the tree is copied into a root Cascade scans.", + "2026-09-06: the MCP page states \"The MCP configuration on this page applies to the legacy Cascade agent only. The Devin Local agent — the default agent for new tabs — configures MCP servers in the Devin CLI config files instead\", which is the Devin CLI profile recorded separately as devin-cli (#701).", + "2026-09-06: no Devin Desktop page documents a plugin manifest for Cascade — the documented customization units are Skills, Rules, Workflows, and AGENTS.md." + ] + }, + "surfaces": { + "manifest": { + "reason": "2026-09-06: Cascade's documented customization units are Skills, Rules, Workflows, and AGENTS.md (https://docs.devin.ai/desktop/cascade/skills, https://docs.devin.ai/desktop/cascade/memories); no page defines a plugin manifest, so the emitted root plugin.json is read by nothing there.", + "state": "unavailable" + }, + "skills": { + "evidence": [ + "2026-09-06: https://docs.devin.ai/desktop/cascade/skills requires a folder per skill with SKILL.md and YAML frontmatter carrying `name` and `description`, and reads the cross-agent .agents/skills/ root." + ], + "reason": "2026-09-06: the emitted package root is not a Cascade discovery root; each skill directory is copied into .windsurf/skills/, ~/.codeium/windsurf/skills/, or .agents/skills/ before Cascade sees it, and the copy is what loads.", + "state": "degraded" + }, + "mcp": { + "reason": "2026-09-06: Cascade reads MCP servers from ~/.codeium/windsurf/mcp_config.json only (https://docs.devin.ai/desktop/cascade/mcp), where a remote server \"requires a serverUrl or url field\" and interpolation is ${env:VAR_NAME} / ${file:/path}; no page reads a plugin-relative mcp.json, so the emitted document is not a Cascade MCP source.", + "state": "unavailable" + }, + "placeholders": { + "reason": "2026-09-06: the documented interpolation patterns are ${env:VAR_NAME} and ${file:/path/to/file} in mcp_config.json (https://docs.devin.ai/desktop/cascade/mcp); ${PLUGIN_ROOT} and ${PLUGIN_DATA} are not documented anywhere for Cascade, so the reserved behavior of Agent Plugins 1.0.0 §9.1 is not provided.", + "state": "unavailable" + }, + "hooks": { + "reason": "2026-09-06: Agent Plugins 1.0.0 defines no hooks, so this projection emits no hooks document for Cascade to read.", + "state": "unavailable" + } + } + }, + "junie": { + "name": "JetBrains Junie", + "issue": 710, + "observed": "junie.jetbrains.com/docs retrieved 2026-09-06, agent-skills page dated 01 September 2026; no CLI version is published on the page", + "tier": "skills", + "install": { + "source": "local-directory", + "actions": [ + { + "role": "register", + "command": "junie --skill-location /skills" + }, + { + "role": "inspect", + "command": "/skills" + } + ], + "location": ".junie/skills// (project) or ~/.junie/skills// (user); `skill-locations` in config.json makes an extra folder persistent, and .agents/skills/ is read in a trusted project" + }, + "discovery": { + "required": [ + "skills" + ], + "shadowedBy": [], + "evidence": [ + "2026-09-06: https://junie.jetbrains.com/docs/agent-skills.html states \"Skills follow the open Agent Skills format and are portable across agents\", requires that \"The SKILL.md file is required. A folder without it is not recognized as a skill\", and reads \"Custom folders: any folders you add with the --skill-location option or the skill-locations field in config.json\".", + "2026-09-06: the same page names the default roots — \"/.junie/skills//\" and \"~/.junie/skills//\" — plus \".agents/skills/ directories: /.agents/skills/ (in a trusted project) and ~/.agents/skills/\"; the emitted package root is none of them, so it loads only as a registered extra location.", + "2026-09-06: https://junie.jetbrains.com/docs/junie-cli-mcp-configuration.html names the MCP config locations as \"Project scope: .junie/mcp/mcp.json at the root of your project\" and \"User scope: ~/.junie/mcp/mcp.json\", and no page states which file name --mcp-location looks for inside an additional folder.", + "2026-09-06: no Junie page documents a plugin manifest; the documented units are agent skills, guidelines, and MCP configuration." + ] + }, + "surfaces": { + "manifest": { + "reason": "2026-09-06: Junie's documented units are agent skills, guidelines, and MCP configuration (https://junie.jetbrains.com/docs/agent-skills.html); no page defines a plugin manifest, so the emitted root plugin.json is read by nothing there.", + "state": "unavailable" + }, + "skills": { + "evidence": [ + "2026-09-06: https://junie.jetbrains.com/docs/agent-skills.html requires a folder per skill containing SKILL.md with YAML frontmatter whose `name` is required and `description` optional — satisfied by every skill this projection emits — and reads extra folders given with --skill-location." + ], + "reason": "2026-09-06: the emitted skills/ root is not a default location, so it loads only once registered with --skill-location or the skill-locations config field, and \"if a project-level and a user-level skills have the same name, the user-level skill will be skipped\".", + "state": "degraded" + }, + "mcp": { + "reason": "2026-09-06: MCP servers are read from .junie/mcp/mcp.json or ~/.junie/mcp/mcp.json (https://junie.jetbrains.com/docs/junie-cli-mcp-configuration.html). --mcp-location adds \"additional folders where MCP servers should be found\", but no page states the file name it looks for inside them, and the documented server fields are command/args/env and url/headers with no `type` discriminator, so the emitted plugin-root mcp.json is not a proven Junie MCP source.", + "state": "unavailable" + }, + "placeholders": { + "reason": "2026-09-06: no ${PLUGIN_ROOT} or ${PLUGIN_DATA} expansion is documented for Junie MCP configuration or skills, so the reserved behavior of Agent Plugins 1.0.0 §9.1 is not provided.", + "state": "unavailable" + }, + "hooks": { + "reason": "2026-09-06: Agent Plugins 1.0.0 defines no hooks, so this projection emits no hooks document for Junie to read.", + "state": "unavailable" + } + } } }, "specificationSections": { diff --git a/packages/agent-bundle/tests/install-surface.test.ts b/packages/agent-bundle/tests/install-surface.test.ts index afd7586a4..197544159 100644 --- a/packages/agent-bundle/tests/install-surface.test.ts +++ b/packages/agent-bundle/tests/install-surface.test.ts @@ -302,6 +302,11 @@ it('documents recorded Agent Plugins clients for the portable profile', () => { expect(install).toContain('**Antigravity**'); // A client that reads the emitted tree where it lies is registered, not installed. expect(install).toContain('**Pi**'); + // An instruction-and-skill host is recorded at the tier it actually reaches, + // in the location its own documentation scans (#703, #704, #710). + expect(install).toContain('**Cascade (Devin Desktop)**'); + expect(install).toContain('**JetBrains Junie**'); + expect(install).toContain('**Swival**'); // Reading a document and running what it configures are separate claims. expect(install).toContain('`mcp` records that the client reads the emitted `mcp.json` as MCP configuration'); // This fixture carries no component, so a client that reads only components diff --git a/packages/agent-bundle/tests/portable-adapter.test.ts b/packages/agent-bundle/tests/portable-adapter.test.ts index 918724bfb..693d8ec88 100644 --- a/packages/agent-bundle/tests/portable-adapter.test.ts +++ b/packages/agent-bundle/tests/portable-adapter.test.ts @@ -664,6 +664,7 @@ it('emits the artifact paths every recorded client reads, and none of the manife expect(clients.map((client) => client.id)).toEqual([ 'antigravity', + 'cascade', 'cline', 'codewhale', 'copilot-cli', @@ -671,11 +672,13 @@ it('emits the artifact paths every recorded client reads, and none of the manife 'gemini-cli', 'grok-build', 'hermes-agent', + 'junie', 'kiro-powers', 'openclaw', 'opencode', 'pi', 'qoder-cli', + 'swival', 'vs-code', 'zed-agent', ]); From ccb34051ec5f8d9488f7962de91181ffcedfad40 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Mon, 7 Sep 2026 01:28:39 +0000 Subject: [PATCH 2/4] chore: point the changeset at its PR --- .changeset/portable-client-records-instruction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/portable-client-records-instruction.md b/.changeset/portable-client-records-instruction.md index 648976308..6a65adac6 100644 --- a/.changeset/portable-client-records-instruction.md +++ b/.changeset/portable-client-records-instruction.md @@ -2,4 +2,4 @@ "agent-bundle": patch --- -Record the three instruction-and-skill hosts in the pinned portable capability table: Swival reads the emitted `skills/` tree in place through `--skills-dir` and reads the emitted `mcp.json` only when it is named with `--mcp-config`; JetBrains Junie reads the same tree once it is registered with `--skill-location` or `skill-locations`; and Cascade (Devin Desktop) reads a skill directory copied into one of its own roots, with its MCP configuration kept in `~/.codeium/windsurf/mcp_config.json` and its Devin Local agent profile deferring to the separately recorded Devin CLI. Each record names the manifest, MCP, placeholder, and hook surfaces these hosts do not read, with the dated page that says so. (#PR) +Record the three instruction-and-skill hosts in the pinned portable capability table: Swival reads the emitted `skills/` tree in place through `--skills-dir` and reads the emitted `mcp.json` only when it is named with `--mcp-config`; JetBrains Junie reads the same tree once it is registered with `--skill-location` or `skill-locations`; and Cascade (Devin Desktop) reads a skill directory copied into one of its own roots, with its MCP configuration kept in `~/.codeium/windsurf/mcp_config.json` and its Devin Local agent profile deferring to the separately recorded Devin CLI. Each record names the manifest, MCP, placeholder, and hook surfaces these hosts do not read, with the dated page that says so. (#727) From 665e3267538703ba3a4a37e0aa2a3c26033ca0a5 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Mon, 7 Sep 2026 01:37:53 +0000 Subject: [PATCH 3/4] test(portable): assert Swival's claims track the emitted inventory --- .../tests/install-surface.test.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/agent-bundle/tests/install-surface.test.ts b/packages/agent-bundle/tests/install-surface.test.ts index 197544159..6bfb0595d 100644 --- a/packages/agent-bundle/tests/install-surface.test.ts +++ b/packages/agent-bundle/tests/install-surface.test.ts @@ -194,6 +194,9 @@ it.each([ { agentPlugins: 'installs this bundle as one plugin. Reads: `plugin.json`.', inventory: 'no component', + swivalPartial: false, + swivalTier: 'loads the components it recognizes without reading the manifest. This bundle emits none of' + + ' the paths it reads, so there is nothing to install there.', mcpServers: [], skills: [], skillsTier: 'loads the components it recognizes without reading the manifest. This bundle emits none of' @@ -202,6 +205,9 @@ it.each([ { agentPlugins: 'installs this bundle as one plugin. Reads: `plugin.json`, `skills`.', inventory: 'skills only', + swivalPartial: false, + swivalTier: 'loads the components it recognizes without reading the manifest. Reads: `skills`.' + + ' Register: `swival --skills-dir /skills ""`.', mcpServers: [], skills: [portableSkill], skillsTier: 'loads the components it recognizes without reading the manifest. Reads: `skills`.' @@ -210,6 +216,9 @@ it.each([ { agentPlugins: 'installs this bundle as one plugin. Reads: `mcp.json`, `plugin.json`.', inventory: 'MCP only', + swivalPartial: true, + swivalTier: 'loads the components it recognizes without reading the manifest. Reads: `mcp.json`.' + + ' Register: `swival --skills-dir /skills ""`.', mcpServers: [portableServer], skills: [], skillsTier: 'loads the components it recognizes without reading the manifest. Reads: `mcp.json`.' @@ -218,6 +227,9 @@ it.each([ { agentPlugins: 'installs this bundle as one plugin. Reads: `mcp.json`, `plugin.json`, `skills`.', inventory: 'skills and MCP', + swivalPartial: true, + swivalTier: 'loads the components it recognizes without reading the manifest. Reads: `mcp.json`, `skills`.' + + ' Register: `swival --skills-dir /skills ""`.', mcpServers: [portableServer], skills: [portableSkill], skillsTier: 'loads the components it recognizes without reading the manifest. Reads: `mcp.json`, `skills`.' @@ -234,6 +246,14 @@ it.each([ + ` plugins documented as closed beta) ${expected.agentPlugins}`); expect(install).toContain('- **Qoder CLI** (docs retrieved 2026-09-06; no CLI version is published on' + ` any page) ${expected.skillsTier}`); + // A narrowed surface is a limit on a document; a limit on a document this + // build did not write is not a limit here. + expect(install).toContain('- **Swival** (docs retrieved 2026-09-06; no product version is published on' + + ` the documentation pages) ${expected.swivalTier}`); + const partial = ' - Partial `mcp`: 2026-09-06: the emitted document is read only when it is passed as' + + ' --mcp-config /mcp.json'; + if (expected.swivalPartial) expect(install).toContain(partial); + else expect(install).not.toContain(partial); // A client that reads nothing says so whatever the bundle carries. expect(install).toContain('- **Antigravity** (docs retrieved 2026-09-06; no product or CLI version is' + ' published on any page) loads nothing from this bundle as published.'); From 2f45c8401d7cbc86cdcf71ca0c7b77c3d02cfc44 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Mon, 7 Sep 2026 01:50:14 +0000 Subject: [PATCH 4/4] fix(portable): correct the Swival rows and drop nine twice-written client records Nine client records were written twice in the pinned portable table, and JSON parsing keeps only the last copy: Pi shipped as a client that reads nothing while its live-probed skills-tier record sat unread. Delete the dead run, keep the record each client's evidence supports, and hold the table to one record per client in the suite, since a repeated key is not a duplicate a reader can see. Swival's own rows now say what its pages say. Its skill tree loads only once registered with --skills-dir and loses by name to .swival/skills/ and .agents/skills/, so the row is degraded like Junie's. Its mcp row is unavailable: the emitted document is a shape Swival reads, but only an invocation passing --mcp-config reads this one, and the recorded registration does not, so mcp.json is no longer claimed as a path this client reads. --- .../portable-client-records-instruction.md | 2 +- .../adapters/capabilities/portable-1.0.0.json | 521 +----------------- .../tests/install-surface.test.ts | 22 +- .../tests/portable-adapter.test.ts | 15 + 4 files changed, 34 insertions(+), 526 deletions(-) diff --git a/.changeset/portable-client-records-instruction.md b/.changeset/portable-client-records-instruction.md index 6a65adac6..4681ada8a 100644 --- a/.changeset/portable-client-records-instruction.md +++ b/.changeset/portable-client-records-instruction.md @@ -2,4 +2,4 @@ "agent-bundle": patch --- -Record the three instruction-and-skill hosts in the pinned portable capability table: Swival reads the emitted `skills/` tree in place through `--skills-dir` and reads the emitted `mcp.json` only when it is named with `--mcp-config`; JetBrains Junie reads the same tree once it is registered with `--skill-location` or `skill-locations`; and Cascade (Devin Desktop) reads a skill directory copied into one of its own roots, with its MCP configuration kept in `~/.codeium/windsurf/mcp_config.json` and its Devin Local agent profile deferring to the separately recorded Devin CLI. Each record names the manifest, MCP, placeholder, and hook surfaces these hosts do not read, with the dated page that says so. (#727) +Record the three instruction-and-skill hosts in the pinned portable capability table: Swival reads the emitted `skills/` tree in place through `--skills-dir`, behind its own `.swival/skills/` and `.agents/skills/` roots by name; JetBrains Junie reads the same tree once it is registered with `--skill-location` or `skill-locations`; and Cascade (Devin Desktop) reads a skill directory copied into one of its own roots, with its MCP configuration kept in `~/.codeium/windsurf/mcp_config.json` and its Devin Local agent profile deferring to the separately recorded Devin CLI. Each record names the manifest, MCP, placeholder, and hook surfaces these hosts do not read, with the dated page that says so — Swival's emitted `mcp.json` among them, since only an invocation that passes `--mcp-config` at it reads that file and the recorded registration does not. Fix nine client records that were written twice, where JSON parsing kept only the second copy: Pi is now published as the skills-tier client its live-probed record describes, rather than as a client that reads nothing. (#727) diff --git a/packages/agent-bundle/src/adapters/capabilities/portable-1.0.0.json b/packages/agent-bundle/src/adapters/capabilities/portable-1.0.0.json index 81287543e..0ee7c1533 100644 --- a/packages/agent-bundle/src/adapters/capabilities/portable-1.0.0.json +++ b/packages/agent-bundle/src/adapters/capabilities/portable-1.0.0.json @@ -1114,514 +1114,6 @@ "location": "the emitted skills/ tree is read where it lies; ~/.pi/agent/skills/, ~/.agents/skills/, .pi/skills/, and .agents/skills/ are the scanned roots, and `skills` in settings makes an extra directory persistent" } }, - "qoder-cli": { - "name": "Qoder CLI", - "issue": 696, - "observed": "docs retrieved 2026-09-06; no CLI version is published on any page", - "tier": "skills", - "install": { - "source": "local-directory", - "actions": [ - { - "role": "install", - "command": "qoder plugins install --scope user" - }, - { - "role": "verify", - "command": "qoder plugins validate " - }, - { - "role": "inspect", - "command": "qoder plugins list --json" - } - ], - "location": "the --scope target (user, project, or local); enablement is recorded in settings.json as enabledPlugins" - }, - "discovery": { - "required": [ - "skills", - "mcp.json" - ], - "shadowedBy": [ - { - "path": ".mcp.json", - "surfaces": [ - "mcp" - ] - } - ], - "evidence": [ - "2026-09-06: https://docs.qoder.com/cli/plugins-reference states the manifest \"is located at .qoder-plugin/plugin.json and must not be placed in the plugin root directory\", and that without a manifest \"the CLI loads components from conventional directories and uses the plugin directory name as the plugin name\".", - "2026-09-06: https://docs.qoder.com/cli/plugins states \"plugins install for a local plugin requires at least one recognizable component or resource\", which the emitted skills/ tree and mcp.json satisfy.", - "2026-09-06: no manifest-precedence order is published, so the behavior of a composite root carrying both .qoder-plugin/plugin.json and plugin.json is unproven.", - "2026-09-06: precedence that is published is per file, not per root: https://docs.qoder.com/cli/mcp-reference states \"If both exist, .mcp.json takes precedence, and they are not merged\", which withholds the emitted mcp.json alone and leaves the shared skills/ tree discovered." - ] - }, - "surfaces": { - "manifest": { - "reason": "2026-09-06: https://docs.qoder.com/cli/plugins-reference states the manifest \"must not be placed in the plugin root directory\", so the emitted root plugin.json is not a recognized manifest and the plugin is identified only by its directory name.", - "state": "unavailable" - }, - "skills": { - "evidence": [ - "2026-09-06: https://docs.qoder.com/cli/Skills documents plugin skills/ with the same structure as ~/.qoder/skills/, requiring frontmatter name (lowercase, numbers, hyphens, max 64) and description (max 1024) — both emitted, within both bounds, by the pinned Agent Skills lowering." - ], - "state": "supported" - }, - "mcp": { - "evidence": [ - "2026-09-06: https://docs.qoder.com/cli/mcp-reference states Qoder is \"Compatible with mcp.json (without a leading dot) as a fallback for .mcp.json\", reads the top-level mcpServers key, and accepts type values stdio and http/streamable-http — the transports this projection emits." - ], - "state": "supported" - }, - "placeholders": { - "reason": "2026-09-06: QODER_PLUGIN_ROOT and QODER_PLUGIN_DATA are documented only for hooks (https://docs.qoder.com/cli/hooks-reference), and no ${...} placeholder is documented for MCP server configuration, so the emitted ${PLUGIN_ROOT} and ${PLUGIN_DATA} tokens are not proven to expand.", - "state": "unavailable" - }, - "hooks": { - "reason": "2026-09-06: Qoder reads plugin hooks from hooks/hooks.json and requires the extra { \"hooks\": ... } wrapper (https://docs.qoder.com/cli/hooks-reference); Agent Plugins 1.0.0 defines no hooks, so this projection emits no hooks document for it to read.", - "state": "unavailable" - } - } - }, - "codewhale": { - "name": "CodeWhale", - "issue": 709, - "observed": "Hmbown/CodeWhale main 19d34a5fb6c07b34e0b7234beb74a1cf1969efb4, docs retrieved 2026-09-06 (native Agent Plugins v1.0.0 support since v0.9.4)", - "tier": "agent-plugins", - "install": { - "source": "local-directory", - "actions": [ - { - "role": "install", - "command": "/plugin install ./" - } - ], - "location": "~/.codewhale/plugins// (user) or /.codewhale/plugins// (workspace); a local directory is copied" - }, - "discovery": { - "required": [ - "plugin.json", - "skills", - "mcp.json" - ], - "shadowedBy": [], - "evidence": [ - "2026-09-06: docs/PLUGIN_BUNDLES.md (commit 24ca14efb1615acd5b1646409b2b8d006522194e, 2026-08-29) states \"Codewhale scans only its own roots, looking in each / directory for a manifest named plugin.json (the native Agent Plugins v1.0.0 format, since v0.9.4)\", and docs/PLUGINS.md documents \"/plugin install ./path/to/bundle # local directory (copied)\".", - "2026-09-06: \"A skills/ directory in the bundle root is picked up automatically\" — the emitted layout, with no CodeWhale-specific component paths required." - ] - }, - "surfaces": { - "manifest": { - "evidence": [ - "2026-09-06: docs/PLUGIN_BUNDLES.md states \"The standard's manifest root is closed: $schema, name, and the optional well-known fields (version, description, author, homepage, repository, license, keywords, extensions). An unknown root key is a parse error\" — the closed root this projection emits and validates against the pinned 1.0.0 schema, and \"unknown vendor namespaces are ignored, never rejected\" for the manifest's extensions object." - ], - "state": "supported" - }, - "skills": { - "evidence": [ - "2026-09-06: docs/SKILLS.md (commit 92547e460f007abf8807705036ca6a40fba5cbb9, 2026-09-01) and PLUGIN_BUNDLES.md both read skills from the bundle-root skills/ directory that this projection emits." - ], - "state": "supported" - }, - "mcp": { - "evidence": [ - "2026-09-06: docs/MCP.md (commit 806d93e826ee615b702629775f0ec3dd19c97854, 2026-08-25) supports all three transports the 1.0.0 MCP schema defines, including the stdio and streamable-http forms this projection emits." - ], - "reason": "2026-09-06: CodeWhale narrows the standard's env rule — \"Local stdio environment entries must use exact ${SOURCE_ENV} references\" — so an emitted env value that is anything other than one whole variable reference is not accepted there.", - "state": "degraded" - }, - "placeholders": { - "reason": "2026-09-06: CodeWhale rejects PLUGIN_ROOT and PLUGIN_DATA as env entry names (as the 1.0.0 schema does), but its documentation never states whether it provides those variables or expands ${PLUGIN_ROOT} and ${PLUGIN_DATA} in args, env values, or cwd, so the reserved behavior of §9.1 is unproven there.", - "state": "unavailable" - }, - "hooks": { - "reason": "2026-09-06: docs/HOOKS.md documents CodeWhale's own hook layout; Agent Plugins 1.0.0 defines no hooks, so this projection emits no hooks document for it to read.", - "state": "unavailable" - } - } - }, - "copilot-cli": { - "name": "GitHub Copilot CLI", - "issue": 698, - "observed": "@github/copilot 1.0.83, installed and exercised 2026-09-06", - "tier": "agent-plugins", - "install": { - "source": "local-directory", - "actions": [ - { - "role": "install", - "command": "copilot plugin install " - }, - { - "role": "inspect", - "command": "copilot plugins list" - }, - { - "role": "verify", - "command": "copilot --plugin-dir " - } - ], - "location": "~/.copilot/installed-plugins/_direct/, recorded in ~/.copilot/config.json" - }, - "discovery": { - "required": [ - "plugin.json", - "skills", - "mcp.json" - ], - "shadowedBy": [], - "evidence": [ - "2026-09-06: `copilot plugin install /tmp/hostcli/fixture` on 1.0.83 answered \"Plugin \\\"probe-plugin\\\" installed successfully. Installed 1 skill.\" for a hand-built Agent Plugins package (root plugin.json with the 1.0.0 $schema, skills/review/SKILL.md, mcp.json), and `copilot plugins list` then reported the plugin, the plugin-contributed MCP server, and the plugin-contributed skill from that one manifest.", - "2026-09-06: the same install printed \"Warning: Direct plugin installs (repos, URLs, local paths) are deprecated. Only plugin@marketplace installs will be supported in a future release\", so the local-path command above is a deprecated path on 1.0.83.", - "2026-09-06: the installed copy is a copy, not a link: ~/.copilot/config.json recorded cache_path ~/.copilot/installed-plugins/_direct/fixture with source {\"source\":\"local\",\"path\":\"...\"}." - ] - }, - "surfaces": { - "manifest": { - "evidence": [ - "2026-09-06: 1.0.83 installed the root plugin.json and reported its name and version verbatim (`probe-plugin (v1.0.0)`) with no host-specific manifest present." - ], - "state": "supported" - }, - "skills": { - "evidence": [ - "2026-09-06: `copilot plugins list` on 1.0.83 reported \"Skills: Plugin-contributed: review -- Review a change\", read from skills/review/SKILL.md in the installed package." - ], - "state": "supported" - }, - "mcp": { - "evidence": [ - "2026-09-06: `copilot plugins list` reported \"MCP servers: Plugin-contributed: probe -- stdio transport\" and `copilot mcp get probe` reported Source: Plugin, Source plugin: probe-plugin (1.0.0) — the emitted mcp.json, read without a .mcp.json present." - ], - "state": "supported" - }, - "placeholders": { - "evidence": [ - "2026-09-06: `copilot mcp get probe` on 1.0.83 kept the command as `node ${PLUGIN_ROOT}/mcp/probe.mjs` and listed PLUGIN_ROOT, PLUGIN_DATA, COPILOT_PLUGIN_ROOT, COPILOT_PLUGIN_DATA, CLAUDE_PLUGIN_ROOT, and CLAUDE_PLUGIN_DATA in the server environment — the reserved variables of Agent Plugins 1.0.0 §9.1." - ], - "reason": "2026-09-06: the probe proved the configuration Copilot records, not a spawned server: `copilot mcp get` prints static configuration, and spawning the server requires a GitHub Copilot login that was not performed.", - "state": "degraded" - }, - "hooks": { - "reason": "2026-09-06: Copilot CLI 1.0.83 exposes hooks (documented separately at https://docs.github.com/en/copilot/reference/hooks-reference), but Agent Plugins 1.0.0 defines no hooks, so this projection emits no hooks document for it to read.", - "state": "unavailable" - } - } - }, - "gemini-cli": { - "name": "Gemini CLI", - "issue": 695, - "observed": "@google/gemini-cli 0.58.0, installed and exercised 2026-09-06", - "tier": "skills", - "install": { - "source": "local-directory", - "actions": [ - { - "role": "install", - "command": "gemini skills install /skills/" - }, - { - "role": "inspect", - "command": "gemini skills list --all" - } - ], - "location": "~/.gemini/skills// at user scope" - }, - "discovery": { - "required": [ - "skills" - ], - "shadowedBy": [], - "evidence": [ - "2026-09-06: `gemini skills install /tmp/hostcli/fixture/skills/review` on 0.58.0 answered \"Searching for skills in .../skills/review... The following agent skill(s) will be installing: * review: Review a change\" and \"Successfully installed skill: review (scope: user, location: ~/.gemini/skills/review)\", so the emitted skill directory installs one skill at a time, not the package as a whole.", - "2026-09-06: `gemini extensions install` first blocks on an interactive workspace-trust prompt; past both prompts it reaches the same manifest refusal below." - ] - }, - "surfaces": { - "manifest": { - "reason": "2026-09-06: `gemini extensions validate /tmp/hostcli/fixture` on 0.58.0 exited 1 with \"Configuration file not found at /tmp/hostcli/fixture/gemini-extension.json\" — Gemini CLI requires its own gemini-extension.json manifest, which this projection does not emit, and `gemini extensions list` then reported \"No extensions installed.\"", - "state": "unavailable" - }, - "skills": { - "evidence": [ - "2026-09-06: 0.58.0 parsed the emitted SKILL.md frontmatter and listed the skill as `review [Enabled]` with `Description: Review a change` from ~/.gemini/skills/review/SKILL.md." - ], - "state": "supported" - }, - "mcp": { - "reason": "2026-09-06: Gemini CLI reads MCP servers from the mcpServers map of its own gemini-extension.json manifest or a settings.json (https://geminicli.com/docs/extensions/reference/, last updated May 14, 2026); with the manifest rejected, the emitted mcp.json is never consulted, and the skills install path copies only the skill directory.", - "state": "unavailable" - }, - "placeholders": { - "reason": "2026-09-06: Gemini CLI documents ${extensionPath} for portability inside its own manifest, not the reserved ${PLUGIN_ROOT} and ${PLUGIN_DATA} of Agent Plugins 1.0.0 §9.1; no emitted document that carries those tokens is read at this tier.", - "state": "unavailable" - }, - "hooks": { - "reason": "2026-09-06: Gemini CLI loads extension hooks from hooks/hooks.json and states \"hooks are not defined in the gemini-extension.json manifest\" (https://geminicli.com/docs/extensions/reference/); Agent Plugins 1.0.0 defines no hooks, so this projection emits no hooks document for it to read.", - "state": "unavailable" - } - } - }, - "cline": { - "name": "Cline", - "issue": 705, - "observed": "@cline/cli 0.0.13 exercised 2026-09-06; docs.cline.bot retrieved 2026-09-06 (@cline/sdk 0.0.82)", - "tier": "skills", - "install": { - "source": "local-directory", - "actions": [ - { - "role": "install", - "command": "cp -R skills/ ~/.cline/skills/" - } - ], - "location": "~/.cline/skills// (global) or .cline/skills//, .clinerules/skills/, .claude/skills/ (project)" - }, - "discovery": { - "required": [ - "skills" - ], - "shadowedBy": [], - "evidence": [ - "2026-09-06: https://docs.cline.bot/customization/skills lists the skill roots verbatim — project `.cline/skills/` (recommended), `.clinerules/skills/`, `.claude/skills/`; global `~/.cline/skills/` — and states that a global skill takes precedence over a project skill of the same name.", - "2026-09-06: Cline does not read `.agents/skills/`; the only cross-tool root on that page is `.claude/skills/`.", - "2026-09-06: `@cline/cli` 0.0.13 (bin `clite`) exposes no plugin, skill, or extension subcommand — its full command list is auth, config, connect, mcp, doctor, history, hook, schedule, hub, update, version, kanban — so the copy above is the only install path proven for the CLI, and https://docs.cline.bot/customization/plugins scopes the native plugin tier to \"Cline SDK, CLI, and Kanban\" and states it \"is not applicable on VSCode and JetBrains Extension for now\"." - ] - }, - "surfaces": { - "manifest": { - "reason": "2026-09-06: a Cline plugin is installed from an npm, git, remote, or local source into ~/.cline/plugins/_installed/ with Cline's own layout; no upstream page documents reading a root Agent Plugins plugin.json, and `@cline/cli` 0.0.13 exposes no plugin subcommand to offer it to.", - "state": "unavailable" - }, - "skills": { - "evidence": [ - "2026-09-06: https://docs.cline.bot/customization/skills requires frontmatter `name` that \"must exactly match the directory name\" and a `description` of at most 1024 characters — both emitted, and the name always equals the directory name, by the pinned Agent Skills lowering." - ], - "reason": "2026-09-06: the skill tree must be copied into one of Cline's own roots; the emitted package is not a Cline install unit, and no CLI verb in @cline/cli 0.0.13 performs the copy.", - "state": "degraded" - }, - "mcp": { - "reason": "2026-09-06: Cline reads mcpServers from its own configuration and the retrieved pages give three unreconciled paths for it (~/.cline/mcp.json, .cline/mcp.json, ~/.cline/data/settings/cline_mcp_settings.json); none is a plugin-root mcp.json, and Cline's remote transport is spelled `streamableHttp` rather than the standard's `streamable-http`.", - "state": "unavailable" - }, - "placeholders": { - "reason": "2026-09-06: no ${VAR} interpolation syntax is documented for Cline MCP configuration, and no emitted document carrying the Agent Plugins 1.0.0 §9.1 tokens is read at this tier.", - "state": "unavailable" - }, - "hooks": { - "reason": "2026-09-06: Cline loads hooks from its own hooks directory (`--hooks-dir`, default ~/.cline/hooks); Agent Plugins 1.0.0 defines no hooks, so this projection emits no hooks document for it to read.", - "state": "unavailable" - } - } - }, - "hermes-agent": { - "name": "Hermes Agent", - "issue": 697, - "observed": "hermes-agent.nousresearch.com developer guide retrieved 2026-09-06; no version is printed on the page", - "tier": "agent-plugins", - "install": { - "source": "marketplace", - "actions": [ - { - "role": "install", - "command": "hermes plugins install / --no-enable" - } - ], - "location": "~/.hermes/plugins// with the root plugin.json at that level; \"Anything deeper is ignored\". No local-directory install form is published for a portable package." - }, - "discovery": { - "required": [ - "plugin.json", - "skills", - "mcp.json" - ], - "shadowedBy": [], - "evidence": [ - "2026-09-06: https://hermes-agent.nousresearch.com/docs/developer-guide/plugins/ states \"Portable packages use root plugin.json in the same locations\" as native packages (~/.hermes/plugins//) and \"Anything deeper is ignored\".", - "2026-09-06: the only documented install spec for a portable package is `hermes plugins install owner/repository`; no local-directory install form is published, so installing the emitted directory in place is unproven.", - "2026-09-06: the same page scopes the whole tier — \"This is a compatibility adapter for the portable components Hermes already owns… an explicit supported subset, not a claim of full Agent Plugins conformance.\"" - ] - }, - "surfaces": { - "manifest": { - "evidence": [ - "2026-09-06: \"Hermes validates plugin.json, Agent Skills frontmatter, fixed component locations, mcp.json, resolved paths, and symlink containment locally. It does not fetch JSON schemas while loading a package\", and it \"keys behavior on the canonical v1.0.0 schema identifiers and normative text\" — the identifiers this projection emits." - ], - "reason": "2026-09-06: the validation rule set is not published: the page never states that the manifest root is treated as closed or what happens to an unknown root key.", - "state": "degraded" - }, - "skills": { - "evidence": [ - "2026-09-06: \"An enabled package may provide immediate skills/*/SKILL.md directories\" — the flat layout this projection emits — and \"A bad skill or MCP entry is skipped at its own boundary\"." - ], - "state": "supported" - }, - "mcp": { - "evidence": [ - "2026-09-06: the same page reads stdio MCP servers from the root mcp.json and supports stdio and streamable-http, the only two transports this projection emits; the standard's legacy sse form is documented as not supported, and the compiler never emits it." - ], - "state": "supported" - }, - "placeholders": { - "evidence": [ - "2026-09-06: the page states both reserved variables are provided to stdio servers and that a command is run as \"one executable token … never through a shell\", which is the containment this projection emits." - ], - "reason": "2026-09-06: the expansion sites are unpublished — the page does not say whether ${PLUGIN_ROOT} and ${PLUGIN_DATA} are expanded in args, env values, and cwd as §9.1 requires, only that the variables are provided.", - "state": "degraded" - }, - "hooks": { - "reason": "2026-09-06: Hermes runs hooks from native plugin.yaml plus register(ctx) Python plugins, which the portable tier explicitly does not replace; Agent Plugins 1.0.0 defines no hooks, so this projection emits no hooks document either.", - "state": "unavailable" - } - } - }, - "opencode": { - "name": "OpenCode", - "issue": 693, - "observed": "opencode-ai 1.18.29 exercised 2026-09-06; opencode.ai/docs retrieved 2026-09-06", - "tier": "skills", - "install": { - "source": "local-directory", - "actions": [ - { - "role": "install", - "command": "cp -R skills/ .agents/skills/" - } - ], - "location": ".agents/skills// (project) or ~/.agents/skills// (global)" - }, - "discovery": { - "required": [ - "skills" - ], - "shadowedBy": [], - "evidence": [ - "2026-09-06: https://opencode.ai/docs/skills/ lists six skill roots verbatim, including \"Project agent-compatible: .agents/skills//SKILL.md\" and \"Global agent-compatible: ~/.agents/skills//SKILL.md\", so the emitted skill directories load once copied into either root.", - "2026-09-06: `opencode plugin /tmp/hostcli/fixture` on 1.18.29 failed with \"Plugin directory /tmp/hostcli/fixture is missing package.json or index file\" — an OpenCode plugin is an npm module, so the emitted package is not an install unit for it.", - "2026-09-06: `opencode mcp list` on 1.18.29 reported \"No MCP servers configured\" after that attempt: the emitted mcp.json was never consulted." - ] - }, - "surfaces": { - "manifest": { - "reason": "2026-09-06: `opencode plugin ` requires a package.json or index file and refused the emitted package on 1.18.29; OpenCode reads no root plugin.json.", - "state": "unavailable" - }, - "skills": { - "evidence": [ - "2026-09-06: https://opencode.ai/docs/skills/ requires frontmatter `name` matching `^[a-z0-9]+(-[a-z0-9]+)*$` and the containing directory name, plus a `description` of 1–1024 characters, and states \"Unknown frontmatter fields are ignored\" — every field the pinned Agent Skills lowering emits is either read or ignored." - ], - "reason": "2026-09-06: the skill tree must be copied into one of OpenCode's own roots; the emitted package as a whole is not an OpenCode install unit, and skill names must be unique across all roots (\"Ensure skill names are unique across all locations\").", - "state": "degraded" - }, - "mcp": { - "reason": "2026-09-06: https://opencode.ai/docs/mcp-servers/ configures servers under the `mcp` key of opencode.json with OpenCode's own `type: \"local\" | \"remote\"` shape and a `command` array, not a standalone mcp.json with the standard's `stdio` and `streamable-http` types.", - "state": "unavailable" - }, - "placeholders": { - "reason": "2026-09-06: OpenCode substitutes {env:VAR} and {file:path} in its own configuration; it documents no expansion of the reserved ${PLUGIN_ROOT} and ${PLUGIN_DATA} of Agent Plugins 1.0.0 §9.1, and no emitted document carrying them is read.", - "state": "unavailable" - }, - "hooks": { - "reason": "2026-09-06: OpenCode's event hooks are JavaScript functions returned by a plugin module (https://opencode.ai/docs/plugins/); Agent Plugins 1.0.0 defines no hooks, and this projection emits no plugin module for it to load.", - "state": "unavailable" - } - } - }, - "kiro-powers": { - "name": "Kiro (Powers)", - "issue": 707, - "observed": "kiro.dev/docs/powers pages updated September 2, 2026 and August 4, 2026, retrieved 2026-09-06", - "tier": "agent-plugins", - "install": { - "source": "local-directory", - "actions": [ - { - "role": "install", - "command": "Powers panel -> Add Custom Power -> Import power from a folder -> select -> Install" - } - ], - "location": "Kiro's own power store; the IDE, CLI, and Web tabs share the same import flow" - }, - "discovery": { - "required": [ - "plugin.json", - "skills", - "mcp.json" - ], - "shadowedBy": [], - "evidence": [ - "2026-09-06: https://kiro.dev/docs/powers/ states \"A power is a directory with a required manifest and optional components: 1. plugin.json … 2. skills/ — Agent Skills … 3. mcp.json — MCP server configuration for tool integrations (optional) 4. dev.kiro/\", which is the emitted layout with an optional Kiro-only directory this projection does not write.", - "2026-09-06: https://kiro.dev/docs/powers/installation/ states \"Each power must have a valid plugin.json or POWER.md file at its package root\" and selects the format by manifest filename, not by the $schema value." - ] - }, - "surfaces": { - "manifest": { - "evidence": [ - "2026-09-06: https://kiro.dev/docs/powers/create/ lists $schema with the canonical value https://agent-plugins.org/schemas/1.0.0/plugin.schema.json among its required fields, and its optional list (homepage, repository, license) matches the closed 1.0.0 root; no Kiro key appears at the manifest root." - ], - "reason": "2026-09-06: Kiro's \"Required fields\" table additionally requires version, description, author, and keywords, where the canonical schema requires only $schema and name — so a bundle that declares no portable author or keywords metadata does not meet Kiro's tightened manifest, and Kiro publishes no validation-error behavior to say what happens then.", - "state": "degraded" - }, - "skills": { - "evidence": [ - "2026-09-06: https://kiro.dev/docs/powers/ documents skills//SKILL.md with a references/ subdirectory, the exact tree this projection emits, and https://kiro.dev/docs/skills/ governs the frontmatter it validates." - ], - "state": "supported" - }, - "mcp": { - "evidence": [ - "2026-09-06: https://kiro.dev/docs/powers/ reads MCP server configuration from the power-root mcp.json, and https://kiro.dev/docs/mcp/ documents the stdio form this projection emits." - ], - "reason": "2026-09-06: only stdio is documented for a power's mcp.json; no Kiro page states that a streamable-http server in that file is read, so an emitted remote server is unproven there.", - "state": "degraded" - }, - "placeholders": { - "reason": "2026-09-06: no Kiro page documents ${PLUGIN_ROOT} or ${PLUGIN_DATA} expansion, or the provision of those variables to a power's MCP subprocess, so the reserved behavior of Agent Plugins 1.0.0 §9.1 is unproven there.", - "state": "unavailable" - }, - "hooks": { - "reason": "2026-09-06: https://kiro.dev/docs/hooks/ documents Kiro's own hook configuration; Agent Plugins 1.0.0 defines no hooks, so this projection emits no hooks document for it to read.", - "state": "unavailable" - } - } - }, - "pi": { - "name": "Pi", - "issue": 694, - "observed": "npm probed 2026-09-06; no installable release exists", - "tier": "none", - "discovery": { - "required": [], - "shadowedBy": [], - "evidence": [ - "2026-09-06: `npm view @earendil-works/pi version` returned \"npm error 404\", and `pi-coding-agent@0.0.1` is a \"Placeholder package name reservation for pi-coding-agent\" with no `bin` field, so no Pi executable is installable from npm under either name and nothing about Pi's handling of this artifact can be exercised.", - "2026-09-06: the documented content contract (project and global `.agents/skills/`, `AGENTS.md`) is recorded in issue #694; it is not recorded here as a loaded surface because no release exists to prove it against." - ] - }, - "surfaces": { - "manifest": { - "reason": "2026-09-06: no installable Pi release exists on npm, so no manifest handling can be established.", - "state": "unavailable" - }, - "skills": { - "reason": "2026-09-06: unproven. Pi's repository documents project and global `.agents/skills/` roots, but no installable release exists to exercise the emitted skill tree against.", - "state": "unavailable" - }, - "mcp": { - "reason": "2026-09-06: Pi's own documentation states it has no MCP support at all, so the emitted mcp.json has no reader there.", - "state": "unavailable" - }, - "placeholders": { - "reason": "2026-09-06: with no document of this artifact read, no placeholder of Agent Plugins 1.0.0 §9.1 is expanded.", - "state": "unavailable" - }, - "hooks": { - "reason": "2026-09-06: Agent Plugins 1.0.0 defines no hooks, so this projection emits no hooks document for Pi to read.", - "state": "unavailable" - } - } - }, "vs-code": { "name": "VS Code (Copilot agent plugins)", "issue": 706, @@ -1751,14 +1243,13 @@ }, "discovery": { "required": [ - "mcp.json", "skills" ], "shadowedBy": [], "evidence": [ "2026-09-06: https://swival.dev/pages/skills.html publishes the discovery order — \".swival/skills/ — Swival-specific project skills (highest precedence)\", \".agents/skills/ — common cross-agent standard\", \"--skills-dir paths — explicit extra directories\", then the two global roots — and states \"Every immediate subdirectory that contains SKILL.md is treated as a skill\", which is the shape this projection emits under skills/.", "2026-09-06: the same page states \"Each --skills-dir path can point directly at one skill directory that contains SKILL.md, or at a parent directory where nested subdirectories contain skill files\", so the emitted skills/ directory is read in place with no copy.", - "2026-09-06: https://swival.dev/pages/mcp.html states \"--mcp-config FILE provides an explicit path to an MCP JSON config file. When set, this replaces the default .swival/mcp.json lookup\", so the emitted mcp.json is read only when it is named explicitly.", + "2026-09-06: https://swival.dev/pages/mcp.html states \"--mcp-config FILE provides an explicit path to an MCP JSON config file. When set, this replaces the default .swival/mcp.json lookup\", and publishes the JSON shape it reads — \"mcpServers\" mapping a name to command/args/env for stdio or url/type/headers for HTTP — which is the document this projection emits.", "2026-09-06: no page documents a plugin manifest, a package layout, or an install form that reads a root plugin.json, so nothing here claims one." ] }, @@ -1771,14 +1262,12 @@ "evidence": [ "2026-09-06: https://swival.dev/pages/skills.html requires exactly what this projection emits — a directory per skill containing SKILL.md whose frontmatter carries `name` and `description`, with \"The name field must be lowercase alphanumeric with hyphens, must match the directory name\" — and reads an extra parent directory named with --skills-dir." ], - "state": "supported" + "state": "degraded", + "reason": "2026-09-06: the emitted skills/ root is not a default location, so it loads only once registered with --skills-dir or the swival.toml skills_dir field, and it loses by name to the default roots: \"If the same skill name exists in multiple locations, the first one in the precedence order wins\", with .swival/skills/ and .agents/skills/ ahead of --skills-dir paths. A registered tree outside the project resolves as external, which Swival adds \"as read-only roots\"." }, "mcp": { - "evidence": [ - "2026-09-06: https://swival.dev/pages/mcp.html states \".swival/mcp.json ... uses the same format as other MCP-compatible tools\" with \"command, args, env for stdio, and url, headers for SSE\", and that an explicit file is read with --mcp-config FILE." - ], - "reason": "2026-09-06: the emitted document is read only when it is passed as --mcp-config /mcp.json, and only two transports are documented — \"Each server needs either command (for stdio transport) or url (for SSE transport), but not both\". No page states what Swival does with the spec's `type` discriminator or with a streamable-http server, and a TOML server of the same name \"always win[s] by server name over JSON servers\".", - "state": "degraded" + "reason": "2026-09-06: MCP servers come from swival.toml [mcp_servers.*] or .swival/mcp.json (https://swival.dev/pages/mcp.html). The emitted document is a shape Swival reads, but only an invocation that passes --mcp-config at it reads this one — the flag \"replaces the default .swival/mcp.json lookup\" rather than adding to it, and \"TOML servers (swival.toml [mcp_servers.*]) always win by server name over JSON servers\" — and the registration recorded here does not, so this record claims no Swival MCP source.", + "state": "unavailable" }, "placeholders": { "reason": "2026-09-06: no ${PLUGIN_ROOT} or ${PLUGIN_DATA} expansion is documented for Swival MCP configuration, and the documented substitution surface is the skill body and its own directory path, so the reserved behavior of Agent Plugins 1.0.0 §9.1 is not provided.", diff --git a/packages/agent-bundle/tests/install-surface.test.ts b/packages/agent-bundle/tests/install-surface.test.ts index 6bfb0595d..ba1a6f8e2 100644 --- a/packages/agent-bundle/tests/install-surface.test.ts +++ b/packages/agent-bundle/tests/install-surface.test.ts @@ -205,9 +205,10 @@ it.each([ { agentPlugins: 'installs this bundle as one plugin. Reads: `plugin.json`, `skills`.', inventory: 'skills only', - swivalPartial: false, + swivalPartial: true, swivalTier: 'loads the components it recognizes without reading the manifest. Reads: `skills`.' - + ' Register: `swival --skills-dir /skills ""`.', + + ' Register: `swival --skills-dir /skills ""`.' + + ' Not loaded: manifest, mcp, placeholders, hooks.', mcpServers: [], skills: [portableSkill], skillsTier: 'loads the components it recognizes without reading the manifest. Reads: `skills`.' @@ -216,9 +217,11 @@ it.each([ { agentPlugins: 'installs this bundle as one plugin. Reads: `mcp.json`, `plugin.json`.', inventory: 'MCP only', - swivalPartial: true, - swivalTier: 'loads the components it recognizes without reading the manifest. Reads: `mcp.json`.' - + ' Register: `swival --skills-dir /skills ""`.', + swivalPartial: false, + // Swival's registration hands over the skill tree alone, so an MCP-only + // bundle carries nothing it reads and gets no command. + swivalTier: 'loads the components it recognizes without reading the manifest. This bundle emits none of' + + ' the paths it reads, so there is nothing to install there.', mcpServers: [portableServer], skills: [], skillsTier: 'loads the components it recognizes without reading the manifest. Reads: `mcp.json`.' @@ -228,8 +231,9 @@ it.each([ agentPlugins: 'installs this bundle as one plugin. Reads: `mcp.json`, `plugin.json`, `skills`.', inventory: 'skills and MCP', swivalPartial: true, - swivalTier: 'loads the components it recognizes without reading the manifest. Reads: `mcp.json`, `skills`.' - + ' Register: `swival --skills-dir /skills ""`.', + swivalTier: 'loads the components it recognizes without reading the manifest. Reads: `skills`.' + + ' Register: `swival --skills-dir /skills ""`.' + + ' Not loaded: manifest, mcp, placeholders, hooks.', mcpServers: [portableServer], skills: [portableSkill], skillsTier: 'loads the components it recognizes without reading the manifest. Reads: `mcp.json`, `skills`.' @@ -250,8 +254,8 @@ it.each([ // build did not write is not a limit here. expect(install).toContain('- **Swival** (docs retrieved 2026-09-06; no product version is published on' + ` the documentation pages) ${expected.swivalTier}`); - const partial = ' - Partial `mcp`: 2026-09-06: the emitted document is read only when it is passed as' - + ' --mcp-config /mcp.json'; + const partial = ' - Partial `skills`: 2026-09-06: the emitted skills/ root is not a default location,' + + ' so it loads only once registered with --skills-dir'; if (expected.swivalPartial) expect(install).toContain(partial); else expect(install).not.toContain(partial); // A client that reads nothing says so whatever the bundle carries. diff --git a/packages/agent-bundle/tests/portable-adapter.test.ts b/packages/agent-bundle/tests/portable-adapter.test.ts index 693d8ec88..80f65cb12 100644 --- a/packages/agent-bundle/tests/portable-adapter.test.ts +++ b/packages/agent-bundle/tests/portable-adapter.test.ts @@ -697,6 +697,21 @@ it('emits the artifact paths every recorded client reads, and none of the manife expect(clients.find((client) => client.id === 'antigravity')?.discovery.required).toEqual([]); }); +it('records every client once, since JSON keeps only the last of a repeated key', async () => { + // A record added twice is not a duplicate that a reader can spot: the parser + // drops every copy but the last, so the earlier one is text nothing reads. + const source = await readFile( + new URL('../src/adapters/capabilities/portable-1.0.0.json', import.meta.url), + 'utf8', + ); + const block = source.slice(source.indexOf('\n "clients": {')); + const authored = [...block.slice(0, block.indexOf('\n },')).matchAll(/^ {4}"([a-z0-9-]+)": \{$/gmu)] + .map((match) => match[1]!); + + expect([...authored].sort((left, right) => left.localeCompare(right))) + .toEqual(clientCompatibilityFrom('portable', capabilityTable.clients).map((client) => client.id)); +}); + it('refuses a client record that claims a tier its own rows do not support', () => { const record = (overrides: Record) => ({ demo: {