cmux NEXT sidebar: drag the Chief in from Home, move it anywhere, drag it out to remove it
HOLD: held for dogfooding (sidebar change; coord-deputy fold order 10-23). Do not autoland on a SHIP.
Leo, 2026-10-21 (his exact words):
- "WHERE IS CHIEF IN THE SIDEBAR WHERE IS CHIEF AS OPTIONAL GUI CAN YOU TALK TO CHIEF"
- "IT ALREADY IS AFCCESSIBLE IN FUCKING HOME"
- "IAM SAYHING TOFUCKIGN OPTIONALLY MOVE IT BACK AND FORTH ON THE FUCKING SIDEBAR"
- "IT KINDA IS A FUCKING SIDEBAR ROW... BUT IT'S NOT ON BY DEFAULT YOU CAN JUST DRAG IN A CHIEF AND HAVE IT FUCKING BE DISPLAYED MOVED AROUND THE QUICK ACCESS THING OF IT LIKE A SPECIAL WORKSPACE"
Leo-ask: ask-02828fbad5
Leo-ask: ask-c2df0efe0c
Leo-ask: ask-97431a8bca
Leo-ask: ask-05fd281019
This finishes the optional Chief sidebar item from #22759 / #22867 instead of building a new one. Off by default, as before. Home keeps working unchanged; the Chief stays reachable there. Sidebar work on Lawrence's hold: an open PR to dogfood, not landing.
What changes
- Drag in: drag the Chief's row (or pinned tile) out of Home's conversation list sideways, and it goes on as an app drag (
ChiefDragSession, modelled onLinkDragSession). Over a window's sidebar the list shows the drop outline; releasing there runssidebar.item.add {chief}, the same as Add to Sidebar (top rows). It does nothing if the Chief is already placed. Other conversations keep Home's own pin drag. - Move anywhere: the document sidebar already let a built-in move into groups, Pinned and machine lists. There, the row lost its look; it now keeps the Chief's picture, status and badge (
SidebarItemListRowViewtakes the item'sSidebarItemInfo; the bridge also describes listed built-ins). - Unread or needs-you: the status was already "needs you" while a turn waits on a permission. Now the Chief item shows a dot exactly when Home dots its conversation (unread messages or Mark as Unread, never muted), unless a badge already counts subagents that need you.
- Remove (back to Home only): releasing the Chief beside the sidebar (past its sides) removes it; its card dims while it is out there, and the release point decides. Right-click ā Remove from Sidebar finds it inside a group or a machine list (
SidebarSectionResolve.itemfalls back to the document's records). The Chief counts as placed wherever the sidebar document places it.
Not in this PR: a Home drop lands in the top rows, not at the slot under the pointer. Moving it from there is the existing row drag.
Head 25da39eb24105668962d3ac9031988ead8a618e0
- Base merge:
feat-cmux-nextwas merged into the branch (ab07b924ca3, no force). The conflict resolutions keep both sides: the bridge describes listed built-ins with base'sclosedWorkspaceInfo;HomeSidebarViewtakes base's teammate guards; the listed row keeps its badge and activity layout with base'stitleTextX - labelInset. - Codex round 1 (BLOCK at 2a5761d2, https://github.com/manaflow-ai/cmux/pull/23933#issuecomment-6336852237). Tests came first (95d6d395e4), then the fixes (0cbb4d7b60 through 951f248d):
-
Placement comes from the whole sidebar document, not one window's filtered rows.
-
The tile's mouse-up passes its release point through both tile paths (the list's top block and the older band), so a stale
removesOnDropcan't remove a Chief released back over the sidebar. -
The Chief's unread comes from Home's mapped
unreadConversations, not the row's count. -
No god-file growth. The new code lives in focused files:
ChiefSidebarHost.swift,TopHomePageView+Chief.swift,HomeSidebarView+DragOut.swift,SidebarBridge+ChiefDragOut.swift,SidebarDocStore+PendingChief.swiftandSidebarRegionView+PointerEnd.swift.File Base Now AppServices 571 571 TopHomePageView 520 516 HomeSidebarView 474 474 SidebarListView+Drag 539 539
-
- Codex round 2 (BLOCK at 951f248d, https://github.com/manaflow-ai/cmux/pull/23933#issuecomment-6358274842). Tests came first (a784434c08), then the fixes (acbd817aab, 5eca851ec4):
- Placement includes pending changes.
SidebarDocStore.placesItemreads the mirror's rows: the confirmed document plus the changes the daemon hasn't echoed yet. Before, it read the confirmedrecords. An item that a pendingitem.addadded gets its body from the ops the mirror stamped (SidebarMirror.added). It observesversion, so the feed re-yields on every intent. The testplacementFollowsAChangeBeforeTheDaemonAnswersadds and then removes the Chief against a daemon that never answers.placesItemandChiefSidebar.isPlacedmust both follow each change at once. - A release over another window still drags out. The list's pointer monitor now passes the release's screen point. When a release that went to another cmux window or the desktop finishes its dispatch,
endReleasedGesture(at:)runs the same drag-out path a release in the list's own window does. Beside the sidebar the Chief comes off; otherwise the drag cancels as before. The testaReleaseSentToAnotherWindowStillDecidescovers beside (removed) and back over the sidebar (kept). - The unread tests go through the App's binding. They build real
AppServices, put the Chief's row inservices.home.groupMuting, and followChiefSidebar.Host.app(services). The only test seam is which conversation is the Chief's. With the old row-unread closure put back inHost.app(proof commit 0ce54d1ecff onchief-ui/23933-red-proof),theChiefItemDotsExactlyWhenHomeDoes(muted: false)andmarkAsUnreadInHomeShowsOnTheChiefItemfail.
- Placement includes pending changes.
- Codex round 3 (BLOCK at 5eca851e, https://github.com/manaflow-ai/cmux/pull/23933#issuecomment-6362196359). Tests came first (45f062f66b), then the fixes (55497b0c77):
- A pending Chief draws and comes off. The records the sidebar draws from, finds items in and plans band edits over now include items a change added before the daemon answered (
SidebarDocStore.drawnRecords,SidebarDocRecords.adding). The mirror keeps a pending item's record from the stamped ops and places it where its rows draw it. It forgets the record once a batch confirms it or the rows lose it (refused or undone). So a Chief dragged in comes off at once through Remove from Sidebar, its drag out or the App Store card. The testChiefPendingRemoveTestsadds the Chief against a daemon that never answers, checks that it draws, then runs the App'ssidebar.item.removeEverywhereby item id and by built-in name. - A release elsewhere ends the band's drag too. While the older top band holds a drag, it watches the app's releases (
SidebarRegionView+PointerEnd.swift). The local monitor is set with the drag and removed when the drag ends, however it ends, or when the region goes away. A release sent to another window or the desktop ends the drag after its dispatch, and the release point decides, as a tile's mouse-up does. The testaBandReleaseSentToAnotherWindowStillDecidesusesHarness(document: false)and covers a release beside the sidebar (removed) and back over it (kept, not stuck).
- A pending Chief draws and comes off. The records the sidebar draws from, finds items in and plans band edits over now include items a change added before the daemon answered (
- Codex round 4 (BLOCK at 55497b0c, https://github.com/manaflow-ai/cmux/pull/23933#issuecomment-6363161845). Tests came first (1fc21de75e), then the fixes (71daf297ab):
- No stale pending edits; the early draw is narrowed. Only a built-in (the Chief) now draws before its echo; any other item draws at its echo, as it did before round 3. A pending Chief can move and come off right away. An edit of its own fields, such as its label, is planned over the confirmed records, so it waits for the echo and is never drawn from the add's stale record. The test is
anEditOfThePendingChiefIsNeverDrawnStale. - One Chief.
sidebar.item.addleaves a Chief that is already placed alone, including one drawn before its echo (SidebarDocStore.placesItem, the same drawn view). Two quick drags in, or Get in two windows, make one Chief. The testaSecondAddBeforeTheDaemonAnswersAddsNoSecondChiefruns the App's action twice against a daemon that never answers. - The band's release monitor can't leak. It holds the region and the drag weakly, and removes itself at its first release if either is gone. It is also removed when the region leaves its window (
viewWillMove(toWindow:), inSidebarRegionView+PointerEnd.swift). The testaBandDragsMonitorGoesWhenTheSidebarLeavesItsWindowremoves the sidebar mid-drag.
- No stale pending edits; the early draw is narrowed. Only a built-in (the Chief) now draws before its echo; any other item draws at its echo, as it did before round 3. A pending Chief can move and come off right away. An edit of its own fields, such as its label, is planned over the confirmed records, so it waits for the echo and is never drawn from the add's stale record. The test is
- Codex round 5 (BLOCK at 71daf297, https://github.com/manaflow-ai/cmux/pull/23933#issuecomment-6364021043). Tests came first (c66f8a5586), then the fix (25da39eb24). The fix is one model that replaces the client's own pending-add records from rounds 3 and 4:
- The Chief has one item id. It is
SidebarLayoutDocument.chiefItemID,itm_chief, and every Chief add uses it. A pending Chief is the mirror's own row with that id, and the client keeps no record of it (SidebarDocStore+PendingChief.swift). It lives exactly as long as the mirror's change: confirmed, refused or undone. A refused remove puts it back, and the daemon refuses a second item with that id in any race.SidebarMirroris back to base. - Only the Chief draws before its echo. Settings, the account and any other item draw at their echo, as before.
- Edits wait for the echo, and are disabled rather than dropped. The item menu doesn't offer Show/Hide Label on a pending Chief (
SidebarBridge.pendingEdits), and the planner refuses the edit, so nothing is sent. - Tests, all hard asserts:
aRefusedRemoveOfThePendingChiefKeepsIt: the remove is refused, the Chief draws again, counts as placed, and a second add sends nothing.anEditOfThePendingChiefIsNotOfferedUntilItsEcho: the menu leaves out the edit and the planner throws. A confirmed item keeps its edit.anotherBuiltInDrawsAtItsEcho.
- The Chief has one item id. It is
- Size: about +1310/-85 against base, over the ~800 guideline. Most of it is tests and the code moved out of god files into small files. It stays one PR because it is an open dogfood PR on the sidebar hold.
Verification (fleet)
- At 55497b0c (round 3):
- App compile passed (job 51c2f5a9cbda2b2885e58ac4).
- These suites pass (step afde038a185ce3653d9c0918): ChiefPendingRemoveTests, ChiefTileDragOutTests, ChiefSidebarSharedStateTests, ChiefGroupFoldShiftTests, ChiefListedRowTests, ChiefSidebarItemTests, MouseDownSelectsTests, NewWorkspaceInGroupTests, SidebarChannelsAfterHomeTests, SidebarClickMovesNoRowTests, SidebarCmdNumberTwiceTests, SidebarDocAppSectionAddTests, SidebarEditModeTests, SidebarFocusedVisibleTests, SidebarGroupDragRailTests, SidebarGroupOrderTests, SidebarGroupReorderTests, SidebarListTilePressTests, SidebarManualOrderTests, SidebarTilePressTests, SidebarHeldDragTests and HomeUnreadIndicatorTests.
- The red commit 45f062f66b fails as it should (step 308827f5937d806ed7db8e9c). Both targets of the pending-remove test fail: the Chief isn't drawn and stays placed. Both band release-elsewhere cases fail: the drag stays alive, and the release beside the sidebar keeps the Chief.
- At 71daf297 (round 4):
- App compile passed (job 09055dce2d49777beb024adf).
- The suites from round 3 and SidebarBandHideTests pass (step 3bdc6fe9aa1ed5eeabf75b16).
- The red commit 1fc21de75e (the round-3 code with the round-4 tests) fails as it should (step 591d51fab40b3a43ebe4d89b). The second add draws two Chiefs, the label edit draws stale, and the band monitor outlives the window.
- At 25da39eb (round 5):
- App compile passed (job 5ef3e4761fa75de19a9ae452).
- The same 23 suites pass (step 0c0636cc89c3d9e0be3aaa7a).
- The red commit c66f8a5586 (the 71daf297 code with the round-5 tests) fails as it should (step beff1f03ecc08fc0bb9d4576):
- The menu offers the pending Chief's label edit.
- A pending Settings item draws.
- After the refused remove, the Chief is neither placed nor drawn, and a second add is sent.
- App compile: passed at acbd817a (
cmux-ci compile-check --app, job f74146fca2017721c8ffb41e). The later 5eca851e changes only a test file. - At 5eca851e: ChiefSidebarSharedStateTests and ChiefTileDragOutTests pass (step 90d87e70df06b960bfedcc54).
- At acbd817a: these pass (step 8dff2939d5d30a41f4d6e478): ChiefTileDragOutTests, ChiefListedRowTests, ChiefSidebarItemTests, HomeUnreadIndicatorTests, SidebarTilePressTests, SidebarListTilePressTests, SidebarHeldDragTests, MouseDownSelectsTests, ProfileBarDotReorderTests, SidebarPressDoesNotFocusTests, ChiefGroupFoldShiftTests, SidebarDocAppSectionAddTests and SidebarGroupDragRailTests. In the same run ChiefSidebarSharedStateTests crashed (
NSAppnil); 5eca851e fixes that by starting NSApplication first. - Red commit a784434c: fails as it should (step 05131519cecddc462ba8e836): the placement-before-the-answer test, and the release-beside-the-sidebar case sent to another window.
- Old binding put back (0ce54d1ecff): both unread tests fail (step 277298aafe25f8d6a6510b43).
- Base red: SidebarDragKeepsGroupsTests
aGroupsLastMemberDraggedOutKeepsTheHeaderUntilTheDropfails at base c467f835719 too (step f5a11d5dc5354c1e1355323d).
Reds at 5eca851e, all attributed to base or infra
- cmux-next checks: "No new SwiftUI" and "Checks job structure" are red on base 5526377b2ff (job); this PR touches neither.
- rust workspaces:
Native/OptChat/chief-turnhas no.github/rust-workspaces.tomlentry. It came from base a5a21d3e62d, and base 6ef5b51126e is red the same way (job). - release-notary and Guard status: the same failures as on every recent base commit.
- swift test: the job failed in "Set up runner", which is infra, and has been re-run. At 951f248d, the CI motion and timing failures (SidebarPriorityMotionTests, SidebarHoverCardRetargetBenchTests) passed on the fleet at both base and head.
Capture steps-b975d62e1e at 2a5761d28c47. It predates the review fixes, which don't change how the placed Chief looks.
| Light | Dark |
|---|---|
![]() | ![]() |
Taken over from chief-sidebar-2 (stopped) by chief-ui on cosmic-gray.
Agent session: cosmic-gray
š¤ Generated with Claude Code

