cmux NEXT: a link or terminal opened on the right goes to the pane that already holds its kind

Closed
TE
5d ago
+115-27

Leo, 2026-10-31, of a link from a chat that opened in a new lower-right browser pane under the browser pane already on the right:

"imo in this case, just open it on the existing. you only need the rightmost botom auto split when there's a terminal that gets opened when there's already a browser, and vice versa"

This builds on #28989 (the right column's lower-pane split) and keeps that split for everything but this case.

The rule

RightColumnPlacement.decide now also gets the kind being opened (Kind: .terminal or .browser, the two Leo named) and which kinds each pane in the right column holds:

On the chat's rightOpeningBeforeAfter
nothinganythingsplit rightsplit right (unchanged)
a browser panea link / browsersplit below ita tab in that browser pane
a browser panea terminalsplit below itsplit below it (the kind differs)
a terminal panea terminalsplit below ita tab in that terminal pane
a terminal panea link / browsersplit below itsplit below it
browser over terminala linka tab in the lower (terminal) panea tab in the browser pane
browser over terminala terminala tab in the lower panea tab in the lower (terminal) pane

When several panes hold the kind, the lowest one gets the tab. The width floors only ever turned a split into a tab, so they don't change here.

Paths

  • Links: LinkOpener.openWeb (a chat's links, a terminal's Cmd-click, Home, pages) and a browser page's Cmd-click (BrowserPageRequests.openOnRight) open as .browser. Its reuse check (select a tab already showing the page) uses the same target.
  • Folders: LinkOpener.openFolder opens as .terminal.
  • The docked chat's strip column (MainPaneLayout, LinkOpenPlacement.inColumn) follows the same rule.
  • Unchanged (no kind): chats, subagents, side sessions, Session Info sessions, transcript cards and file pages. Leo named only terminals and browsers.

Not in this PR: a terminal or browser picked on a New Tab page in the chat dock (NewTabPage+Open.openBeside). #28544 rewrites that call and is landing. A follow-up passes the pick's kind there once #28544 has landed.

Tests

  • RightColumnPlacementTests.aBrowserOrTerminalGoesToThePaneThatAlreadyHoldsItsKind: same kind gets a tab and a different kind splits below, for each kind. With both kinds on the right, each open goes to its own pane. A narrow column and an empty right side behave as before. An open with no kind behaves as before.
  • LinkOpenPlacementTests.aLinkGoesToTheBrowserPaneAlreadyOnTheRight: the same rule through LinkOpenPlacement.target and the docked chat's inColumn.
  • The existing lower-split tests (open with no kind) are unchanged and still pass.

Spec: leo-workspace design/pane-placement.md gets a "Same kind goes to its pane (2026-10-31)" section.

Risk: a behaviour change in where a link or folder opens when the right column already holds a pane of that kind. No new timers, observers or animation loops.

Screenshots: none (Leo, 2026-10-31: "WE DONT NEED FUCKIGN SCREENSHOTS JUST LET ME TRY THE SHIT OUT").

Agent session: agent session

šŸ¤– Generated with Claude Code