cmux NEXT sidebar: the Priority view lists chats on remote and cloud machines

Merged
TE
16d ago
+351-24

Summary

The Priority view ranked only this Mac's acpmux chats, the peers that acpmux mirrors, and the Chief home's subagents (AgentPriorityChats.stores = [.shared, .chief]). A chat on a Cloud VM, an SSH machine or a paired server that is not an acpmux peer never showed up.

It now also lists every agent chat tab on the other machines' daemon trees, the ones MachineRegistry already mirrors, and ranks them with this Mac's chats. The state of a remote chat comes from the notice that machine's own daemon posts on its tab (agent_chat_notices.rs, cx-sg1qz):

Unread notice on the tabRow
warning ("needs input")Needs you
error ("failed", "stopped responding")Failed, with the notice text as the error
info ("finished")Done (unseen result)
noneIdle

That daemon clears its notices once the chat is seen or answered anywhere, so a remote row drops back to idle the same way. The row preview is the notice text (DaemonStore.notificationText(for:)). One limit: remote rows never show Working. A daemon tree carries no turn-in-progress state, and getting one would need new remote access, which this PR does not add.

Machine names.

  • A remote row's tag is MachineRegistry.machineName(daemon.machineID), the name the sidebar shows. That is the name MachineColor(name:) in #22763 keys on.
  • An acpmux peer chat resolves its peer to a machine when one matches: an SSH host, short host or label, else a Cloud machine title or server name. Otherwise it shows the peer name.
  • Rows for this Mac (and a server reached at a Unix socket here) have no tag. Machines.local returns nil until sidebar.showLocalMachine lands with #22763. That PR then passes this Mac's display name there.
  • SidebarPriorityRowView.machineColor is unchanged.

Merged with base. origin/feat-cmux-next at 6100943dbaa6 came in with a normal merge (4eaf999b9eec) after #23531 (Red CI) and #23577 (reorder motion) landed. Every entries call now passes both #23531's failingChecks and this PR's machine tag. Red CI is computed only over this Mac's and the Chief home's lanes. The session tree reads pull requests from a lane's folder and the URLs it opened, and a remote chat tab carries neither, so a remote row is never .ciFailing. A test asserts this.

Remote state: what the rows read and what they can do

Read. For each machine MachineRegistry already mirrors (Cloud VMs, SSH machines, paired servers) and whose feature is not turned off (MachineRegistry.daemon(machine:)), the rows read that daemon's DaemonStore tree, which the app already holds for the sidebar:

  • each agent chat tab's title (displayTitle) and agentSession ref (session id, harness);
  • the tab's unread notification marker (level and id);
  • the notice text the store already keeps for the hover card (notificationText(for:));
  • the notice time when the store has one;
  • the connection state and first snapshot, which gate mark pruning.

The machine name comes from MachineRegistry.machineName.

No new remote access. There is no new request, socket method, relay method, allowlist entry or subscription, and nothing is sent to the other machine. The notices come from that machine's own daemon (agent_chat_notices.rs), which already posts them on these tabs, and they already show in the sidebar rows, hover cards and banners.

What a remote row can do:

  • Open: reveals the tab that shows the chat on its machine, the same tab the sidebar row opens.
  • Mark read: only for a Done or Failed row (canMarkRead). It is a local mark: the row drops to Idle here until that machine posts a new notice, and the other machine's notice is left alone. A notice with no time counts from when the app first saw it, so each new notice is a new state and a mark on the old one no longer holds.
  • Pin and snooze: local marks, as for any row.

What a remote row can't do:

  • Archive is a no-op: there is no acpmux socket for that chat here, which matches peer chats today.
  • Working and Red CI never show: the tree carries no running-turn state and no pull request.
  • Marks are pruned only while every tree is connected and loaded, so a dropped SSH link does not drop a remote chat's pins.

Testing

