cmux-next: active team, with a switcher in Settings > Accounts
Summary
cmux-next now has one active team per signed-in account. Every team-scoped feature reads it, and Settings > Accounts has a switcher.
ActiveTeam(CmuxNextCloud/Auth/ActiveTeam.swift) is the one observable source of truth. It holdsteams,id,team,managedTeamID,isSwitching,canSwitch,select(_:)andrefresh().CloudAuth.teams,teamIDandmanagedTeamIDnow forward to it, so existing readers (the Cloud API client, CodeRouter, phone access,cloud.status) already follow it. Devices and Mac Screen (#20426) can readcloud.auth.activeTeamwithout choosing a team themselves.- A switch is now saved for the account. The old
CloudAuth.selectTeamwrote only this device's cache (cmux.auth.selectedTeamID). At the next restore, the account's saved selection (Stack Auth's selected team) won, so a switch was undone on relaunch.selectnow goes throughAuthCoordinator.selectTeam(id:), which saves the selection first. If the save is refused, the current team stays active. - Defaults and reset (existing coordinator behavior, now covered by tests): with no selection, the first team is active. If the account leaves the active team, the first remaining team becomes active. Sign-out clears the selection. A device restricted to a managed team sees and uses only that team.
- Settings > Accounts > Active Team is one settings row: the label, its help line, and the page's menu Select showing the active team. Opening it lists the teams with a checkmark on the active one. With one team, or on a managed device, the menu is shown disabled. A switch updates everything live:
AppServices.startCloudreloads the machine list and the CodeRouter accounts when the active team changes, whatever surface made the change. Phone access already restarts on a team change. The Refresh button also re-reads team membership, so a team left in the browser disappears from the list. - The palette action
openTeamPickeris now titled Switch Active Team… (id,cmux cloud team-pickerand ⌥⇧⌘T are unchanged) and uses the sameActiveTeam.select. The duplicate button was removed from the Accounts section actions. - A refresh in flight no longer undoes a switch. The fix is in the shared
CmuxAuthRuntimeAuthCoordinator.refreshTeams(found in review), so iOS gets it too. Rapid switches end in the newest choice: a choice made while a save is in flight waits, replacing any earlier waiting one, and is saved when the running save lands (found live on mini-cmux10s: four overlapping switches used to end in the first one). coderouter.*over the socket refuses ateamIdthat is not the active team (not_active_team). OmittingteamIduses the active team, as before.accounts.listnow reportsactive_team.
Backend
No backend change was needed. Stack Auth already provides "list my teams" (user.listTeams) and a selected team saved per user (selectedTeam / setSelectedTeam). Gaps:
- No roles.
CMUXAuthTeamhas onlyid,displayNameandslug, so the switcher cannot show a role. Devices permissions (view-only vs full control) will need a membership role or permission read. - Server pairing uses a different team id.
CloudPairingSourcereads the Worker's team fromteam.policy.get, which is not the Stack team id.ServerModel/ServerHeadlessApprovaltaketeams.firstfrom that one-element list. This PR does not route them throughActiveTeam, because there is no mapping from a Stack team to a Worker team yet.
Testing
ActiveTeamTests(CmuxNextAppTests) andAuthCoordinatorTeamActionsTests.aRefreshInFlightDoesNotUndoASwitch(CmuxAuthRuntime): red, then green, on the fleet. Steps are in the review comment.ActiveTeamTests.theLastSwitchWinsWhileOneIsSaving: red at 6a6253017f0 (Caught error: .switching, cmux-ci step d1737eed10f57c68301f6d59), green at 1d335fe2bb7.webviews/src/pages/settings/accounts.test.tsx(the picker row, its menu and switch, the disabled one-team and managed states, signed out) passes in the full webviews suite on the fleet (cmux-ci step 46c2a887aa7bad4925eff007 at 3401e42d0ff). The suite's other failures are base findings in files this PR does not touch.- Live on mini-cmux10s with the agent test account (two teams), tag team4 at 1d335fe2bb7: switch from the picker and from the palette's Switch Active Team… (effect within 1 s, no relaunch), persistence across a relaunch, a
coderouter.*call naming the other team refused withnot_active_team, rapid overlapping switches end in the newest choice, sign-out clears the team and hides the row. The account was left on cmux Agent DEV's Team. - Trust note: https://github.com/manaflow-ai/cmux/issues/13742#issuecomment-6225940610
Proof
Settings > Accounts with the Active Team menu open (tag team4, mini-cmux10s, composited window snapshot):
Review: a6caffc8f318d4755261753252d8003d8fc44035 (subagent reviews of the picker and of the merge, size-cap and last-wins changes; findings and resolutions in the PR comments)
Runtime test: live on mini-cmux10s, tag team4 at 1d335fe2bb7 (cmux-ci build e15fd4638e41b8edf755a08d); a6caffc8f31 adds only the re-check of a queued choice (ActiveTeamTests on the fleet)
No capture: the Active Team menu needs a signed-in account with two or more teams, which a cmux-ci capture scene cannot sign into; the snapshot above is a real tagged build (team4 on mini-cmux10s).
Since a6caffc8f31: merged current feat-cmux-next (b14f1f27654a, 1413f093e71b). The base had made Team Picker a Cmd-Shift-P step with a team argument; the merge keeps that step and switches through ActiveTeam.select, titled "Switch Active Team…". Generated exports regenerated (fleet settings export, PR autofix action surfaces). Review receipt at the head is in the PR reviews.
Changelog
- Added: Settings > Accounts shows your teams and lets you switch the active team; Cloud machines, CodeRouter accounts and phone access follow it.
- Fixed: A team switch now lasts after relaunching cmux.
🤖 Generated with Claude Code