Skip to content

Add native shared tab-row tools protocol - #27133

Merged
teamleaderleo merged 36 commits into
feat-cmux-nextfrom
lane/orch-native-tools-a
Oct 30, 2026
Merged

teamleaderleo merged 36 commits into
feat-cmux-nextfrom
lane/orch-native-tools-a

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Native shared tab-row tools (PR a)

Build the native mechanism for content-supplied trailing tools in the shared tab row. Agent pages publish a bounded declarative list with pane.tabRowTools.set; native PaneToolbarView renders symbols, toggles, badges and press-open menus, and sends tabRowToolInvoked {id, menuItemId?} back through the page host. The tabRow event now includes nativeRowTools so the publisher can gate its layout.

Leo said:

"speaking of that top right buttons section area thing, okay, what do you think about moving it into Swift? Like just going more native with it? Because I just feel like on my fing God, I've ran into so many fing different hacks and stuff just to get this nonsense working. ... we keep running into this nonsense, right? ... And then we could just RPC it or whatever the f*** into TypeScript sometimes. But I feel like, okay, more native buttons and stuff, maybe that might be nicer."

The migration tunable is chrome.tabs.nativeRowTools, default OFF while this series lands. This PR does not remove the existing web tools hole or clearance CSS. The final series PR will flip the default and remove both together so the migration cannot stall behind a Debug switch.

Risk: normal. Swift cannot be built on this VM; python3 scripts/cmux-next/prepush-gate.py passed locally. A standalone SwiftFormat binary is unavailable here. Added decoding bounds tests and the tab-row event/op coverage. Fleet compile and Swift suites will be run by the coordinator.

Leo's standing direction:

"Like you need to be more ambitious, really. Like the whole dynamic workflow situation. I don't know if you already have the UI for that, how good it is, if you guys have tested it out yet. But, you know, we need to have that. And likewise, obviously, like the session info area, like that's where the things can be shown, and also the right tab area. All of these, like better and better UI. Just go ahead, man. I feel like you can do a hell of a lot more. More codex, more Claude, more whatever. We have the capacity, so let's use the fing capacity to go do some more productive fing work, right?"

Menu rows are page-declared actions: native returns their IDs and the page owns execution, like WebContextMenu. The menu-action baseline explicitly allows this one row builder; the checker and other allowances are unchanged. Keyboard Space and VoiceOver open the same press menu as a mouse press.

Validation at 909b6a9: menu-action guard, prepush gate and diff whitespace check pass locally. The new native keyboard-menu regression test requires the Mac suite. The prior aggregate check's No new SwiftUI failure reproduces identically on base 920ece1: HomeChatColorsPanel.swift and HomeChatColorsView.swift import SwiftUI outside the allowlist. The prior fast-tier failure is artifact upload ETIMEDOUT; its execution outcome is separate from upload evidence.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Adds the native protocol for content-supplied tools in the shared tab row, moving chat header controls from a web-rendered overlay into native Swift buttons.

  • Agent pages publish declarative tools via pane.tabRowTools.set; PaneToolbarView renders them as symbols, toggles, badges, and press-open menus, and sends tabRowToolInvoked {id, menuItemId?} back through the page host.
  • The toolbar follows the selected page's model through tab switches, first-paint holds, and AppKit reparenting; pane retirement and page close clear the ownership callback, a page reload drops the old page's tools, and menu-bearing tools respond to keyboard and VoiceOver activation, refresh their tint on toggle, and route presses through the page's gesture tracker.
  • The tabRow event now includes nativeRowTools so the publisher can gate its layout; native tools only render for the shared page host with a return event stream.
  • When a narrow pane cannot fit every native button, the non-fitting ones fall back into the "…" overflow menu, which chat panes now show; disabled tools stay in the menu.
  • Strict decoding bounds (16 tools, 32 menu items per menu, 256 across all tools and nesting, 2 menu levels, 64-char text, 256-byte text) reject malformed payloads; optional badge, checked, and role fields may be absent.
  • Gated behind chrome.tabs.nativeRowTools (default OFF); the existing web tools hole and clearance CSS stay until the final PR of the series flips the default and removes both together.

