Skip to content

Feature request: distinguish accounts that share the same email (personal vs team/org) #504

Open

Description

@sanjeevpenupala

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:

  1. New widget(s): e.g. Claude Account Plan (renders the mapped organizationType, Max/Pro/Enterprise/Team) and/or Claude Account Organization (renders organizationName). Both sit alongside the existing email widget.
  2. Option on the existing widget: a toggle to append the plan or org, e.g. Account: you@example.com (Team) or Account: 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)

Happy to open a PR if that's useful.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions