Start refusals: a teammate's machine offers New Cloud Machine; Choose Folder on another machine opens its folders
Leo, 2026-10-31: "let's work on improving this a LOT" and, on refusals, "we can't simply block always. we need to be able to get stuff running asap. lots and lots of bare prototypes so we can evolve our app as we go."
Stacked on #29145 (its commits show here until it lands; this lands after it). Fixes two follow-ups from its review:
What changed
A teammate's Cloud machine says so (#29214). A teammate's link has no owner answer, so AgentSessionAttachClient.ownedConnection refused with agent_session.host_unverified before the start, and the card's New Cloud Machine action (mapped from agent_session.team_vm_blocked) never showed.
- The Cloud link now keeps the Cloud API's exact
vm_kind: "team"answer next to the owner one:CloudLinkSocket.callerIsTeammate(app link, fromcloud.machine.connect),CloudAttachEndpoint.callerIsTeammate/CloudMachineLink.callerIsTeammate(legacy link). It is false whenever the same answer says owner, and false once the link ends. AgentTabStore.runRemoteStartchecks it first: on a teammate's link the start is refused asagent_session.team_vm_blocked("%@ is a teammate's machine, so its owner starts chats there. Pick your own machine, or create one with New Cloud Machine.", the existinghandlers.refusal.agentRemoteStart.teamVM, already translated in #29145), and nothing is sent to the machine. Ahost_unverifiedfrom the owner check on a link that turned out to be a teammate's while the start connected gets the same code (AgentRemoteStartRefusal.classified).- The owner check is unchanged. The teammate answer grants nothing; it only names the refusal. A non-owner still never gets a start, and a machine whose kind is unknown still gets
host_unverified.
Choose Folder on another machine opens that machine's folder menu (#29213). The card's Choose Folder called workspace.chooseFolder, which the host refuses on a remote chat.
startRefusalRoute(action, remoteChat)(startRefusal.ts, one new function after the existing ones) sends a remote chat's Choose Folder to the composer's Location menu (openPicker("Location")). This Mac's open panel stays the fallback when the menu isn't mounted.- The remote
project.listreply is markedmachine: true, and the pane passes those folders to the composer asmachineFolders. While the chat's own machine is picked, the Location menu lists them (its work folder and the folders under it, from #29145'sagent-session-folders-v1). Before this, a remote chat's menu listed only folders its chats had used. A pick there becomes this chat's folder throughworkspace.useFolder(the remoteuseRemotepath), not a new chat. Local panes and other machines' picks work as before. - SwitchNotice.tsx is untouched, and startRefusal.ts gets only the new function, so the "Share machineā¦" work on top of those files merges cleanly.
Risk: low. The start's owner gate is unchanged. The only new path refuses earlier, and the folder menu change applies only when the host marks a list as the machine's own.
Tests
- Swift (
AgentTabRemoteStartTests): a teammate's machine is refused asteam_vm_blockedand its endpoint is never dialed;classifiedmaps onlyhost_unverifiedon a teammate's link; ateamsocket answer is a teammate's and an owner answer never is. The existing owner start tests (vm_kind: "owner", the work-folder fallback) still pass through the shared setup. - Web (
startRefusal.test.ts): Choose Folder on a remote chat routes to the machine's folder menu, on this Mac to the panel, and New Cloud Machine to the Cloud connect. cmux-ci compile-check --appandcmux-ci test --setup webviews(acpmux suite, tsc, biome): see the comments below.
Agent session: agent session
š¤ Generated with Claude Code
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Fixes two follow-ups from the #29145 review: a teammate's Cloud machine now refuses to start chats clearly and offers New Cloud Machine, and Choose Folder on a remote chat opens the other machine's folder menu instead of this Mac's.
Teammate's machine refusal (#29214)
- A link whose Cloud API answer is
vm_kind: "team"refuses the start asagent_session.team_vm_blockedbefore anything is sent; the failed card offers New Cloud Machine beside Retry. - The owner check is unchanged: only an owner answer ever sends a start, and
host_unverifiedon a teammate's link becomes the teammate refusal.
Remote folder handling (#29213)
- cmux-tui now serves
agent-session-folders-v1(the machine's work folder and the folders under it), so a remote start with no folder falls back to it instead of failing. - Choose Folder on a remote chat opens the composer's Location menu listing that machine's folders; a pick there becomes the chat's folder through
workspace.useFolder. - A fresh chat whose session has not started yet routes Choose Folder by its connection's origin.