New suite SidebarPriorityRemoteChatsTests:

  • aChatOnACloudOrSSHMachineIsRankedWithThisMacsChats: chats on two remote trees rank with this Mac's lanes in the right tiers, and each is tagged with its machine's display name.
  • aPeerChatNamesItsMachineAndThisMacIsTaggedOnlyWhenAsked: a peer resolves to its machine name, an unmatched peer keeps its own name, local rows have no tag until a local name is passed, and a peer chat that its machine's tree also lists shows once.

Red on the tests-only commit, run on the fleet:
cmux-ci run --class light --script scripts/ci/package-test-lane.sh --ref 901267536151fbffe38ab7b6180716ec3c5720bd --key pv-prio-remote-9012675361-2 --arg=suite --arg=Packages/macOS/CmuxNext --arg=SidebarPriorityRemoteChatsTests --env CMUX_CI_XCODE_APP=/Applications/Xcode_26.6.app
Step 40898e0eee32dbfc1a7bb95a failed: the test target does not compile on base because AgentPriorityChats.Machines and SidebarPriorityMachine do not exist. The base has no source for remote chats at all.

Green on the merged head 4eaf999b9eecdef4600e24464f114b3c58fd5adc:

  • Step 18ff9bbc652b81ba6203b414 (key pv-prio-remote-4eaf999b9e-5) passed all 4 suites: SidebarPriorityRemoteChatsTests (3/3, including the new aRemoteRowIsNeverRedCIAndMarksReadAsItsNoticeAllows), SidebarPriorityRedCITests, AgentPriorityRankingTests and SidebarPriorityRowActionsTests.
  • Step e7a61e161156be77c0659c8f (key pv-prio-remote-4eaf999b9e-6, --target-worker aws-m4pro-9) passed SidebarPriorityMotionTests (4/4).
  • cmux-ci compile-check --ref 4eaf999b9eecdef4600e24464f114b3c58fd5adc --app passed (job f7775be7c988a223577c2df4).

Before the merge: step 39a6ee7ea450ac9e21e1d4fe passed and compile-check job 2646f709dc6b2480f85e24b2 passed at 635ce4396601.

python3 scripts/cmux-next/prepush-gate.py reported no new violations on every push.

Observed / Not run

  • Observed: the fleet red and green steps and the app compile-checks above.
  • Not run: a live tagged build with a real Cloud VM or SSH chat. The media-tour label requests the native capture.
  • Read only, not run: the remote daemon's notice levels (cmux-tui/crates/cmux-tui-core/src/mux/agent_chat_notices.rs), which this mapping relies on.

Localization: no new user-facing strings.

Changelog

Added: The sidebar's Priority view lists agent chats on Cloud VMs, SSH machines and servers, tagged with each machine's name.

Proof

Native sidebar row. media-tour label added for the capture.

Agent session: cosmic-gray

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

The Priority view now ranks agent chats on Cloud VMs, SSH machines, and paired servers, not just this Mac's acpmux chats and the Chief home's subagents. It reads only state the app already holds—each connected machine's daemon tree and the notices its daemon posts on tabs—so no new remote call is added.

Row state comes from the notice on the chat's tab: a warning ("needs input") becomes "Needs you", an error ("failed", "stopped responding") becomes "Failed" with the notice text, an info notice becomes "Done (unseen result)", and no notice is idle. Remote rows are tagged with the machine's sidebar name; an acpmux peer resolves to its machine when one matches, otherwise it keeps the peer name. This Mac's rows stay untagged until sidebar.showLocalMachine lands (#22763).

Opening a remote row reveals the tab that shows the chat on its machine. Mark read, pin, and snooze work as they do locally, and marks are pruned only while every tree is connected and loaded so a dropped SSH link doesn't wipe remote pins. Archive does nothing for a remote row—there's no acpmux socket for it here. One limit: remote rows never show Working, since a daemon tree carries no turn-in-progress state.

New test suite SidebarPriorityRemoteChatsTests covers ranking with local lanes, machine tagging, peer resolution, and local rows staying untagged by default.