Repository navigation
Description
Summary
The Claude Account Email widget shows only the account email. When one email address maps to more than one account, for example a personal Max plan and a seat on a team/organization, both selectable from the same /login picker, the widget renders identically for every one of them. After switching accounts with /login, there's no way to tell from the status line which account is actually active.
Why the email alone isn't enough
A single email can own or belong to multiple accounts:
- Personal: Max plan
- Team: a seat under an organization
Both show the same email in the /login picker, and the status line prints the same Account: you@example.com for either one. I verified the email is byte-for-byte identical across both accounts, so it can't be the thing that distinguishes them.
Current behavior (source)
src/widgets/ClaudeAccountEmail.ts reads only the email field:
interface ClaudeJson { oauthAccount?: { emailAddress?: string } }
// ...
const email = data.oauthAccount?.emailAddress;The type declares only emailAddress, so the other fields sitting beside it in the same object are dropped at parse time.
The disambiguating data already exists, and I verified it updates on switch
The same oauthAccount object in ~/.claude.json that the widget already reads for emailAddress also carries fields that differ between accounts. I tested this by doing a real /login switch and diffing the file before and after. The file is rewritten immediately on switch (both profileFetchedAt and its mtime advance), so there's no staleness problem. A widget reading it gets the active account, not a cached one.
Fields that flipped between a team seat and a personal Max account (values genericized):
| field | Team account | Personal Max |
|---|---|---|
organizationType |
claude_team |
claude_max |
organizationName |
Acme Team |
<email>'s Organization (auto-generated) |
seatTier |
team_tier_1 |
null |
organizationUuid |
(uuid A) | (uuid B) |
So no new data source is needed. The widget already opens the right file and parses the right object.
Important caveat: the supported status line JSON carries no identity
The JSON Claude Code pipes to the status line command (StatusJSON in this repo) contains session, model, cwd, cost, context, effort, and rate limits, but no account, email, organization, or plan field. So any account-identity widget has to read ~/.claude.json directly, which is undocumented internal state. It works today and updates correctly, but Anthropic could restructure it without notice. The durable fix would be Anthropic putting account/org into the status line payload, which is a separate upstream ask this repo can't solve on its own.
Proposed solution
Key off organizationType as the primary discriminator. It's a stable enum, and I checked the full set of values and their labels against Claude Code's own bundle, which maps organization_type to a subscription label with this switch:
switch (organization_type) {
case "claude_max": z = "max"; break;
case "claude_pro": z = "pro"; break;
case "claude_enterprise": z = "enterprise"; break;
case "claude_team": z = "team"; break;
default: z = null; break;
}So the recognized values and labels are:
organizationType |
label |
|---|---|
claude_max |
Max |
claude_pro |
Pro |
claude_enterprise |
Enterprise |
claude_team |
Team |
Reusing these exact labels keeps the widget in step with the product.
One thing worth copying from that switch is the default: null branch. Claude Code itself doesn't treat this enum as exhaustive, and values have been added over time. A widget should do the same: map the four known values to labels, and for anything unrecognized, fall back to the raw organizationType string (or organizationName) instead of a blank or a wrong hard-coded label. Then you don't need certainty that the list is complete. Known values get a friendly label, unknown ones still show something accurate.
Two shapes that would work:
- New widget(s): e.g.
Claude Account Plan(renders the mappedorganizationType,Max/Pro/Enterprise/Team) and/orClaude Account Organization(rendersorganizationName). Both sit alongside the existing email widget. - Option on the existing widget: a toggle to append the plan or org, e.g.
Account: you@example.com (Team)orAccount: you@example.com · Max.
I'd lean toward option 1 sourced from organizationType. It keeps each widget single-purpose and gives a readable label without exposing the auto-generated "<email>'s Organization" string that personal accounts get.
Related (not duplicates)
- Add indicator of account in use #47: original "account indicator" request (API vs Pro/Max). Different axis: this is same email, multiple subscription accounts.
- claude-account-email widget ignores CLAUDE_CONFIG_DIR when multiple profiles are active #317:
claude-account-emailignoringCLAUDE_CONFIG_DIRfor multiple profiles (different emails, wrong file read). This is a single profile where one email maps to multiple accounts.
Happy to open a PR if that's useful.
Activity