[Bug]: Limits merges Claude instances with different logins into one row when they share a config directory#30602

opened7d agobyCceter843

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

packages/contracts or packages/shared

Steps to reproduce

  1. Sign in to Claude Code with account A as usual (claude auth login).
  2. Sign in account B into its own login folder. Claude Code's CLAUDE_SECURESTORAGE_CONFIG_DIR moves only the credentials file, and ~/.claude and ~/.claude.json stay shared:
    1$env:CLAUDE_SECURESTORAGE_CONFIG_DIR = "$HOME\.claude-b"
    2claude auth login
  3. In Settings → Providers, add a Claude instance named "Claude B". Leave its config directory empty, and add the environment variable CLAUDE_SECURESTORAGE_CONFIG_DIR set to the full path of that folder.
  4. Send a message on each instance so the two accounts are at different usage.
  5. Open Usage → Limits and click Refresh limits a few times.

I use this setup because T3 only lets a thread switch between Claude instances that use the same config directory (providers-claude.md). With it, a thread can move to another account, and CLAUDE.md, memory, and sessions stay shared.

Expected behavior

Two Claude rows, one per login, each with its own session and weekly numbers. The thread details card already shows the right numbers for a thread on each instance.

Actual behavior

There's one Claude row. It's labeled with the email stored in the shared ~/.claude.json, which belongs to whichever account signed in last. Its numbers come from whichever instance T3 checked most recently, so they switch between the two accounts. The provider cards also show the same email for every instance.

Each instance's numbers are correct. Its probe runs with its own login, and the thread details card (ThreadDetailsUsage, which looks up by instanceId) shows them right. The rows are merged because:

  • Claude Code reports account.email from oauthAccount.emailAddress in the shared ~/.claude.json, not from the login it's using, so every instance on the machine reports the same email.
  • The Claude driver reads workspaceId from oauthAccount.organizationUuid in the same file (readClaudeOrganizationId in ClaudeDriver.ts), so that matches too.
  • accountKey and collectLimitAccounts in packages/shared/src/usageLimits.ts key accounts by driver, email, and workspaceId, and keep the fresher reading.

Possible fix: also key a Claude instance by where its login is stored, for example by adding the instance's resolved CLAUDE_SECURESTORAGE_CONFIG_DIR to the key when it sets one. Instances that share one login, like presets, would still merge, and instances with separate logins would get their own rows.

Related: #28142 has the same symptom for hub accounts that really share an email. Its fix (#28290) only covers hub accounts.

Impact

Major degradation or frequent failure

Version or commit

0.1.6 (desktop). The same code is unchanged on main @ df2dfde.

Environment

Windows 10 22H2, T3 Code desktop 0.1.6, Claude Code 2.1.316

Logs or stack traces

shell
1

Screenshots, recordings, or supporting files

No response

Workaround

Deleting oauthAccount.emailAddress from ~/.claude.json makes Limits fall back to one row per instance. Claude Code writes the email back (daily profile refresh, token renewals, and sign-ins), so it has to be removed again each time.