composer: the environment picker's This Mac keeps this Mac's name; a chat's Cloud machine stays under Cloud

Merged
TE
5d ago
+121-4

Leo, 2026-10-30, on the composer's environment picker (nightly 4113890): "the ui is so ass in general for this tho". His screenshot: under This Mac the only row is kind-aqua-sandpiper, a Cloud machine, and the real Mac is not listed at all.

Cause

When a chat is seeded onto another machine (a peer or a Cloud machine), the native handshake sets machineName to that machine (AgentPaneHandshakeReply.swift, if let peer = seed.host { handshake.machineName = peer }). The page passed machineName as the picker's local name (App.tsx localName={machineName} → ComposerContext.availableComputers), so the This Mac row was titled with the Cloud machine, and this Mac's own name was gone.

Change

  • The handshake also carries localMachineName, always this Mac's own name (the Sharing name). machineName keeps its meaning (the chat's machine) for the surfaces that read it.
  • The picker's This Mac row reads it through thisMacName (environments.ts). With an older host, machineName counts only when it isn't the chat's peer or Cloud host; otherwise the row reads "This Mac".
  • The Cloud machine stays where it belongs, under Cloud and VMs.

Not in this PR: the "Where should this chat run? On your computer / In the cloud" choice that comes first. #26801 starts it, and another lane is folding that stack; this change doesn't touch the Cloud row it adds.

Screenshots

Gallery state agent-pane.composer-context/environment-picker-cloud-chat: a chat seeded onto the Cloud machine kind-aqua-sandpiper, with an SSH peer gpu-box. Synthetic data, gallery advisory run at a429b600, 2x, cropped to the menu. The before shots come from a temporary gallery state that gave the row base's name (the chat's machine); a later commit removed that state.

BeforeAfter
Dark
Light

Before, This Mac is titled kind-aqua-sandpiper, the Cloud machine, so the same machine shows up twice and this Mac is missing. After, This Mac reads office-mac (this Mac's own name), and kind-aqua-sandpiper appears once, under Cloud and VMs, with the checkmark.

Viewed after image: yes
Visual verdict: The after list is the existing picker with the right name in This Mac's row: no new controls, nothing repeated per row, and it fits in a 400px pane, so Leo would accept it next to ChatGPT or Claude.

No capture: the native change only adds a localMachineName string to the handshake and draws nothing. The visible change is the webview row shown above.

Design spec: leo-workspace design/environment-picker.md (rule 1; Leo's words and screenshot recorded there). This PR adds the spec's entry to .github/design-surfaces.json.

Gallery: agent-pane.composer-context/environment-picker-cloud-chat, agent-pane.composer-context/environment-picker

Tests

bun test test/environment-picker.test.tsx covers this: 53 pass, 2 of them new. One test checks that a Cloud machine is never listed under This Mac and that This Mac keeps this Mac's name, for both a current and an older host. The other is a unit test of thisMacName.

Red/green: with thisMacName returning machineName (base's behaviour), both new tests fail, and the This Mac row reads kind-aqua-sandpiper instead of this Mac's name. With the change, both pass.

Observed / Not run

Observed: the test file above (red, then green); oxlint and vp fmt --check on the changed webview files; scripts/cmux-next/prepush-gate.py with no new violations. scripts/web-lint.sh's other failures (design tokens, layers, format) are all in pages/settings/styles.css and settings files, which this PR doesn't touch (base).
Not run here: the webview type check (left to CI on this shared host) and the Swift compile (fleet/CI). The Swift change only adds one optional Codable field and sets it.

Changelog

Fixed: the environment picker's This Mac row shows this Mac's name, never the Cloud machine a chat runs on.

Risk: low. One optional handshake field the page reads when it's there; pages that predate it ignore it.

Agent session: agent session

šŸ¤– Generated with Claude Code