cmux NEXT: anything opened on the right goes to the lower pane when the right already holds something

Draft
TE
5d ago
+1026-309

Leo, 2026-10-30:

"subagent stuff... or anything we expect to open on "the right"... if there's already a thing on the right, there should be logic for just putting it on the lower pane of the right. that kinda split."

Earlier, 2026-10-28 (the spec, leo-workspace design/pane-placement.md):

"I mean the right top pane, and then you split to the bottom once so that you get the three items. But you want four items. I don't know what the fourth item should go."

Stacked on #27789. This PR's own diff is ef884b554e8f..HEAD. It stays a draft until #27789 lands.

The rule

One function, RightColumnPlacement.decide (CmuxNextAgentPane), decides every open on the right of a pane. Its input is the right column the window actually shows (RightColumn.measure, from the pane geometry):

What's on the right of the sourceWhere the new item goes
nothinga new split right of the source
one pane (diff, terminal, browser, session, anything)a new split below it; that pane keeps what it shows
two or more panesa tab in the lowest pane, never a third split
  • No split leaves the chat under 480 pt or the right column under 420 pt; that open becomes a tab instead.
  • Closing the lower pane's last tab removes the pane, so the split collapses back, and the next open splits below again.

Paths routed through it

  • Transcript subagent / Task cards (AgentSubagentPanes): #27789's placement function, now shared and reading the window's geometry instead of the tracker's own list.

  • Side chats, /btw, Session Info sessions, transcript session cards (AgentSidePanes; chat.sideChat and chat.offer.open).

  • Links opened to the right, and chats opened from Needs you (LinkOpener / LinkOpenPlacement): new .splitBelow target for a source that takes tabs. openWeb's reuse of a page already open on the right, openFolder and DurableTabLink's fallback handle it.

  • Main-pane layout (ux-owner, 2026-10-30, on Leo's "anything we expect to open on 'the right'"): the strip column right of the docked chat is its right side, so the same lower split applies (LinkOpenPlacement.inColumn, openOnRight). With nothing on its right yet, main-pane layout still makes the column by its own rule.

Unchanged: Home's pinned dock (a different surface, not named) keeps the link rule: the pane on its right, else a column beside the dock.

Overlap

This overlaps #26582 (RightPanePlacement, the general document/session policy, owned by another lane), which doesn't touch these paths yet. This PR doesn't take its type or touch its branch. Every path here calls one pure function, so it can fold into that policy later.

Tests (one per path)

  • RightColumnPlacementTests: the rule itself, narrow floors, and close-collapses-then-splits-again.
  • AgentSubagentPanesPlacementTests: with the right side occupied, the first subagent splits below it and the second is a tab there; closing collapses; a 4th subagent is a tab, never a third split.
  • AgentSideSessionPaneTests: side sessions split right, then once below, then become tabs in the lower pane; with the right side occupied they split below it; closing the lower pane's tabs collapses it and the next open splits again.
  • LinkOpenPlacementTests: with the right side measured, a link beside a pane splits below it, a full column takes a tab in its lower pane, narrow columns take a tab, and the main-pane strip column gets the same lower split.

Spec: leo-workspace design/pane-placement.md gains "Something already on the right (2026-10-30)" (lane/ux-pane-placement-lower).

Screenshots

Before/after: pending a fleet capture (requested from ux-owner for the media tour). They'll be added before this leaves draft.

Risk: a behaviour change in where the 2nd+ item opens on the right, for all of these paths. No new timers, observers or animation loops.

Agent session: agent session

šŸ¤– Generated with Claude Code