Skip to content

fix(portable): correct the Copilot, CodeWhale, VS Code, and Hermes client records - #732

Merged
ScriptedAlchemy merged 4 commits into
mainfrom
portable-client-record-corrections
Sep 7, 2026
Merged

fix(portable): correct the Copilot, CodeWhale, VS Code, and Hermes client records#732
ScriptedAlchemy merged 4 commits into
mainfrom
portable-client-record-corrections

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Sep 7, 2026

Copy link
Copy Markdown
Owner

Closes #728.

Four record corrections on the pinned portable clients block, plus the rendered output they feed. No adapter, registry, or discovery interpreter changed; nothing about what the compiler writes changed.

Corrections

  1. GitHub Copilot CLI (Host support: GitHub Copilot CLI — native and Open Plugin Spec projection with verified discovery precedence #698)discovery.shadowedBy now records the two locations its published file-locations table puts ahead of the emitted tree, per surface: .plugin/plugin.json for manifest (the manifest order is .plugin/plugin.json, plugin.json, .github/plugin/plugin.json, .claude-plugin/plugin.json, so the emitted root still wins over the Claude manifest — asserted against the claude+portable composite) and .mcp.json for mcp (the table publishes MCP configuration as .mcp.json, .github/mcp.json; the emitted root mcp.json is proven only by the 1.0.83 probe, which ran with no .mcp.json present). Its mcp row is degraded: the probe listed one stdio server, and no streamable-http server was registered, launched, or authenticated. The local-install deprecation and the unspawned-server placeholders row stay visible.
  2. CodeWhale (Host support: CodeWhale — Agent Plugins bundles, hash-bound trust, skills, MCP, and TUI hook profile #709) — the narrowed mcp reason now covers the whole plugin boundary from the pinned MCP guide and the same commit's docs/PLUGIN_BUNDLES.md: HTTPS-or-loopback endpoints with no user information, query, or fragment; literal headers rejected in favor of env_headers/bearer_token_env_var; redirects held to the reviewed origin; and capabilities.network_hosts matching the normalized endpoint host set exactly. That declaration rides in extensions["net.codewhale"], which this projection writes only from an authored portable.extensions, and a remote server emitted without it is a validation error — "an active bundle must be … free of validation errors" — so the record says the bundle stays inactive there rather than loading with a narrowed surface. No new portable field, no relaxed trust policy.
  3. VS Code (Host support: Copilot editor/VS Code — Agent Plugins namespace, hooks, skills, instructions, and MCP #706)chat.pluginLocations carries the already-supported register role, matching the local-plugin documentation ("register it with the chat.pluginLocations setting … false to keep it registered but disabled"), so the generated instructions print Register:. Cline is asserted in the same test and unchanged: its cp -R action really copies, so install stays. The validator now refuses a register anchor against any non-local-directory source.
  4. Hermes (Host support: Hermes Agent — portable package conformance and optional native Python hooks #697)install.source is the new repository value: the plugin guide separates hermes plugins install <name> (index name, resolved to repo @ pinned ref) from hermes plugins install user/repo (from Git; "Explicit owner/repo or Git-URL identifiers never touch the index"). The recorded command keeps --no-enable, so the install still leaves the plugin disabled, and no local-directory form is claimed.

The install-source enum genuinely lacked Git, so it gained one value (repository) — the smallest compatible metadata addition. Non-local install prose names its source (Install from a marketplace … / Install from a Git repository …), the agent-plugins tier sentence says a client loads the bundle (the recorded action alone reports whether it copies or registers), and the generated host reference gains an install-source column in both locales.

Tests

  • packages/agent-bundle/tests/portable-adapter.test.ts: a record test holding each correction to its pinned source (both shadowed surfaces, the quoted file-locations rows, stdio-only evidence, CodeWhale's remote restrictions, register vs install role, repository source), plus validator coverage that repository is accepted, git is refused, and a register action against a repository source is refused.
  • packages/agent-bundle/tests/install-surface.test.ts: a four-row inventory matrix (no component, skills only, MCP only, skills and MCP) asserting the whole rendered line per client — tier sentence, paths this build wrote, action role, source, Not loaded list, both .plugin/plugin.json and .mcp.json hypotheticals — and asserting the MCP narrowings (Copilot's stdio subset and unspawned server, CodeWhale's endpoint/header/secret-URL/redirect clauses and inactive-bundle consequence) appear only when the build wrote mcp.json. The composite test asserts Copilot still reads the root manifest with .claude-plugin/plugin.json present, hands mcp to the build's .mcp.json, and prints neither MCP-document narrowing there.
  • Generated en/zh reference verified through pnpm docs:site:build: install-source column, repository for Hermes, register for VS Code, install for Cline, .plugin/plugin.json (manifest) and .mcp.json (mcp) shadow cells, both intro rewrites.

Local gate

Run on this branch, which contains current origin/main (b5cf7575e0):

  • pnpm build — pass
  • pnpm typecheck — pass
  • pnpm lint — pass (1483 files)
  • pnpm test:unit — pass, 4439 passed / 0 failed / 6 skipped (a first run under a machine load average of 300 timed out in seven unrelated timing-sensitive tests — codex-plugin-validation, event-ipc, install, mcp-probe-service, uninstall, two web-host-routes-unit; re-run clean once load dropped)
  • pnpm docs:site:build — pass, language parity checked, 0 broken links / 28329 anchors
  • Touched files re-run after every edit round: install-surface, portable-adapter, adapter-capability-states, adapter-metadata

No native client was executed for this change; the corrections are document review over pinned sources.

Deslop

Deslop: claude-opus-5, 3 edits (helper reduced to the source sentence it prints, CodeWhale reason held to the upstream wording, remote-form quote pinned in evidence instead of paraphrased in the reason).

Self-review

Reviewers: claude-fable-5-1-thinking-high (change-risk-reviewer, two rounds) and gpt-5.6-sol-max (two rounds).

Fable, round 1:

  1. Copilot's new file-locations evidence claimed the published order covered skills and mcp.json, and the composite assertion locked in an unproven mcp.json read beside .mcp.jsonfixed: the evidence quotes the table's own rows, scopes the root mcp.json read to the probe that ran without .mcp.json, and the record gained the .mcp.jsonmcp shadow; the composite assertion now expects plugin.json, skills.
  2. CodeWhale's reason understated a validation failure as a missing declarationfixed: it now states the bundle fails validation and stays inactive.
  3. register with a non-local source would render as an installfixed: validator guard plus a negative test.
  4. Changeset trailer cited the issuefixed: (#732).
  5. Wrong GitHub anchor in the CodeWhale citationfixed: #plugin-contributed-mcp.

Sol, round 1:

  1. The agent-plugins tier sentence said "installs this bundle", contradicting the register actionfixed: "loads this bundle as one plugin".
  2. The generated-reference intro said every install copies the artifact, though a skills-tier install copies one componentfixed in both locales.
  3. No regression test for the generated reference outputdismissed, and Sol accepted the dismissal ("proportionate"), as did Fable: the unit glob is packages/**/tests/**, so reaching website/plugins/generated-reference.ts needs a test-only export of renderHosts or a cross-workspace import; website/docs/*/reference/hosts.md is generated and gitignored, and AGENTS.md designates pnpm docs:site:build as its gate. That gate passes, and both locales' rendered rows were verified directly.
  4. Incomplete per-client clause coveragefixed: the matrix asserts CodeWhale's endpoint/header/secret-URL/redirect clauses, the inactive-bundle consequence, and Copilot's unspawned-server row.

Round 2: Fable confirmed all five findings resolved with no new risk from the tier rename or the new shadow. Sol confirmed 1, 2 and 4 fixed and asked for one more composite assertion (Copilot's placeholders narrowing suppressed once .mcp.json takes mcp) — added in d9cfb26af4.

…ient records

Copilot CLI records .plugin/plugin.json as the one manifest location its
published order puts ahead of the emitted root, and narrows its mcp row to
the listed stdio server the probe proved. CodeWhale's mcp row names the
remote endpoint, header, secret-URL, redirect, and capabilities.network_hosts
restrictions its plugin boundary imposes, and where that declaration has to
ride. VS Code's chat.pluginLocations action takes the register role, since it
loads the directory in place; Cline keeps install, because its action copies
the tree. Hermes records the new repository install source for a Git
owner/repository install that leaves the plugin disabled.
@changeset-bot

changeset-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d9cfb26

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
agent-bundle Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 7, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-07T04:00:15.400768Z 57405f9 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

…lure to their sources

The published file-locations table covers the manifest order alone: skills
default to skills/ and MCP configuration is .mcp.json or .github/mcp.json, so
.mcp.json is recorded as taking the MCP surface and the emitted root mcp.json
stays proven only by the probe that ran without it. A CodeWhale bundle whose
remote endpoint has no matching capabilities.network_hosts fails validation
rather than loading with a narrowed MCP surface, and a register action is now
refused against anything but a local directory.

@ScriptedAlchemy ScriptedAlchemy left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated-head review — be5eef842c9e5b7240177f3eed468aa3b28e6005

Reviewed the initial seven-file diff at 57405f9307 and the additional correction commit be5eef842c that arrived during the review. One P2 discovery-claim correction remains; the other requested record changes are materially addressed. Source, test and first-party documentation review only; no native clients or repository tests were executed by this reviewer.

P2 — A winning manifest can redirect components; do not promise that it shadows only metadata

Files: portable-1.0.0.json, clients.copilot-cli.discovery.shadowedBy; install/surface.ts, clientLine; install-surface.test.ts.

The record marks .plugin/plugin.json as taking only manifest. The renderer and new tests then promise that the winning manifest leaves the other root components readable, including the sentence uses it for manifest and still reads the rest.

The official reference's component-path fields allow skills to select different directories and mcpServers to select another file or inline definitions. Its $schema field also determines whether the selected document opts into spec semantics. The file-location precedence order does not establish that an arbitrary higher-priority manifest preserves the lower portable manifest's component interpretation.

A concrete negative fixture is a composite root with its ordinary portable plugin.json, skills/ and mcp.json, plus this higher-priority .plugin/plugin.json and the referenced alternate components:

{
  "name": "override",
  "skills": "alternate-skills/",
  "mcpServers": "alternate-mcp.json"
}

The current record/rendering continues to claim the portable root's skill/MCP files on the basis of presence alone. This is a source/document-derived counterexample; I have not executed that fixture through Copilot. The documented overrides are enough to invalidate the unconditional promise.

Minimal correction: when a winning manifest has not been inspected/proven to preserve those bindings, withhold or qualify the affected component and placeholder claims. Reuse the existing shadow/qualification model; do not add a universal discovery interpreter or assume all foreign files shadow every surface. Keep a genuine per-file .mcp.json override separate from manifest-selected component paths. Preserve the correct lower precedence of .claude-plugin/plugin.json behind the root manifest.

Add an emitted-winning-manifest case to the rendered-output tests, not just a hypothetical sentence and a lower-priority Claude-manifest fixture. Test that an uninspected/overriding selected manifest cannot produce a guaranteed Reads: skills, mcp.json claim. Make the generated English/Chinese reference say the same thing.

Corrections now present — do not redo them

  • Hermes is a repository source with disabled-by-default installation retained.
  • VS Code is registration in place, while Cline's copy remains installation.
  • Copilot's evidence distinguishes a listed stdio configuration from executed/authenticated transport support.
  • CodeWhale's remote limits and missing network-host declaration now explicitly describe validation failure/whole-bundle inactivity, rather than silently promising a working degraded connection.
  • The additional commit adds .mcp.json handling, rejects non-local register actions, fixes the source anchor, and changes the changeset reference to #732.
  • Inventory-conditioned notes, the single capability validator, and shared generated reference remain the right architecture. No new native adapter is implied by these records. Aider/Jules remain excluded.

The PR's recorded full local gate and four-inventory tests are useful evidence, but they should be refreshed/identified for the final correction head. The earlier hosted query was queued/cancelled, not a reproduced code failure. This review does not add a requirement to wait for hosted CI instead of the repository's accepted local gates, and does not authorize a merge.

…all copies

The agent-plugins tier sentence said every such client installs the bundle,
which contradicted the register action VS Code actually publishes; the recorded
action now carries that distinction alone. The generated reference says an
install copies the artifact or the one component the client recognizes, since
a skills-tier install copies only that component. The inventory matrix asserts
CodeWhale's endpoint, header, secret-URL and redirect limits, its inactive-
bundle consequence, and Copilot's unspawned-server placeholder row.
@ScriptedAlchemy
ScriptedAlchemy merged commit 62e5c3a into main Sep 7, 2026
3 checks passed
@ScriptedAlchemy
ScriptedAlchemy deleted the portable-client-record-corrections branch September 7, 2026 04:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P2] Finish deferred portable-client record corrections from #723 without reopening native-adapter scope

1 participant