feat(desktop,host-service): provider account switching in the Usage tab
Merged
KI
3mo ago+2367+2367+0123456789012345678901234567890123456789-51-51-01234567890123456789
Summary
- The Usage tab now manages multiple Claude Code / Codex logins: add a second subscription as its own profile, pick which account new terminals and agents launch with, re-sign any login into a different account, and remove a profile — all without Superset ever touching a credential store.
- The account view groups cards under provider sections (each with its own Add account button); cards carry a
Defaultpill, a hoverMake defaultaction, status chips, and a⋯menu (Switch sign-in… / Remove…). The system-default login is never removable.
Why / Context
People with two subscriptions (personal + work) hit session limits on one account while the other sits idle. Discovery already listed every login's quota side by side; this adds the ability to act on it. The most requested action from the token-spend feedback thread was exactly this: start new work on the account with headroom.
How It Works
Switching is selection-by-env, not credential materialization:
host_settingsgainsdefault_claude_config_dir/default_codex_home(migration 0024, plain ALTERs; null = system default).buildTerminalAgentLaunchand new-terminal PTY env (createTerminalSessionInternal) overlayCLAUDE_CONFIG_DIR/CODEX_HOMEfrom that pointer, so preset launches, host-side agent runs, and a manually typedclaudeall follow it. Per-agentenv_jsonstill wins; a vanished profile dir falls back to the system default. Running sessions keep the account they spawned with (env is baked at spawn).usage.quotaaccounts now carryselection+isDefault(decorated per query, so switching reflects instantly without re-hitting provider endpoints).- New host procedures:
usage.logins(local-only discovery — pollable while a sign-in is pending; Codex homes carry anauth.jsonfingerprint since Codex identity isn't knowable offline),usage.setDefaultAccount,usage.removeAccount,usage.prepareClaudeProfile. - Making a Claude profile the default (or detecting its sign-in) merges Superset's lifecycle hooks into the profile dir (
ensureClaudeManagedHooksAt/ensureCodexManagedHooksAt, new agent-setup exports) and marks CLI onboarding complete — without these, agents on the profile lose status reporting, and the first launch opens the CLI's first-boot wizard where a stray Enter can start an unwanted login. - Add account / Switch sign-in never automate OAuth: the dialog hands the user the provider's own login command for the right dir, then watches local state (profile discovery / state-file email / auth.json fingerprint) to detect completion.
- Removal deletes the profile dir plus its scoped keychain items (path guards: inside
$HOME, never a default home), clears a default pointer aimed at it, and drops the host's quota cache.
Manual QA (driven end-to-end over CDP against the dev app, two real Max accounts)
- Two Claude accounts + Codex render with quota;
Defaultpill sits on the system default for both providers - "Use for new agents" moves the pill, persists to host.db, and survives switching back (both directions)
- Agent launched after switching runs with
CLAUDE_CONFIG_DIR='<profile>'visible in the pty and boots on that profile - Brand-new terminal after switching:
echo $CLAUDE_CONFIG_DIRshows the profile andclaude auth statusreports the selected account (the preset-strip launch path that bypasses the host agent launcher) - Add-account dialog detects a completed sign-in via the logins poll and offers "Use for new agents"
- Switch sign-in on a profile card shows the dir-scoped login command; on the system-default card, the bare command
- Remove: confirm dialog → card disappears → directory deleted on disk; system-default cards have no Remove
- Hook merge lands in the profile's
settings.json(all 8 events) on selection - Duplicate-account edge: two profiles holding the same email stay distinguishable (source label always shown)
Not exercised live: completing a Switch sign-in on the system default (would rotate my real default login mid-session); its detection is the same poll loop verified in add mode with a different comparator.
Testing
bun run typecheck(host-service, agent-setup, desktop)- biome on all touched dirs
bun testhost-service: agents launch-env suite (5 new tests incl. precedence, mutation-tested to fail on regression) + profile-seed suite (4 tests)
Design Decisions
- Env injection over rewriting
~/.claude+ keychain on switch: rewriting the shared stores means owning refresh-token races (they're single-use), live-session gating, and rollback. Injecting the profile dir per launch keeps the provider CLI the sole owner of every credential, scopes the switch to new sessions by construction, and fits an app whose agents it launches itself. - Guided command instead of automated OAuth for add/re-sign: the CLI's login flow writes the right stores itself (including the config-dir-scoped keychain item); automating it would mean capturing credentials in transit.
Known Limitations
- A shell rc file that exports its own
CLAUDE_CONFIG_DIR/CODEX_HOMEoverrides the injected PTY env for manually typed CLIs (agent launches are unaffected — the command-line overlay wins). - The default pointer follows the profile dir, not the account inside it: re-signing a profile into a different account silently changes what new agents use. Deliberate (a profile is a slot), but worth knowing.
- A signed-out Codex home is undetectable (its
auth.jsonis gone), so unlike Claude profiles it cannot be surfaced for re-sign-in or removal. - Claude re-sign detection compares the state-file email, so re-signing the same email into the same slot isn't detected (nothing changed to act on).
usage.history(token spend) is not yet attributed per account.
Follow-ups
- Account picker at agent-start time with headroom inline (choose the account with quota left at the moment it matters)
- Per-account attribution in usage history
Summary by CodeRabbit
-
New Features
- Added account management for Claude Code and Codex usage cards.
- Users can add accounts, switch sign-in, set defaults, and remove secondary accounts.
- Account cards now show provider, status, and default indicators with management menus.
- Defaults apply automatically to future terminals and agents.
- Added provider-specific grouping, empty states, command copying, refresh handling, and notifications.
-
Bug Fixes
- Improved alternate account setup, onboarding, and profile preservation.
- Added clearer handling for signed-out accounts and safer account removal.