Repository navigation
cmux-next: tools opened from the docked agent chat open in the strip - #18170
Conversation
Red: set-column-dock and move-tab-to-column drop role, identify does not advertise dock-column-role-v1, the registry record drops it, and the app never sends it back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cmux-tui: ColumnDock gains an optional role (agent_chat), set with the pin by set-column-dock and move-tab-to-column, journaled and restored with it, dropped with it, and read as no role when unknown. identify advertises dock-column-role-v1. Spec and generated bindings updated. cmux next: DockSnapshot, the dock requests and the layout's DockColumn carry the role; no behavior uses it yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The agent chat dock (a left dock column with the agent_chat role) never gets tabs of its own. A person's New Terminal, New Browser or Cmd-T from it opens a tab in the scrolling strip, in the strip pane focused last; Cmd-T's agent or page kind becomes a New Tab page there. A chat alone on its screen moves into a new left chat dock and the new terminal or browser stays in its pane, in one daemon commit. Chats outside the chat dock stay normal panes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Not verified: macOS jobs did not run: compile and app tests were skipped on CI passes on Written by |
…its cwd NEW-TERMINAL-INHERITS-CWD: a terminal opened from the docked agent chat (a strip tab, or the tab a lone chat leaves when it docks) sends only an explicit cwd and otherwise nil, so the daemon's resolver (new-terminal-cwd-v1) decides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review (correctness read, nx-docked-column lane). Concrete defects:
|
… column Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ScreenLayout.column(containing:) only searches real columns, so a new workspace's screen (one split tree) had none and New Terminal from its lone chat opened beside the chat. LayoutScreen.column(containing:) gives the implicit column. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hat-role # Conflicts: # cmux-tui/bindings/cpp/.cmux-sdk-manifest.json # cmux-tui/bindings/cpp/include/cmux/raw/generated/models.hpp # cmux-tui/bindings/go/raw/.cmux-sdk-manifest.json # cmux-tui/bindings/go/raw/generated_commands.go # cmux-tui/bindings/go/raw/generated_events.go # cmux-tui/bindings/go/raw/generated_metadata.go # cmux-tui/bindings/go/raw/generated_presence_test.go # cmux-tui/bindings/go/raw/generated_types.go # cmux-tui/bindings/java/src/com/cmux/raw/.cmux-sdk-manifest.json # cmux-tui/bindings/java/src/com/cmux/raw/Protocol.java # cmux-tui/bindings/python/cmux/raw/_generated/.cmux-sdk-manifest.json # cmux-tui/bindings/python/cmux/raw/_generated/_schema.py # cmux-tui/bindings/python/cmux/raw/_generated/metadata.py # cmux-tui/bindings/rust/src/generated/.cmux-sdk-manifest.json # cmux-tui/bindings/rust/src/generated/commands.rs # cmux-tui/bindings/rust/src/generated/events.rs # cmux-tui/bindings/rust/src/generated/metadata.rs # cmux-tui/bindings/rust/src/generated/mod.rs # cmux-tui/bindings/rust/src/generated/types.rs # cmux-tui/bindings/typescript/src/raw/generated/.cmux-sdk-manifest.json # cmux-tui/bindings/typescript/src/raw/generated/commands.ts # cmux-tui/bindings/typescript/src/raw/generated/events.ts # cmux-tui/bindings/typescript/src/raw/generated/index.ts # cmux-tui/bindings/typescript/src/raw/generated/metadata.ts # cmux-tui/bindings/typescript/src/raw/generated/types.ts # cmux-tui/bindings/zig/src/raw/generated/.cmux-sdk-manifest.json # cmux-tui/bindings/zig/src/raw/generated/protocol.zig # cmux-tui/spec/commands.md
…ock-tools # Conflicts: # cmux-tui/bindings/cpp/.cmux-sdk-manifest.json # cmux-tui/bindings/cpp/include/cmux/raw/generated/models.hpp # cmux-tui/bindings/go/raw/.cmux-sdk-manifest.json # cmux-tui/bindings/go/raw/generated_commands.go # cmux-tui/bindings/go/raw/generated_events.go # cmux-tui/bindings/go/raw/generated_metadata.go # cmux-tui/bindings/go/raw/generated_presence_test.go # cmux-tui/bindings/go/raw/generated_types.go # cmux-tui/bindings/java/src/com/cmux/raw/.cmux-sdk-manifest.json # cmux-tui/bindings/java/src/com/cmux/raw/Protocol.java # cmux-tui/bindings/python/cmux/raw/_generated/.cmux-sdk-manifest.json # cmux-tui/bindings/python/cmux/raw/_generated/_schema.py # cmux-tui/bindings/python/cmux/raw/_generated/metadata.py # cmux-tui/bindings/rust/src/generated/.cmux-sdk-manifest.json # cmux-tui/bindings/rust/src/generated/commands.rs # cmux-tui/bindings/rust/src/generated/events.rs # cmux-tui/bindings/rust/src/generated/metadata.rs # cmux-tui/bindings/rust/src/generated/mod.rs # cmux-tui/bindings/rust/src/generated/types.rs # cmux-tui/bindings/typescript/src/raw/generated/.cmux-sdk-manifest.json # cmux-tui/bindings/typescript/src/raw/generated/commands.ts # cmux-tui/bindings/typescript/src/raw/generated/events.ts # cmux-tui/bindings/typescript/src/raw/generated/index.ts # cmux-tui/bindings/typescript/src/raw/generated/metadata.ts # cmux-tui/bindings/typescript/src/raw/generated/types.ts # cmux-tui/bindings/zig/src/raw/generated/.cmux-sdk-manifest.json # cmux-tui/bindings/zig/src/raw/generated/protocol.zig # cmux-tui/spec/commands.md
…hat-role # Conflicts: # cmux-tui/bindings/cpp/.cmux-sdk-manifest.json # cmux-tui/bindings/cpp/include/cmux/raw/generated/models.hpp # cmux-tui/bindings/cpp/src/raw/generated/protocol.cpp # cmux-tui/bindings/go/raw/.cmux-sdk-manifest.json # cmux-tui/bindings/go/raw/generated_commands.go # cmux-tui/bindings/go/raw/generated_events.go # cmux-tui/bindings/go/raw/generated_metadata.go # cmux-tui/bindings/go/raw/generated_presence_test.go # cmux-tui/bindings/go/raw/generated_types.go # cmux-tui/bindings/java/src/com/cmux/raw/.cmux-sdk-manifest.json # cmux-tui/bindings/java/src/com/cmux/raw/Protocol.java # cmux-tui/bindings/java/src/com/cmux/raw/SetColumnDockRequest.java # cmux-tui/bindings/python/cmux/raw/_generated/.cmux-sdk-manifest.json # cmux-tui/bindings/python/cmux/raw/_generated/_schema.py # cmux-tui/bindings/python/cmux/raw/_generated/client.py # cmux-tui/bindings/python/cmux/raw/_generated/metadata.py # cmux-tui/bindings/python/cmux/raw/_generated/models.py # cmux-tui/bindings/rust/src/generated/.cmux-sdk-manifest.json # cmux-tui/bindings/rust/src/generated/commands.rs # cmux-tui/bindings/rust/src/generated/events.rs # cmux-tui/bindings/rust/src/generated/metadata.rs # cmux-tui/bindings/rust/src/generated/mod.rs # cmux-tui/bindings/rust/src/generated/types.rs # cmux-tui/bindings/typescript/src/raw/generated/.cmux-sdk-manifest.json # cmux-tui/bindings/typescript/src/raw/generated/commands.ts # cmux-tui/bindings/typescript/src/raw/generated/events.ts # cmux-tui/bindings/typescript/src/raw/generated/index.ts # cmux-tui/bindings/typescript/src/raw/generated/metadata.ts # cmux-tui/bindings/typescript/src/raw/generated/types.ts # cmux-tui/bindings/zig/src/raw/generated/.cmux-sdk-manifest.json # cmux-tui/bindings/zig/src/raw/generated/protocol.zig # cmux-tui/crates/cmux-tui-core/src/model/layout_columns.rs # cmux-tui/crates/cmux-tui-core/src/mux/dock_columns.rs # cmux-tui/crates/cmux-tui-core/src/mux/tests/column_update.rs # cmux-tui/crates/cmux-tui-core/src/mux/tests/dock_columns.rs # cmux-tui/crates/cmux-tui-core/src/server.rs # cmux-tui/crates/cmux-tui-core/src/server/capabilities.rs # cmux-tui/crates/cmux-tui-core/src/server/dock_columns_tests.rs # cmux-tui/crates/cmux-tui-core/src/workspace_registry/resource_store/screen_rows.rs # cmux-tui/crates/cmux-tui-core/src/workspace_registry/resource_store/viewport.rs # cmux-tui/spec/sdk-schema.json
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hat-dock-tools # Conflicts: # cmux-tui/bindings/cpp/.cmux-sdk-manifest.json # cmux-tui/bindings/cpp/include/cmux/raw/generated/models.hpp # cmux-tui/bindings/go/raw/.cmux-sdk-manifest.json # cmux-tui/bindings/go/raw/generated_commands.go # cmux-tui/bindings/go/raw/generated_events.go # cmux-tui/bindings/go/raw/generated_metadata.go # cmux-tui/bindings/go/raw/generated_presence_test.go # cmux-tui/bindings/go/raw/generated_types.go # cmux-tui/bindings/java/src/com/cmux/raw/.cmux-sdk-manifest.json # cmux-tui/bindings/java/src/com/cmux/raw/Protocol.java # cmux-tui/bindings/python/cmux/raw/_generated/.cmux-sdk-manifest.json # cmux-tui/bindings/python/cmux/raw/_generated/_schema.py # cmux-tui/bindings/python/cmux/raw/_generated/metadata.py # cmux-tui/bindings/rust/src/generated/.cmux-sdk-manifest.json # cmux-tui/bindings/rust/src/generated/commands.rs # cmux-tui/bindings/rust/src/generated/events.rs # cmux-tui/bindings/rust/src/generated/metadata.rs # cmux-tui/bindings/rust/src/generated/mod.rs # cmux-tui/bindings/rust/src/generated/types.rs # cmux-tui/bindings/typescript/src/raw/generated/.cmux-sdk-manifest.json # cmux-tui/bindings/typescript/src/raw/generated/commands.ts # cmux-tui/bindings/typescript/src/raw/generated/events.ts # cmux-tui/bindings/typescript/src/raw/generated/index.ts # cmux-tui/bindings/typescript/src/raw/generated/metadata.ts # cmux-tui/bindings/typescript/src/raw/generated/types.ts # cmux-tui/bindings/zig/src/raw/generated/.cmux-sdk-manifest.json # cmux-tui/bindings/zig/src/raw/generated/protocol.zig
…ock-tools # Conflicts: # Packages/macOS/CmuxNext/Sources/CmuxNextApp/Handlers/TabLifecycle.swift
This comment has been minimized.
This comment has been minimized.
…ock-tools # Conflicts: # Packages/macOS/CmuxNext/Sources/CmuxNextApp/Handlers/TabLifecycle.swift
|
Found 1 test failure on Blacksmith runners: Failure
|
The conflicts were the generated cmux-tui SDK bindings: the dock column role landed on base separately. Took base's side and regenerated them with cmux-tui/bindings/codegen/generate.py (--check is clean). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 5d3bca2. Configure here.
…w tab here Cursor review on #18170: .newColumn is built for a chat dock with no scrolling column, which the daemon never keeps (an all-docked screen undocks), and a zoomed screen maps to its zoomed pane alone, so a zoomed chat looked like a lone chat and docked. resolve takes a zoomed seam, still ignored here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ile zoomed, and opens the chat's context Cursor review on #18170: - The daemon never keeps a dock without a scrolling column (an all-docked screen undocks), so .newColumn is gone; it also dropped an explicit cwd and sent browsers and New Tab pages into the dock. - A zoomed screen maps to its zoomed pane alone; nothing docks or moves until the zoom ends. - A URL-less browser from the docked chat opens what the chat works on (#16620), in the strip pane. - A browser a lone chat leaves when it docks is recorded for Auto tabs.newTabKind, like any other browser (Cursor on #18223). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Takes #18170's Cursor fixes (no strip-less .newColumn, zoom keeps the tab here, the chat's context for a URL-less browser). The one conflict was ChatColumnPlacement.resolve: kept the zoom check and this branch's isChat helper. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/37871997540 at 9e3a1a2 failed: cmux-next swift test. |
…18223) * test: the dock column keeps an agent chat role Red: set-column-dock and move-tab-to-column drop role, identify does not advertise dock-column-role-v1, the registry record drops it, and the app never sends it back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: dock columns keep an agent chat role (dock-column-role-v1) cmux-tui: ColumnDock gains an optional role (agent_chat), set with the pin by set-column-dock and move-tab-to-column, journaled and restored with it, dropped with it, and read as no role when unknown. identify advertises dock-column-role-v1. Spec and generated bindings updated. cmux next: DockSnapshot, the dock requests and the layout's DockColumn carry the role; no behavior uses it yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-sdk): build ColumnPin with its optional role Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): tools opened from the docked chat go to the strip Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cmux-next): tools opened from the docked chat open in the strip The agent chat dock (a left dock column with the agent_chat role) never gets tabs of its own. A person's New Terminal, New Browser or Cmd-T from it opens a tab in the scrolling strip, in the strip pane focused last; Cmd-T's agent or page kind becomes a New Tab page there. A chat alone on its screen moves into a new left chat dock and the new terminal or browser stays in its pane, in one daemon commit. Chats outside the chat dock stay normal panes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): a lone New Tab page is not a chat to dock Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): a terminal from the docked chat lets the daemon pick its cwd NEW-TERMINAL-INHERITS-CWD: a terminal opened from the docked agent chat (a strip tab, or the tab a lone chat leaves when it docks) sends only an explicit cwd and otherwise nil, so the daemon's resolver (new-terminal-cwd-v1) decides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): a lone chat on a split-tree screen sees its implicit column Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): a lone chat on a split-tree screen docks ScreenLayout.column(containing:) only searches real columns, so a new workspace's screen (one split tree) had none and New Terminal from its lone chat opened beside the chat. LayoutScreen.column(containing:) gives the implicit column. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): the chat dock shows no tab strip until it holds two tabs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cmux-next): the chat dock shows no tab strip until it holds two tabs The agent chat is a docked column with no tab bar by default. The chat dock's pane (the dock column with the agent_chat role) and a chat alone on its screen, which docks when the first tool opens, hide their strip while they hold one tab. The strip comes back at two tabs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): a new agent chat opens in the chat dock Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cmux-next): a new agent chat opens in the chat dock Every new agent chat (New Agent Chat, Cmd-I on a pane, the CLI, Duplicate, a session link) opens in the chat dock: a tab in the existing dock, else a new left dock with the agent_chat role made from the chat once it exists. A chat alone on its screen keeps a second chat in its pane; it docks when the first tool opens. A New Tab page that becomes a chat stays where it is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): a new chat bound for the chat dock never shows in the strip Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): a new chat moves into its dock without flashing in the strip A new chat bound for a new chat dock opens unselected and hidden from its pane's strip (pendingDock), then shows once, in its dock, focused. A failed move shows it where it is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(cmux-next): DockRole in its own file (god-file limit) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * style(cmux-tui): rustfmt the merged permanent-dock test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(cmux-next): new chat routing lives in NewChatPlacement openAgentTab's dock routing moves to NewChatPlacement.opening, so PaneController stays under the 1000-line god-type limit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(cmux-next): fold PaneController's chat dock notes into fewer lines Base grew PaneController; merged with the tip it spanned 1004 lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: run cmux-next again (generated files never got a runner on 01c19d2) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): a strip-less chat dock and a zoomed chat keep the new tab here Cursor review on #18170: .newColumn is built for a chat dock with no scrolling column, which the daemon never keeps (an all-docked screen undocks), and a zoomed screen maps to its zoomed pane alone, so a zoomed chat looked like a lone chat and docked. resolve takes a zoomed seam, still ignored here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): chat dock routing drops the strip-less case, holds while zoomed, and opens the chat's context Cursor review on #18170: - The daemon never keeps a dock without a scrolling column (an all-docked screen undocks), so .newColumn is gone; it also dropped an explicit cwd and sent browsers and New Tab pages into the dock. - A zoomed screen maps to its zoomed pane alone; nothing docks or moves until the zoom ends. - A URL-less browser from the docked chat opens what the chat works on (#16620), in the strip pane. - A browser a lone chat leaves when it docks is recorded for Auto tabs.newTabKind, like any other browser (Cursor on #18223). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): a dock-bound chat stays hidden across its rekey and other docks; the strip shows beside the chat dock Cursor review on #18223: - pendingDock holds the provisional id, and the created id only after the creation reply, so the strip can list the created chat in between. - A finished dock clears every pending chat of the pane. - hidesStrip takes a chat alone in the strip for the screen's lone chat even when a chat dock exists. dockFinished is the finish seam, still clearing everything here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): a dock-bound chat stays hidden across its rekey and other docks; the strip shows beside the chat dock Cursor review on #18223: - The strip hides pendingDock through the store's aliases, so the tab that replaces a provisional chat is hidden from its first snapshot. - dockFinished removes only that chat; other chats on their way stay hidden. - The new chat's focus waits until the layout shows it outside the pane it moved from. - A chat alone in the strip beside a chat dock keeps its strip. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* test: the dock column keeps an agent chat role Red: set-column-dock and move-tab-to-column drop role, identify does not advertise dock-column-role-v1, the registry record drops it, and the app never sends it back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat: dock columns keep an agent chat role (dock-column-role-v1) cmux-tui: ColumnDock gains an optional role (agent_chat), set with the pin by set-column-dock and move-tab-to-column, journaled and restored with it, dropped with it, and read as no role when unknown. identify advertises dock-column-role-v1. Spec and generated bindings updated. cmux next: DockSnapshot, the dock requests and the layout's DockColumn carry the role; no behavior uses it yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-sdk): build ColumnPin with its optional role Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): tools opened from the docked chat go to the strip Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cmux-next): tools opened from the docked chat open in the strip The agent chat dock (a left dock column with the agent_chat role) never gets tabs of its own. A person's New Terminal, New Browser or Cmd-T from it opens a tab in the scrolling strip, in the strip pane focused last; Cmd-T's agent or page kind becomes a New Tab page there. A chat alone on its screen moves into a new left chat dock and the new terminal or browser stays in its pane, in one daemon commit. Chats outside the chat dock stay normal panes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): a lone New Tab page is not a chat to dock Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): a terminal from the docked chat lets the daemon pick its cwd NEW-TERMINAL-INHERITS-CWD: a terminal opened from the docked agent chat (a strip tab, or the tab a lone chat leaves when it docks) sends only an explicit cwd and otherwise nil, so the daemon's resolver (new-terminal-cwd-v1) decides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): a lone chat on a split-tree screen sees its implicit column Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): a lone chat on a split-tree screen docks ScreenLayout.column(containing:) only searches real columns, so a new workspace's screen (one split tree) had none and New Terminal from its lone chat opened beside the chat. LayoutScreen.column(containing:) gives the implicit column. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): the chat dock shows no tab strip until it holds two tabs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cmux-next): the chat dock shows no tab strip until it holds two tabs The agent chat is a docked column with no tab bar by default. The chat dock's pane (the dock column with the agent_chat role) and a chat alone on its screen, which docks when the first tool opens, hide their strip while they hold one tab. The strip comes back at two tabs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): a new agent chat opens in the chat dock Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cmux-next): a new agent chat opens in the chat dock Every new agent chat (New Agent Chat, Cmd-I on a pane, the CLI, Duplicate, a session link) opens in the chat dock: a tab in the existing dock, else a new left dock with the agent_chat role made from the chat once it exists. A chat alone on its screen keeps a second chat in its pane; it docks when the first tool opens. A New Tab page that becomes a chat stays where it is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): a new chat bound for the chat dock never shows in the strip Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): a new chat moves into its dock without flashing in the strip A new chat bound for a new chat dock opens unselected and hidden from its pane's strip (pendingDock), then shows once, in its dock, focused. A failed move shows it where it is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): the chat dock cannot be split and takes only chats Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): the chat dock refuses splits and non-chat tabs The agent chat dock is a docked region, not a split pane. splitRoom, which every split, auto layout and split drop goes through, refuses splitting it, and moving a terminal, browser or tab group into it is refused with a localized reason. Chats still move in, and tabs already in the dock still reorder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(cmux-next): DockRole in its own file (god-file limit) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * style(cmux-tui): rustfmt the merged permanent-dock test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(cmux-next): new chat routing lives in NewChatPlacement openAgentTab's dock routing moves to NewChatPlacement.opening, so PaneController stays under the 1000-line god-type limit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(cmux-next): splitRoom's doc names the chat dock rule (AppServices line budget) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): ChatDockRules imports CmuxNextDaemon for PaneModel and TabModel Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(cmux-next): fold PaneController's chat dock notes into fewer lines Base grew PaneController; merged with the tip it spanned 1004 lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: run cmux-next again (generated files never got a runner on 01c19d2) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): a strip-less chat dock and a zoomed chat keep the new tab here Cursor review on #18170: .newColumn is built for a chat dock with no scrolling column, which the daemon never keeps (an all-docked screen undocks), and a zoomed screen maps to its zoomed pane alone, so a zoomed chat looked like a lone chat and docked. resolve takes a zoomed seam, still ignored here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): chat dock routing drops the strip-less case, holds while zoomed, and opens the chat's context Cursor review on #18170: - The daemon never keeps a dock without a scrolling column (an all-docked screen undocks), so .newColumn is gone; it also dropped an explicit cwd and sent browsers and New Tab pages into the dock. - A zoomed screen maps to its zoomed pane alone; nothing docks or moves until the zoom ends. - A URL-less browser from the docked chat opens what the chat works on (#16620), in the strip pane. - A browser a lone chat leaves when it docks is recorded for Auto tabs.newTabKind, like any other browser (Cursor on #18223). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): a dock-bound chat stays hidden across its rekey and other docks; the strip shows beside the chat dock Cursor review on #18223: - pendingDock holds the provisional id, and the created id only after the creation reply, so the strip can list the created chat in between. - A finished dock clears every pending chat of the pane. - hidesStrip takes a chat alone in the strip for the screen's lone chat even when a chat dock exists. dockFinished is the finish seam, still clearing everything here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): a dock-bound chat stays hidden across its rekey and other docks; the strip shows beside the chat dock Cursor review on #18223: - The strip hides pendingDock through the store's aliases, so the tab that replaces a provisional chat is hidden from its first snapshot. - dockFinished removes only that chat; other chats on their way stay hidden. - The new chat's focus waits until the layout shows it outside the pane it moved from. - A chat alone in the strip beside a chat dock keeps its strip. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cmux-next): an edge drop does not split the chat dock; a workspace drop skips it Cursor review on #18290: a drop commits the split its preview measured (roomDecided) without splitRoom, so the chat dock split; a drop on a workspace in the sidebar targets the screen's first pane, the chat dock when it is on the left, which refuses it. dropSplit and workspaceDropPane are the seams, still with the old behaviour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cmux-next): edge drops and group actions do not split the chat dock; workspace drops skip it Cursor review on #18290: - A drop committing the split its preview measured (roomDecided) still asks ChatDockRules: the chat dock refuses it, for tabs and groups. - A drop on a workspace in the sidebar lands in its first pane outside the chat dock, so it is not refused. - tabGroup.moveToNewSplit refuses the chat dock, and tabGroup.moveToWorkspace skips it, like the drag paths. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: retrigger after an unrelated HomeCloudLinkTests timeout Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: retrigger after an unrelated DiffSidecarProcessTests flake Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: rerun swift tests after an unrelated timeout Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

