Contracts: bridge senders by object, closed empty schemas, raw method strings, typed acpmux params and _meta, open-remote --focus
Leo, 2026-11-05: "You guys keep running into these. These are weird issues that I feel like you should be able to just fix beforehand and check on beforehand."
The open follow-ups from #36260, #36265, #36579 and #36592, in one PR. Each check that stops a hand-named field from drifting across a boundary now covers the cases it missed.
Webview to Swift bridge (agentBridgeContract.test.ts)
- The scan also finds senders that arrive as object properties (
opts.send(...)), destructured parameters ({ post },{ send: s }, defaults included), and destructured locals (const { postNative: post } = deps). The self-test covers each shape, plus a daemon sender passed by object that it must not report. - On its first run it found
git.capabilitiesincheckpoints/controller.tsx, which no app serves. It is now listed underunservedinschemas/agent-bridge/contract.jsonwith the reason. The Swift test fails onceAgentPageOpsserves it.
Swift to acpmux (scripts/ci/check-swift-acpmux-protocol.py)
- A closed object schema with no properties (
additionalProperties: false) now allows no keys. Before, it allowed any key. - The Swift method list and
knownParamsare tokenized as Swift strings: raw (#"..."#), multiline ("""), and strings containing]or,. _meta.acpmuxkeys are checked against the new closedAcpmuxRequestMetatype in the spec. That coversknownParams' meta set and the pane's writes (acpmux["k"] =,setAcpmuxMeta,setDecision(field:)). The check fails if the spec has noAcpmuxRequestMeta.- acpmux (
protocol/params.rs): all 65 methods the app sends now have closed params schemas (63 were untyped). The keys come from each handler's reads.AcpmuxRequestMetalists the 68 keys acpmux reads fromparams._meta.acpmux. The IR and the webmethods.ts/types.tsare regenerated, so most of this diff is generated. Three new allowlist entries, each with its reason:noProjectis the pane's own key, stripped byAcpmuxPathPolicybefore sending.ownerCloudandfeaturesare reply keys thatRemoteAcpmuxWirewrites when it answersinitializeas the remote daemon.
CLI to app actions (cli/app.rs, action_argument_contract.rs)
cmux open-remote --focus [true|false]and--focus=falsenow reach the action's ownfocusargument. Before, only--arg focus=...reached it. The run's own focus follows the same value. An action without afocusargument keeps--focusas the run's focus only.open_remote_focus_reaches_the_actionpins those spellings.every_argument_named_like_a_cli_flag_reaches_its_actionchecks every argument an offered action takes whose--flagthe CLI also owns. Each one must reach the action through that flag, or be listed inGLOBAL_FLAG_ARGUMENTSwith the spelling that does reach it. Today four are listed:sessionon agent open, agent open-tab, remote connect and history resume, all reached with--arg session=orcmux action run ... --session. A new collision fails the test. So does a stale entry.cli-action-requests.jsonis regenerated: open-remote now sendsfocusthrough--focus.
After screenshots don't apply: this changes contract checks and the CLI's argument encoding only, with no UI.
Checks, all on fleet Linux:
- cmux-tui:
action_argument_contract6/6, clippy-D warningson cmux-tui and acpmux, fmt. - acpmux:
protocoltests. - Webviews: bridge contract 3/3, fmt.
check-swift-acpmux-protocol.pyon the repo, plus its 13 unit tests.
The review's follow-ups (multiline method literals in the app-wide scan; compression and any other request key missing from AcpmuxRequestMeta) are filed as follow-ups from the review receipt.
every_safe_transport_operation_has_a_noun_first_path (git.diff base/head) and root_help_lists_every_scope... (remote-host) fail the same way on base 424f297. They are not from this PR.
Takes back #28098: its untyped(method::…) registry line in acpmux/src/protocol/mod.rs is now keyed::<…Params>(method::…) with a closed params schema; the method, its kind and its handler are unchanged (the IR still lists all 292 methods).
Takes back #28859: its untyped(method::…) registry line in acpmux/src/protocol/mod.rs is now keyed::<…Params>(method::…) with a closed params schema; the method, its kind and its handler are unchanged (the IR still lists all 292 methods).
Takes back #29003: its untyped(method::…) registry line in acpmux/src/protocol/mod.rs is now keyed::<…Params>(method::…) with a closed params schema; the method, its kind and its handler are unchanged (the IR still lists all 292 methods).
Takes back #30188: its untyped(method::…) registry line in acpmux/src/protocol/mod.rs is now keyed::<…Params>(method::…) with a closed params schema; the method, its kind and its handler are unchanged (the IR still lists all 292 methods).
Takes back #30879: its untyped(method::…) registry line in acpmux/src/protocol/mod.rs is now keyed::<…Params>(method::…) with a closed params schema; the method, its kind and its handler are unchanged (the IR still lists all 292 methods).
Changelog
- CLI:
cmux open-remote --focus falsenow opens the remote pane without focusing it, as the action's ownfocusargument says.
Agent session: agent session
🤖 Generated with Claude Code
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Closes the contract-check follow-ups from #36260, #36265, #36579 and #36592: each check that stops a hand-named field from drifting across a boundary now covers the cases it missed.
Bridge and Swift-to-acpmux checks
- The webview scan now catches senders passed as object properties or destructured parameters and locals; this caught
git.capabilities, now listed as unserved in the agent-bridge contract. - Closed schemas with no properties reject any key, Swift method strings tokenize as raw and multiline strings, and
_meta.acpmuxkeys must appear in the new closedAcpmuxRequestMeta. - All 65 methods acpmux serves now have closed params schemas derived from handler reads;
AcpmuxRequestMetacovers the 68_meta.acpmuxkeys. The IR and web types are regenerated, so most of the diff is generated. - Three allowlist entries added:
noProject(the pane's own key, stripped byAcpmuxPathPolicy) andownerCloud/features(reply keys forinitialize).
CLI action arguments
cmux open-remote --focus [true|false]and--focus=falsenow reach the action's ownfocusargument; only--arg focus=...did before.- A new contract test fails on any action argument whose
--flagthe CLI owns and that can't reach the action through that flag; foursessioncases are listed inGLOBAL_FLAG_ARGUMENTS.cli-action-requests.jsonis regenerated.
Changelog: cmux open-remote --focus false now opens the remote pane without focusing it. Two test failures (every_safe_transport_operation_has_a_noun_first_path, root_help_lists_every_scope...) also fail on base and are not from this PR.