feat: meter a second Claude or Codex account - #39
Merged
Merged
Conversation
People who hold two accounts with the same tool got one meter row that showed the first account's budget and silently mixed both accounts' tokens. A second account is now its own provider slot (.codexAlt / .claudeAlt) with its own quota windows, plan badge, session history, heatmap, alerts, and (for Codex) reset credits — never merged, because two accounts' windows are two different budgets. A slot exists when its alternate config directory exists on the Mac: METERUSAGE_CODEX_ALT_HOME (CODEX_HOME-equivalent) or METERUSAGE_CLAUDE_ALT_CONFIG (CLAUDE_CONFIG_DIR-equivalent), with stored defaults keys as fallback. The Codex slot spawns its own CLI subprocess with that home; meterusage still never touches any auth file. Slots are named by position only; no account identifier is ever read or displayed. Verified with swift build and swift test on macOS (362 tests) plus a demo-mode meterusage json run listing both accounts per tool.
The second-account rows only appeared once the alternate config directory already existed, so a fresh install showed nothing under Settings and the feature was undiscoverable. The rows now always show with an editable directory field (the same keys the environment overrides), and the Accounts caption explains the setup flow.
The two fixed second-account slots capped at one extra account per tool. Accounts are now a managed list: Settings gains a Second accounts card with add and remove per row, a name, and the config directory — a user with three Codex logins adds three rows and the app meters each. Every surface keys readings by the slot's identity (provider + generated id), so labels can change without orphaning history, archive, or alert state; the JSON report carries the label in an additive account field. Readings appear after relaunch, when composition builds each account's sources.
The add buttons rendered the literal string 'Add (provider.disp…' — an over-escaped interpolation. One compact 'Add account' menu in the section header now names the tool per item (two side-by-side buttons truncated at card width), rows animate in at 150 ms ease-out, and the copy is tightened.
.fixedSize() let the header button overflow the popover edge; the label shortens to 'Add' and the menu items still name the tool.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
People who hold two accounts with the same CLI tool get one meter row per tool today: the row shows the first account's budget while the token totals silently mix both accounts' sessions. There is no way to see the second account's headroom, and no way to tell which account is about to get cut off.
What this does
A second account becomes its own provider slot (
codexAlt/claudeAlt) — a full meter row with its own quota windows, plan badge, session history, heatmap, alerts, and (for Codex) reset credits. Slots are never merged with the primary account, because two accounts' windows are two different budgets.Setup (documented in README and ADR 0005): a slot exists when its alternate config directory exists on the Mac.
Stored defaults keys (
meterusage.codexAltHome,meterusage.claudeAltConfig) work too; the environment wins. Config changes apply on relaunch.Design notes
codex app-serversubprocess withCODEX_HOMEset, so the CLI authenticates as the other account. meterusage still never reads any credential file; the Claude plan decode stays a narrow tier-only decode of the alternate directory's own.claude.json(no fallback to the primary account's file — a wrong-but-plausible tier is worse than none).~form.codexAlt/claudeAltentries (schema unchanged). Reset credits route to the slot whose loaded quota reported the credit id.Verification
swift buildandswift teston macOS: 362 tests, 0 failures.MultiAccountTestscover resolution precedence (env > defaults), tilde expansion, blank-key handling, presence gating (including a directory removed mid-session), per-slot polling, reset routing, archive/history key separation, and JSON report entries.METERUSAGE_DEMO=1 meterusage jsonlistsclaudeAltandcodexAltentries alongside the primary slots.supportsat 0.92+ confidence; the two below-threshold findings were confirmed by direct read of the view/model hunks.Docs
README (Second accounts section + provider matrix note),
docs/PRIVACY.md(new source-table rows + identity-boundary paragraph),docs/KB.md,CHANGELOG.md, and newdocs/adr/0005-multi-account-slots.md.Model(s): glm-5.3-flash
Harness: T3 Code (OpenCode)