Summary
Section D of the 2026-10-06 call: the agent chat is a docked region on the left, and tools are tabs in the area to its right, like the Codex app. The chat dock is the left dock column with the
agent_chatrole (#18169), and it never gets tabs of its own.What a person sees:
, menu, palette), New Browser and Cmd-T open a tab in the scrolling strip, never a split. The tab goes to the strip pane focused last and takes focus. A terminal gets only an explicit cwd and otherwise sends none, so the daemon's resolver picks it (decision NEW-TERMINAL-INHERITS-CWD, capabilitynew-terminal-cwd-v1`). Cmd-T on a chat would make another chat, so it opens the New Tab page in the strip instead.move-tab-to-columnwith adockpin andrespawn).dock-column-role-v1keep the old behavior.Builds on #18169 (the role). Supersedes the inference-based
next-chat-column-toolsbranch, which never got a PR.Follow-ups: the dock refuses splits and drops, and layout operations skip it. A
layout.dockAgentChatsetting and Dock/Undock Chat actions come after that.Testing
ChatColumnPlacementTestswas committed red before the fix (b85c214), with a stub that always answers "here". Runs usescripts/measure/suite-runner.shon a fleet runner.import CmuxNextBridge, so it did not compile. Re-run with only that import added (scratch dc19226): 5 failed (theDockedChatSendsTheToolToTheStrip,theStripPaneFocusedLastGetsTheTab,theDockedChatSkipsOtherDocks,theDockedChatWithoutAStripGetsANewColumn,aChatAloneOnItsScreenDocks). The 4 tests that expect "here" passed.ChatColumnPlacementTests(9 tests),NewTabKindTests,EmptyWorkspaceNewTabTests,StripNewTabTests,NewTerminalWorkspaceSettingsTests,AgentBrowserProfileTests,DockColumnCapabilityTests,DockColumnMappingTests,EncodingTests5353e55 applies NEW-TERMINAL-INHERITS-CWD to the strip tab and to the terminal a lone chat leaves behind. No test covers that wiring yet; the docked-column agent on Lawrence's side is handing over tests for open-pane routing.
The first live check (build of 5353e55 on a capture mini, real key presses) found a bug. New Terminal from a lone chat opened a terminal tab beside it, and the chat did not dock. A new workspace's screen is one split tree, and
ScreenLayout.column(containing:)only searches real columns, so the chat's screen looked like it had none.LayoutScreen.column(containing:)gives the implicit column.aSplitTreeScreenIsOneImplicitColumnfailed: no columns, so the placement was "here"ChatColumnPlacementTests,NewTabKindTests,StripNewTabTests,EmptyWorkspaceNewTabTestsLive check on a capture mini (fleet build of 977bcf8, job 2677fd2a). The routed steps used real foreground key presses; actions run from the CLI count as scripts and skip this routing. The setup was a new chat (Cmd-I) with the pane's other tabs closed via the CLI (setup only).
~, which the daemon picked because no cwd was sent.The chat's dock kept only the chat throughout.
Cursor review fixes (after the base merge that took this PR to Swift only):
theDockedChatWithoutAStripStaysHere(got.newColumn) andaZoomedChatDocksNothing(got.dockChat)ChatColumnPlacementTests,PanePaintHoldTests,DebugPageTargetTests.newColumn) is gone: the daemon never keeps a dock without a scrolling column (an all-docked screen undocks), and the path dropped an explicit cwd and sent browsers into the dock.tabs.newTabKind. No unit test covers these two wirings (nothing in the suite builds aPaneControllerwith an agent page).Proof
Window-only captures, with host names covered. Each image is before and after, side by side.
Changelog
Changed: in cmux-next, a terminal, browser or New Tab opened from the docked agent chat opens as a tab in the area to its right.
🤖 Generated with Claude Code
Note
Medium Risk
Changes user-visible tab/pane routing and layout moves for agent chat; gated on daemon capabilities but affects focus, cwd, and dock commits when enabled.
Overview
Routes new terminals, browsers, and New Tab pages opened from the docked agent chat (
agent_chatrole) into the scrolling strip instead of the chat dock, using newChatColumnPlacementlogic (recent strip focus, zoom, lone-chat detection).When a lone agent chat fills a screen, user-initiated New Terminal/Browser docks the chat in a new left column via
TabMoves.toNewDockColumnwithrole: .agentChatand a single daemon commit (respawnfor the tool left in the pane).TabMovesnow forwards optional dock role to the daemon (dock-column-role-v1).Tab lifecycle wiring: strip targets get focus; terminals from the dock use
daemonResolvesCwdso cwd inheritance follows the daemon resolver; URL-less browsers from the dock use the chat pane’s working context while opening in the strip; lone-chat dock can respawn a browser in the vacated pane.Adds
ChatColumnPlacementTestsfor placement rules (implicit single-column screens, zoom, strip-less dock edge cases).Reviewed by Cursor Bugbot for commit 39ea26e. Bugbot is set up for automated code reviews on this repo. Configure here.