Skip to content

Multi-account attribution: tag usage with the account each Claude config root belongs to #201

Description

@shawnla90

Problem

Two Claude Code accounts on one Mac are common (personal Max plan + employer Team plan, switched via CLAUDE_CONFIG_DIR). Today this breaks in two independent, silent ways:

  1. Counting: only the default roots are scanned, so the second account's config dir (e.g. ~/.claude-tradeengage) is invisible — its tokens never reach the egg. Extend additional scan folders to every provider, not just Claude #177 / feat: add per-provider additional scan folders (#177) #187 / Add user-configurable additional scan folders with wildcard support #162 address finding the folders; this issue is about what happens after they're found.
  2. Attribution: even once a second root is scanned, everything merges into one undifferentiated total. The transcripts themselves carry no account/org field on any line, so a jsonl parser cannot attribute usage — the root is the only attribution boundary that exists on disk.

Real-world numbers from my machine: default root 1,334 session files / 701MB (personal Max 5x), second root invisible — including sessions from the same evening missing from todayTotalTokens.

Proposal

Layered on top of per-provider scan folders (#177/#187), not competing with it:

  1. Root → account mapping: each Claude config root contains .claude.json with an oauthAccount block (email, org name, org type). Read it once per root (cached by mtime) and tag the root with that identity.
  2. Entry tagging: add an optional accountKey (the root it came from, resolved to the account identity when known) to LocalUsageReader.Entry / the provider snapshot. Dedup stays global by entry ID.
  3. Display: default UI unchanged (one merged total — the companion aggregates everything, per the no-provider-branch rule). Add a per-account breakdown in the popover's Claude section when more than one account is present, mirroring how scopedLimitEntries extends the limits list.

This composes with #187's per-provider folders: those PRs contribute the roots; this contributes what the roots mean. It also complements #199 (account labeling on the official limits), which covers the OAuth side of the same two-account confusion.

Open questions

  • Is an account dimension on Entry acceptable, or would you rather keep Entry flat and aggregate per-root at the provider-snapshot level? (Snapshot-level is smaller; entry-level survives cache merging.)
  • .claude.json is large (can be several MB) — proposal reads only the oauthAccount object via JSONSerialization on a mtime-gated cache. Any concerns?

Happy to implement after alignment — flagging the design first since this touches Entry and the cache format.

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