Migration
No action needed while the tunable is off. A final PR in the series will flip the default and remove the web tools hole and clearance CSS.

Written for commit e6bc95d. Summary will update on new commits.

View guided diff Turn on auto-fix

Capture tour-agent-pane at 1ade7ac0e9d4 (fleet build, capture mini, text checked for private data)

Light Dark
light dark

Agent session: agent session

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Bead cx-6utf7g created for this PR by the cmux coordinator.

@cursor

cursor Bot commented Oct 29, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Default changes

This pull request changes 5 defaults at f8e3ebd6b078 (what everyone gets without configuring anything):

  • tunable-source.CmuxNextAgentPane/AgentPaneTabRow.swift:offer: "48391d4a5571e55903d3511336132cd508c255f8f7235e3c343028f881fb92e6" -> "f7ac9d8835e42c6f7d8609626e55fba4e698810878672ae92ce0582b05265ae3"
  • tunable-source.CmuxNextAgentPane/AgentPaneTabRow.swift:tabRow: "1521885bf4839cfac198fa3ae98cc48bd95bed9e1c702846fd51b8ed5a19e5ad" -> "d5b82509e08e906b34fd6edb5edb1a7ec4cda99cd26cfa5e9e5779b0c0a1b3d5"
  • tunable-source.CmuxNextDesign/Tunables/ChromeTunables.swift:fixed: "71b734ca93e0f27b8b87781852d9b67856737e6c028822e68d95f64bc8414630" -> "8a00815e4da185323cd87a384bc037dae2040e76449783498d84cb0cdec6763f"
  • tunable-source.CmuxNextDesign/Tunables/ChromeTunables.swift:nativeRowTools: (none) -> "15bd15cce71b64ffb0217c639a35ff2ec4a55e0e5ff84cecaa3b81b303d1b43e"
  • tunable.chrome.tabs.nativeRowTools: (none) -> false

Signed off on this commit by review (codex gpt-6-astra).

Merge receipt: merged as 5f1a4b03aad8 with these defaults changed, signed off by review (codex gpt-6-astra).

Regenerate the snapshot with python3 scripts/ci/defaults_guard.py snapshot.

@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review f8e3ebd: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr27133 -f ref=lane/orch-native-tools-a -f platform=macos -f backend_mode=local

red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on 6c8bc64 to compare; do not merge until green; see lane-rules

@github-actions github-actions Bot added risk:high Risk tier (docs/ci/risk-tiers.md) and removed risk:normal Risk tier (docs/ci/risk-tiers.md) labels Oct 29, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (gpt-6-astra): SHIP at 04d77c1

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Fleet check of a4e09e8 (the frozen head; cc4d616 was not used).

Check Receipt Result
cmux-ci compile-check --app (Linux) job 5a6a8f54fe9b4cd265c35d5f fail: 22 errors, emit-module failed
package-test-lane.sh suite Packages/macOS/CmuxNext ... (Mac, cmux-ci run) step d8544913d2c8f6d65829caef fail: the CmuxNext build stops with the same errors, so no suite ran

Suites in the Mac step. Each one has no result (build failed), which is not a pass: AgentPaneTabRowToolsTests, AgentPaneTabRowHolesTests, AgentPaneTabRowNeedTests, AgentPageProviderEventsTests, PaneMoreOverflowButtonTests, PaneChromeEvenInsetTests, PaneMoreShotsTests, AgentInteropAccessibilityTests, HomeDockTabRowToolsTests, PaneTabBarControlsTests, TabBarRestingControlsTests, PaneDiscoverabilityTests.

Both runs report the same compile errors. They come from this PR's files in CmuxNextAgentPane:

  • AgentPaneModel.swift:103, :492 and AgentPaneRequest.swift:170: cannot find type 'PaneTabRowTool' in scope. That in turn causes AgentPaneRequest.swift:8: type 'AgentPaneRequest' does not conform to protocol 'Equatable'.
  • AgentPaneModel+Header.swift:170: cannot find 'ChromeTunables' in scope.
  • AgentPageEvent.swift:77-80, :94-97: main actor-isolated property 'id' / 'symbol' / 'label' / 'enabled' / 'toggled' / 'badge' / 'menu' / 'checked' / 'role' / 'children' can not be referenced from a nonisolated context.

Likely causes, from reading the tree at this sha:

  1. The package sets InternalImportsByDefault, and none of AgentPaneModel.swift, AgentPaneRequest.swift or AgentPaneModel+Header.swift imports CmuxNextDesign, where PaneTabRowTool and ChromeTunables live. Each of those files needs import CmuxNextDesign.
  2. CmuxNextDesign builds with .defaultIsolation(MainActor.self). That makes the stored properties of PaneTabRowTool and PaneTabRowMenuItem main-actor isolated, but the static func tabRowTools(_:) builder in AgentPageEvent and its menu-object helper are nonisolated. One fix is to mark the two value types nonisolated (they are Sendable value types). The other is to isolate the builders.

These are this PR's own reds, not base reds: the errors are in the files this PR adds or changes.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Fleet check of 04d77c1. This replaces the a4e09e8 comment above.

Check Receipt Result
cmux-ci compile-check --app (Linux) job 4521ca8dd89acfd6822e8728 fail: emit-module failed
package-test-lane.sh suite Packages/macOS/CmuxNext ... (Mac, cmux-ci run) step 4e506839900716c9288c9f2c fail: the CmuxNext build stops with the same errors, so no suite ran

Suites in the Mac step. Each one has no result (build failed), which is not a pass: AgentPaneTabRowToolsTests, AgentPaneTabRowHolesTests, AgentPaneTabRowNeedTests, AgentPageProviderEventsTests, PaneMoreOverflowButtonTests, PaneChromeEvenInsetTests, PaneMoreShotsTests, AgentInteropAccessibilityTests, HomeDockTabRowToolsTests, PaneTabBarControlsTests, TabBarRestingControlsTests, PaneDiscoverabilityTests.

The main-actor isolation errors in AgentPageEvent.swift are gone at this head. These remain, the same in both runs:

  • CmuxNextAgentPane/AgentPaneModel.swift:103, :491 and AgentPaneRequest.swift:170: cannot find type 'PaneTabRowTool' in scope. That in turn causes AgentPaneRequest.swift:8: type 'AgentPaneRequest' does not conform to protocol 'Equatable'.
  • CmuxNextAgentPane/AgentPaneModel+Header.swift:170: cannot find 'ChromeTunables' in scope.

Likely fix: the package builds with InternalImportsByDefault, so each file imports what it uses. AgentPaneModel.swift, AgentPaneRequest.swift and AgentPaneModel+Header.swift need import CmuxNextDesign. 46 other files in the target already have it.

This is the PR's own red, not a base red.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (gpt-6-astra): SHIP at b1b2d35
Scoped delta review: AgentPageProvider.swift and AgentPaneModel.swift preserve both base dictation/Chief operations and branch pane.tabRowTools.set routing/tabRowTools state; no unrelated merge changes.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra): BLOCK at f1f053f

  • P1 — Packages/macOS/CmuxNext/Sources/CmuxNextApp/PaneContentView.swift:215: During a paint hold, content is the incoming page while visibleContent is the outgoing page. The owner therefore binds to the incoming model, but PaneNativeToolOwnershipTests.swift:60-62 explicitly expects the outgoing callback during the hold; this assertion will fail and changes native-tool behavior.

  • P2 — Packages/macOS/CmuxNext/Sources/CmuxNextApp/PaneContentView.swift:215,219: If content is reparented elsewhere, hostsContent becomes false and displayedAgentPaneView becomes nil, but nativeToolOwner.model remains stale because no refresh is triggered by that reparenting. Native buttons/callbacks can remain attached after the pane loses its content.

DesignTunables.all does include nativeRowTools through ChromeTunables.fixed at ChromeTunables.swift:82,91, and no remaining ChromeTunables.all references were found.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra): BLOCK at b0d6113

P2 — AgentPaneView.close() never clears onNativeToolOwnerChange before removing the view (AgentPaneView.swift). Retired/closed views can retain a callback into the pane they left; detachContent() only clears the currently shown view, and parked agent views retain theirs. Clear the callback in close() (and when retiring agent views) before removal.

