cmux NEXT: see and accept team invitations in Settings > Accounts
Leo-ask: ask-6ef2624788
Leo, routed as "Invite teammates by account (Chief's second pick; also Leo's ask-ed33ccaa7a on multiplayer and sharing)". Leo's ask-ed33ccaa7a: "how's the state of multiplayer/inviting teammates/inviting people to see your chats/sharing?"
What was missing
Inviting a teammate by email already works end to end from NEXT (Home's Invite to Team, home.inviteToTeam, POST /api/teams/:id/invitations, which emails the invitation). The invitee could only accept on cmux.com, though: NEXT never showed an invitation addressed to you.
What this changes
Settings > Accounts now has Invitations to You above the team list: each team that invited one of your verified emails, who invited you, the role and the expiry, with Join Team and Decline. Join Team re-reads the team list and makes the joined team active (the server already saves it as the account's selection), so the team's Cloud machines are the ones cmux lists next. An invitation answered elsewhere (another device, the emailed link) says why and leaves the list.
CmuxAuthRuntime:CmuxTeamsAPI.receivedInvitations(),acceptInvitation(id:),declineInvitation(id:)over the team API's existing routes (GET /api/teams/invitations,POST /api/teams/invitations/:id/accept|decline;web/services/teams/received.ts), which take the signed-in user's verified email as the proof. No backend change.CMUXAuthCore:CMUXReceivedTeamInvitation,CMUXTeamJoin, and threeCMUXTeamErrorcases:invitationInvalid(410invitation_invalid, 404invitation_not_found),emailMismatch(409),seatLimit(409).AuthCoordinator:receivedTeamInvitations(),acceptTeamInvitation(id:)(refreshes the team list, then selects the joined team),declineTeamInvitation(id:).CloudAuthandAccountsTeamBackend: the same three;AccountsTeamsModelreads the invitations with the roles and runsteam.accept/team.decline(the invitation id goes asteam).- Webview:
AccountsTeams.tsxdraws the group from the host's texts; mock host and two gallery states (accounts-team-invited,accounts-team-joined). - Strings: 10 new keys in CmuxNextAccounts' catalog, in all 21 locales (most of the line count).
- What's New highlight:
team-invitations-in-settings.md.
The logic is the thin client of an existing HTTP API inside the existing Swift auth stack (CmuxAuthRuntime is shared with iOS), so it stays there rather than moving to Rust.
Verification
cmux-ci run --class light --script scripts/ci/package-test-lane.sh --arg suite --arg Packages/Shared/CmuxAuthRuntime --arg CmuxTeamsAPITests,AuthCoordinatorTeamManagementTests --ref 9de2d7cb48fb75cb4e99cc4b1cfc1f66ad3626d6: both suites pass (20 tests, 4 new: list/accept/decline wire, refusal mapping, coordinator join-and-activate, decline).- AccountsTeamManagementTests (CmuxNext, 3 new) and the webview check plus settings tests: see the comment below.
python3 scripts/cmux-next/prepush-gate.py: no new violations.
Observed / Not run
- Observed: the fleet suites above.
- Not run: a live accept against the dev backend with two accounts; the cloud-demo lane does that readback separately and posts it here.
- iPhone parity: not in this PR; follow-up.
Changelog
Added: Settings > Accounts shows team invitations sent to your verified email, with Join Team and Decline.
No capture: webview UI; the gallery states accounts-team-invited and accounts-team-joined render it.
🤖 Generated with Claude Code
Agent session: agent session
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Settings > Accounts now lists team invitations sent to your verified email, with Join Team and Decline. Previously, invitees could only accept on cmux.com; now the joined team becomes active so its Cloud machines show up next.
New Features
- Invitations to You shows the inviting team, inviter, role, and expiry above the team list.
- Join Team re-reads the team list and makes the joined team active; Decline removes the invitation.
- Invitations answered elsewhere leave the list with a reason, covered by the new
invitationInvalid,emailMismatch, andseatLimiterrors.