Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/claude-capability-repin-2-1-260.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"agent-bundle": patch
---

Re-pin the `claude` host contract from Claude Code 2.1.250 to 2.1.260 (`observedCliVersion`, `hostCli.version`, the `claude-2.1.260.json` capability table, and every `schemas/claude/*` snapshot; Claude `adapterRevision` `1.28.0`, composite `plugin` `1.29.0`). Add the `model-switch/before` and `model-switch/after` canonical event-route families (`src/events/model-switch/before.tsx`, `.../after.tsx`): on Claude Code they compile to `PreModelSwitch` and `PostModelSwitch` (2.1.251 or later), a decided `model-switch/before` projects `outcome: 'allow' | 'ask' | 'deny'` to `hookSpecificOutput.permissionDecision` with the reason as `permissionDecisionReason`, `model-switch/after` is observation-only with `Agent.Context` delivered as `additionalContext`, and Codex, Cursor, and portable carry dated `unavailable` rows. `hooks.schema.json` now admits `PreModelSwitch` and `PostModelSwitch` (`command`, `http`, `mcp_tool` handlers) in a `claude.nativeHooks` document. `build`, `validate --artifact`, and `doctor` request `claude plugin validate --strict --json` first and fall back to the text reporter only when the CLI rejects the flag, so a CLI of unknown version no longer skips the JSON report. The Claude agents capability rows record that 2.1.260 `--strict --json` accepts `color`, `initialPrompt`, and `experimental.cacheTtl` without validating their values; the agents component stays deferred. (#542)
10 changes: 5 additions & 5 deletions docs/canvases/agent-bundle-walkthrough.canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ const WIRE_IPC_REQUEST = `{
"protocolVersion": 1,
"artifactEpoch": "17903a885df8d142e2fc4457e61bb34479e81a8f4cc64e24cb92db49eaabe3f1",
"event": "tool/before",
"hostContractRevision": "2.1.250",
"hostContractRevision": "2.1.260",
"target": "claude",
"native": { ...the validated stdin envelope, value-preserving (re-serialized JSON, not raw bytes)... }
}
Expand All @@ -287,7 +287,7 @@ const WIRE_RENDER_PROPS = `props = {
event: "tool/before",
idempotencyKey: sha256({ event, native, target }),
observedAt: "2026-09-01T23:41:07.512Z",
provenance: { host: "claude", hostContractRevision: "2.1.250",
provenance: { host: "claude", hostContractRevision: "2.1.260",
nativeEvent: "PreToolUse", source: "native" },
sequence: 1,
},
Expand Down Expand Up @@ -499,7 +499,7 @@ export default function AgentBundleWalkthrough() {
silent guess.
</Text>
<Table
headers={["Surface", "Claude 2.1.250", "Codex 0.147.0", "Cursor 2026-08-28", "Portable 1.0.0"]}
headers={["Surface", "Claude 2.1.260", "Codex 0.147.0", "Cursor 2026-08-28", "Portable 1.0.0"]}
columnAlign={["left", "left", "left", "left", "left"]}
rows={[
["Plugin manifest",
Expand Down Expand Up @@ -735,7 +735,7 @@ else try { output = await requestEventRuntime({ ... }); }
Codex — with a written reason per host, not a silent gap.
</Text>
<Table
headers={["Canonical event", "Claude 2.1.250", "Codex 0.147.0", "Cursor 2026-08-28", "Portable 1.0.0"]}
headers={["Canonical event", "Claude 2.1.260", "Codex 0.147.0", "Cursor 2026-08-28", "Portable 1.0.0"]}
rowTone={["success", "success", "success", "success", "success", "success", "warning"]}
rows={[
[<Text as="span" style={{ fontFamily: MONO }} size="small">session/start</Text>, "SessionStart", "SessionStart", "sessionStart", "—"],
Expand Down Expand Up @@ -963,7 +963,7 @@ agent-bundle install cursor --from artifact/cursor # staged copy`}
docs/framework-mode.md · examples/&#123;hooks-and-scripts,audiobook-curator,rsc-agent-runtime&#125;.
Wire payloads in section 4 are illustrative values over verified shapes. Reflects the
post-PR-#280 split of React rendering (events/project.ts) from envelope projection
(events/projection.ts). Host capability facts pinned at Claude Code 2.1.250, Codex
(events/projection.ts). Host capability facts pinned at Claude Code 2.1.260, Codex
0.147.0, Cursor 2026-08-28, Agent Plugins 1.0.0 (observed 2026-08-28 … 2026-09-01).
</Text>
<Text size="small" tone="quaternary">
Expand Down
9 changes: 5 additions & 4 deletions docs/diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,11 @@ first, which covers `plugin.json`, `hooks/hooks.json`, and the `skills/`,
`agents/`, and `commands/` directories, and then
`claude plugin validate <dir>/.claude-plugin/marketplace.json --strict`, dropping
the marketplace run's `plugins[N] plugin.json →` copies of manifest findings the
plugin run already reported. On Claude Code 2.1.259 or later both runs add
`--json` and each finding is attributed to its file (`generatedPath`); older
releases fall back to the text report, attributed by its `Validating <type>:
<file>` headers.
plugin run already reported. Both runs ask for `--json` first (Claude Code
2.1.259 or later; the pinned 2.1.260 prints it) and each finding is attributed
to its file (`generatedPath`); when the CLI rejects the flag (`unknown option
'--json'`) or the probed version predates 2.1.259, the runs fall back to the
text report, attributed by its `Validating <type>: <file>` headers.

`claude plugin validate --strict` is not a load verdict: Claude Code 2.1.250
through 2.1.260 accept manifests and component files (for example an invalid
Expand Down
2 changes: 1 addition & 1 deletion docs/framework-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ and `agent-bundle inspect` reports the judgment per target (see
[component accounting](entry-conventions.md#agent-bundle-inspect-component-accounting)).
A host with no row for a kind reads as an honest `unavailable`, never a silent
pass. The matrix below is the state of the pinned tables (Claude Code
2.1.250, Codex 0.147.0, Cursor 2026-08-28, Agent Plugins 1.0.0); the JSON
2.1.260, Codex 0.147.0, Cursor 2026-08-28, Agent Plugins 1.0.0); the JSON
tables under `packages/agent-bundle/src/adapters/capabilities/` carry the
evidence strings themselves.

Expand Down
4 changes: 3 additions & 1 deletion examples/rsc-agent-runtime/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ Host/Origin allowlists mitigate DNS rebinding and cross-origin requests, but the

### Semantic event-route support

| Event family | Cursor | Claude Code 2.1.250 | Codex 0.147.0 |
| Event family | Cursor | Claude Code 2.1.260 | Codex 0.147.0 |
| --- | --- | --- | --- |
| `session/start` | Supported | `SessionStart` | `SessionStart` |
| `session/end` | `sessionEnd` (observe-only; desktop only) | `SessionEnd` (observe-only) | `SessionEnd` (observe-only) |
Expand All @@ -246,6 +246,8 @@ Host/Origin allowlists mitigate DNS rebinding and cross-origin requests, but the
| `task/create` | Unavailable | `TaskCreated` (deny) | Unavailable |
| `task/complete` | Unavailable | `TaskCompleted` (observe-only; blocking is exit-code-only) | Unavailable |
| `agent/idle` | Unavailable | `TeammateIdle` (deny via continue:false) | Unavailable |
| `model-switch/before` | Unavailable | `PreModelSwitch` (allow/ask/deny; 2.1.251+) | Unavailable |
| `model-switch/after` | Unavailable | `PostModelSwitch` (observe-only + context; 2.1.251+) | Unavailable |
| `agent/start` | `subagentStart` (deny via `permission: "deny"`; no context channel) | `SubagentStart` (context) | `SubagentStart` (context) |
| `agent/stop` | `subagentStop` (deny via `followup_message`; no context channel) | `SubagentStop` (deny + context) | `SubagentStop` (deny) |
| `workspace/open` | Supported (observe-only; native `pluginPaths` return not modeled) | Unavailable | Unavailable |
Expand Down
2 changes: 1 addition & 1 deletion examples/rsc-agent-runtime/scripts/eval-hosts.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { sanitizedHostEnvironment } from './eval-host-environment.mjs';
import { exampleRootFromModule } from './eval-host-paths.mjs';

const exampleRoot = exampleRootFromModule(import.meta.url);
const expectedVersions = { claude: '2.1.250', codex: '0.147.0' };
const expectedVersions = { claude: '2.1.260', codex: '0.147.0' };

const parseHost = (argv) => {
const hostIndex = argv.indexOf('--host');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"marketplace": ".claude-plugin/marketplace.json",
"mcp": ".mcp.json"
},
"observedCliVersion": "2.1.250",
"observedCliVersion": "2.1.260",
"pathTokens": {
"pluginData": "${CLAUDE_PLUGIN_DATA}",
"pluginRoot": "${CLAUDE_PLUGIN_ROOT}",
Expand Down
102 changes: 95 additions & 7 deletions packages/agent-bundle/fixtures/contracts/claude/cli-help.txt
Original file line number Diff line number Diff line change
@@ -1,26 +1,114 @@
version: 2.1.250
version: 2.1.260

$ claude plugin --help
Usage: claude plugin|plugins [options] [command]

Manage Claude Code plugins

Options:
-h, --help Display help for command

Commands:
details [options] <name> Show a plugin's component inventory and projected token cost
install|i [options] <plugin> Install a plugin from available marketplaces
details [options] <name> Show a plugin's component inventory and
projected token cost
disable [options] [plugin] Disable an enabled plugin
enable [options] <plugin> Enable a disabled plugin
eval [options] [target] Run eval cases (<eval dir>/**/case.yaml
or prompt.md + graders/*.md; the eval dir
is evals/ unless --eval-dir or the
manifest says otherwise) against a plugin
and report scored results. Target is a
path, a plugin name, or a
`plugin@marketplace` id — installed and
skills-dir plugins both resolve (and add
a no-plugin baseline arm)
help [command] display help for command
init|new [options] <name> Scaffold a new plugin at
~/.claude/skills/<name>/ (auto-loads next
session as <name>@skills-dir)
install|i [options] <plugin> Install a plugin from available
marketplaces (use plugin@marketplace for
specific marketplace)
list [options] List installed plugins
marketplace Manage Claude Code marketplaces
validate [options] <path> Validate a plugin or marketplace manifest
prune|autoremove [options] Remove auto-installed dependencies that
are no longer needed
tag [options] [path] Create a {name}--v{version} git tag for a
plugin release, validating that
plugin.json and any enclosing marketplace
entry agree
uninstall|remove [options] <plugin> Uninstall an installed plugin
update [options] <plugin> Update a plugin to the latest version
(restart required to apply)
validate [options] <path> Validate a plugin or marketplace
manifest, or the skills, agents, and
commands in a directory
$ claude plugin validate --help
Usage: claude plugin validate [options] <path>

Validate a plugin or marketplace manifest, or the skills, agents, and commands
in a directory

Options:
-h, --help Display help for command
--json Output the validation report as JSON (same exit codes)
--strict Treat warnings as errors (exit 1). Use in CI to fail on
unrecognized fields, missing metadata, and other issues that the
runtime tolerates.
$ claude plugin list --help
Usage: claude plugin list [options]

List installed plugins

Options:
--available Include available plugins from marketplaces (requires --json)
-h, --help Display help for command
--json Output as JSON
$ claude plugin marketplace --help
Usage: claude plugin marketplace [options] [command]

Manage Claude Code marketplaces

Options:
-h, --help Display help for command

Commands:
add [options] <source> Add a marketplace from a URL, path, or GitHub repo
help [command] display help for command
list [options] List all configured marketplaces
remove|rm [options] <name> Remove a configured marketplace
update [options] [name] Update marketplace(s) from their source - updates
all if no name specified
$ claude mcp add --help
Usage: claude mcp add [options] <name> <commandOrUrl> [args...]

Add an MCP server to Claude Code.

Examples:
# Add HTTP server:
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp

# Add HTTP server with headers:
claude mcp add --transport http corridor https://app.corridor.dev/api/mcp
--header "Authorization: Bearer ..."

# Add stdio server with environment variables:
claude mcp add my-server -e API_KEY=xxx -- npx my-mcp-server

# Add stdio server with subprocess flags:
claude mcp add my-server -- my-command --some-flag arg1

Options:
-e, --env <env...> Set environment variables
-H, --header <header...> Set WebSocket headers
-t, --transport <transport> Transport type (stdio, sse, http). Defaults to stdio if not specified.
--callback-port <port> Fixed port for OAuth callback (for servers
requiring pre-registered redirect URIs)
--client-id <clientId> OAuth client ID for HTTP/SSE servers
--client-secret Prompt for OAuth client secret (or set
MCP_CLIENT_SECRET env var)
-e, --env <env...> Set environment variables (e.g. -e KEY=value)
-H, --header <header...> Set headers for HTTP/SSE servers (e.g. -H
"X-Api-Key: abc123" -H "X-Custom: value")
-h, --help Display help for command
-s, --scope <scope> Configuration scope (local, user, or project)
(default: "local")
-t, --transport <transport> Transport type (stdio, sse, http). Defaults to
stdio if not specified.
Loading
Loading