cmux NEXT: new tabs from an agent chat open on the right, after that pane's selected tab (fixes #23105 regression)

TE
11d ago
+229-20

Leo on nightly 3a63d6d (2026-10-21): "THIS ADDING TABS: IT SWITCHES AROUND AND DOESN'T REALLY GET ADDED". Lucas: tabs "disappear inside of chats". Then Leo: "DEFAULT ON THE RIGHT ... EVERYBODY IS SAYING OPEN DEFAULT ON THE RIGHT".

Regressing PR: #23105 (2a7eec57, main pane layout). Since then chat docks are common. Cmd-T and + in a docked chat's pane went to the strip pane on its right, but NewTabSlot still anchored the tab's slot on the chat pane's selected tab. So the placement was held in the chat's pane, never found the tab there, and the tab landed at the end of the strip pane, out of view.

Rules:

  • Cmd-T, + and Option-+ (newTab.ofKind) in an agent chat's pane follow layout.linkPlacement (read through services.linkOpener.placement()):
    • split-right / new-column (the default): the tab opens on the right, in the strip pane ChatColumnPlacement.route picks (the most recent one). It lands right after that pane's selected tab, selected and focused, and no other tab moves in either pane. From a lone chat, a terminal or browser tab still docks the chat as on base. A New Tab page opens in a new split on the right and the chat stays where it is.
    • same-pane: the tab stays in the chat's pane, right after its selected tab, selected.
  • Any other pane (terminal, browser, page) keeps its new tab, as before.
  • Home's pinned dock (no +) still opens beside it.
  • Scripts, CLI and MCP, and the other ChatColumnPlacement.route callers (newSurface, openBrowser, link opens), are unchanged.

Change:

  • ChatColumnPlacement.newTabStays(in:services:) is the one seam: it decides whether a person's new tab stays in its pane. TabLifecycle.newTabOfPaneKind computes it once and passes it to newTerminal and newBrowser as staysInPane, and uses it for pages too.
  • A tab routed to another pane takes that pane's slot (NewTabSlot.rebased).

Tests: NewTabStaysInItsPaneTests (daemon-backed, 5 tests) builds an agent chat dock left of a strip pane, with focus in the dock.

  • With the default, Cmd-T and Option-+ each add exactly one tab to the strip pane, right after its selected tab. The tab is selected, focus is in the strip, and the dock is unchanged.
  • With same-pane, both add the tab to the dock right after its selected tab, and the strip is unchanged.
  • Cmd-T in a terminal pane keeps the tab there, right after the terminal.

Fleet: the app compile check and the suite (5/5) passed at the head.

Known gap, not a regression: after a lone chat's first New Tab page splits right, the chat is not docked. A later Cmd-T in the chat then stays in its pane, as on base.

No capture: the before/after recordings from the fleet repro show a private host; the tests pin the behaviour.

Leo-ask: ask-504ac4c80e

Agent session: cosmic-gray

🤖 Generated with Claude Code