Account-first Phase 3: Claude Cowork / Desktop accounts - #1032
Account-first Phase 3: Claude Cowork / Desktop accounts#1032robinebers wants to merge 5 commits into
Conversation
Cowork sandboxes now carry per-sandbox identity: sessions from the default login stay on the default card, sessions from a known config-dir account attach as its log roots, and a distinct Desktop login becomes its own card backed by Desktop's org-pinned Safe Storage credentials. The default card's Cowork walk is partitioned the moment another account's sandboxes exist so no spend bleeds between cards. Co-authored-by: Cursor <cursoragent@cursor.com>
…ing on a truncated walk Two review findings: an identity file that omits its org half must not split one login into two cards (routing now compares uuid-first via sameClaudeAccount), and a cowork walk that hits its time budget must not drive routing from a partial sandbox list (the pass skips wholesale and retries next launch). Co-authored-by: Cursor <cursoragent@cursor.com>
Review follow-up: the partition (and scoped cards' log roots) is launch-frozen by design — a live walk would count another account's brand-new sessions on the wrong card until routing catches up, the exact bleed the partition exists to prevent. Missing-until-relaunch is the safer failure; files inside known sandboxes still update live. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 015a575. Configure here.
Review finding: a distinct Cowork account without an org pin builds no card, so gating the unpinned fallback on claudeCards.isEmpty left the default card free to follow Desktop's active org — that account's usage pool. The gate now also checks the partition, which is set whenever another account's sandboxes exist. Co-authored-by: Cursor <cursoragent@cursor.com>
Field find on a Max 20x account showing "Max 5x": v2 held the current login only as an expired entry plus a live profile-only leftover with stale 5x tier metadata, while the login's live full-scope token sat in v1 — and the v2-first short-circuit never looked. Both generations now compete in one ranked pool: token quality outranks cache generation, generation only breaks quality ties (still ahead of raw expiry). The v2-tombstone-suppresses-v1 rule is unchanged. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Just discovered a bug that when logged into Claude Code but changing the account while OpenUsage is running, that this logic now shows 2x the same account despite Cowork still having knowledge over two different accounts. This needs fixing. |
Bug: bare-id Claude account disappears after default-home swapWhat I expectedTwo Claude cards (as before the swap):
What actually happensOnly one Claude card renders after Personal takes over the default home. Team is discovered every launch, then intentionally dropped. Repro (this machine)
When it still workedThrough ~2026-07-30 both cards refreshed ( Root causeIn guard record.id != "claude" else {
// The bare record's account has moved out of the default home into a side login
// while another account occupies the default. The bare CARD is the default home's
// runtime, so this record can't render under its own id this launch. Proper swap
// support re-points this in Phase 4; until then the parked account stays hidden.
AppLog.warn(.config, "discovery: the claude record's account now lives outside the default home; its card is unavailable until swap support lands")
continue
}So:
This matches the plan’s “swap re-points sources” story, but Phase 4 isn’t here yet — and today that gap is user-visible data loss (a known, still-found account with rename/layout/history simply stops rendering). Expected fix direction (Phase 4 or a Phase 3 follow-up)When the bare-id account no longer holds the default home:
Happy to help verify a patch against this machine’s registry state. |
|
Superseded by #1140, which rebuilds Claude multi-account support on the current main branch with account-owned runtimes, Desktop and CLI discovery, account-safe iCloud synchronization, and comprehensive regression coverage. |

TL;DR
Cowork sessions become account-aware: each sandbox names the account that ran it, and a Claude Desktop login distinct from every CLI login gets its own card — backed read-only by Desktop's org-pinned Safe Storage credentials, with its Cowork sessions as the card's spend.
What was happening
What this changes
ClaudeCoworkDiscovery(new): a launch-time walk over Cowork's session sandboxes that reads each sandbox's own.claude.jsonidentity file (no keychain, no credentials, 400ms budget). The walk itself is shared with the spend scanner, so discovery and scanning can never see different sandbox sets.ClaudeDesktopAuthStore.loadaccepts an organization pin; a Desktop-backed card reads exactly its account's cached token, never Desktop's active org. NewClaudeCredentialScope.desktopOnly(organization:).ClaudeLogUsageScanner: gainscoworkRootsOverrideto scan an explicit sandbox set (the partition); cache identity includes the partition so changing it invalidates correctly..desktopsource kind on account records; Desktop-backed cards reuse the whole existing account-card pipeline (layout, rename, iCloud identity, CLI/API matching).Heads-up
Tests
.desktopOnlyscope, pinned standard fallback, and the scanner partition.Made with Cursor