P1/P3: no additional findings.

@cursor

cursor Bot commented Oct 30, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra): BLOCK at e6bc95d

P1: None.

P2: prunePark can clear the destination pane’s callback from a still-hosted view. A view parked in pane A can be adopted by pane B, which binds B’s callback; a later prunePark/dropParked in A sees view.superview !== A.contentHost and unconditionally nils the hook at [PaneContentView+Parking.swift:112-114]. The view remains hosted by B, but future reparenting no longer refreshes B’s owner. This violates requirement (2).

P3: None.

  • Every normal path that restores content uses show(): new installation, parked unpark, paint-hold incoming content, and WindowEntryHandoff re-entry. show() binds the callback at [PaneContentView.swift:331-344]. No other code directly adds content views to contentHost; launch-image insertion is separate.
  • The still-hosted loss described above is the exception: source-pane pruning can remove the destination’s hook after rebinding.
  • The callback remains main-actor/AppKit confined. It captures [weak self], so there is no retain cycle. It only refreshes observable ownership and toolbar state; it does not reparent views, so there is no re-entrancy loop.
  • Against the base commit, the new test fails: close() leaves the hook installed, and removal triggers the old refresh path, clearing owner.model instead of preserving it. The test is at [PaneNativeToolOwnershipTests.swift:96-112].
  • The only newly cross-module symbol is AgentPaneView.onNativeToolOwnerChange, correctly made public at [AgentPaneView.swift:452-458].

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra): SHIP at f8e3ebd

No P1/P2/P3 findings in this delta.

  • AgentPaneNativeToolsHostTests.swift:57: Offering first matches the replay event’s contract. Capability and publication assertions remain meaningful.
  • PaneMoreOverflowButtonTests.swift:62: Width 1 forces overflow; the throwing count requirement precedes every array subscript. Missing rows now fail the test instead of reaching the signal-6 indexing path. Disabled-ancestor and stale-invocation checks remain intact.
  • PaneNativeToolOwnershipTests.swift:33: The labeled two-second timeout fails clearly. Both children are structured tasks; cancelAll() cancels the loser, and the group joins it. ObservationStream.current uses the cancellation-aware legacy iterator, whose cancellation handler resumes pending waits.
  • PaneNativeToolOwnershipTests.swift:96: Awaiting selection establishes observation of the incoming model before subsequent mutations. Rejecting the outgoing callback matches PaneToolbar.apply’s ownership guard. Direct post-paint assertions correctly avoid waiting for an unchanged, deduplicated snapshot.
  • PaneContentView.swift:219 and PaneContentView+Parking.swift:113: Adopted hooks survive old-pane cleanup. Detached selected views clear their hook through viewDidMoveToSuperview; parked views already clear it in retire, and close() clears it independently. Returning to A installs a fresh A callback through show. The adoption test also verifies functional cleanup when the view leaves B.

Main-actor isolation holds for view, owner, and iterator access. Static review only; no runtime tests executed.

Scope: delta review of e6bc95d..f8e3ebd, covering the findings in the BLOCK at e6bc95d. Fleet at this head (relayed by the coordinator): compile-tests 27/27 PASS; AgentPaneNativeToolsHostTests, AgentPaneTabRowToolsTests, AgentPaneFramelessChromeTests, PaneMoreOverflowButtonTests and PaneNativeToolOwnershipTests PASS. AgentPageProviderEventsTests fails routerResetDropUsesTheCapturedProviderAfterRouterCloses() with the same error at head and at merge base 6c8bc64, so that one is a base red. No crash.

@teamleaderleo
teamleaderleo merged commit 5f1a4b0 into feat-cmux-next Oct 30, 2026
139 of 146 checks passed
@teamleaderleo
teamleaderleo deleted the lane/orch-native-tools-a branch October 30, 2026 14:34
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

This branch was previously deployed

1 inactive deployment
ci-routing-agent — f8e3ebd6 Deployed Oct 30, 2026 by teamleaderleo via namespace autofix #7872
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:high Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant