Skip to content

fix(server): usage counts every configured provider instance - #8470

Open
DonovanMontoya wants to merge 9 commits into
pingdotgg:mainfrom
DonovanMontoya:fix/usage-provider-instance-homes
Open

fix(server): usage counts every configured provider instance#8470
DonovanMontoya wants to merge 9 commits into
pingdotgg:mainfrom
DonovanMontoya:fix/usage-provider-instance-homes

Conversation

@DonovanMontoya

@DonovanMontoya DonovanMontoya commented Aug 28, 2026

Copy link
Copy Markdown

Problem

The Usage page resolves one transcript directory per provider from the legacy single-instance settings (settings.providers.claudeAgent / settings.providers.codex). Anyone running multiple instances of a provider through providerInstances — e.g. separate Claude accounts isolated in their own config directories — silently gets zero usage from every instance except the default one.

Fixes #5805.

Fix

A new usageProviderHomes module enumerates transcript homes from the same settings merge the runtime registry uses (deriveProviderInstanceConfigMap), so the scan sees exactly the set of instances that can run agents:

  • Every Claude instance contributes its home: an explicit homePath wins; otherwise a CLAUDE_CONFIG_DIR configured on the instance's environment; otherwise the default home. The server's own ambient environment is deliberately not consulted, so what usage scans is determined by settings alone.
  • Every Codex instance contributes its sessions directory via the existing resolveCodexHomeLayout.
  • Instances that resolve to the same directory collapse to one scan entry, so nothing double counts.
  • Instances whose config fails to decode are skipped (the registry already surfaces those as unavailable).

Each directory reports as its own fingerprinted entry in sources, which the existing cross-environment merge in usageMerge already dedupes per directory — no contract or client changes needed. Grok's GROK_HOME resolution moved into the new module unchanged.

Covered by focused tests (multiple instances via homePath and via instance env var, same-home collapsing, bad-config skipping, ambient-env isolation, legacy settings), plus the existing usage suite. docs/user/usage.md now mentions multi-instance coverage.

Before / after

Same machine, two configured Claude instances (~/.claude + a second account in ~/.claude-max), 30-day window.

Before — only the default ~/.claude is scanned (74 sessions, $485.18):

before

After — both instance homes are scanned (88 sessions, $722.05):

after

Relation to existing PRs

#5806, #6312, #6596, #6603, and #7419 target the same bug. This version differs by deriving the instance set from deriveProviderInstanceConfigMap rather than re-implementing instance enumeration, so usage can never disagree with the registry about which instances exist; it also handles env-var-isolated instances and same-home dedupe while keeping the diff to the usage module plus docs (no contract, wire, or client changes). Happy to close this one if the maintainers prefer any of the earlier takes.

Authored with Claude (Fable 5) running in Claude Code.


Note

Medium Risk
Raises usage contract merge floor to v6 (older servers show partial coverage) and changes multi-environment dedupe semantics; incorrect home resolution could still miss or double-count transcripts.

Overview
Usage scanning now walks every Claude and Codex home from providerInstances (via new resolveUsageProviderHomes), not only legacy settings.providers. Instance homePath, absolute CLAUDE_CONFIG_DIR / CODEX_HOME, Codex shadow layouts, and same-home collapsing match runtime behavior; transcript dirs are canonicalized with realPath so symlinked aliases scan once while missing paths still show as separate missing sources.

Aggregation and merge tie each bucket to a sourceIndex into the summary’s sources array. Cross-environment mergeUsage drops duplicate transcript directories per source, not per provider, so overlapping environments keep unique homes instead of losing an entire provider’s totals.

Contract v6 adds sourceIndex on UsageBucket (decode default 0); USAGE_MERGE_COMPATIBLE_SINCE is 6, so v5 summaries are treated as stale during merge. User docs note multi-instance Claude/Codex coverage.

Reviewed by Cursor Bugbot for commit cc8777d. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Count usage from every configured provider instance in UsageService

  • Adds resolveUsageProviderHomes to enumerate all configured Claude and Codex instance homes, applying the same home and environment precedence rules as provider execution, skipping invalid instances, and de-duplicating paths
  • Adds a required source-index argument to UsageAggregator.add so records from different transcript directories stay in separate buckets even when day, hour, provider, and model match
  • Replaces provider-level ownership tracking in ownedContribution with source-index ownership so merging drops only duplicate directories while preserving unique directories of the same provider
  • Bumps USAGE_CONTRACT_VERSION from 5 to 6 and raises USAGE_MERGE_COMPATIBLE_SINCE from 4 to 6; older bucket data decodes with a default source index of zero
  • Risk: summaries produced with contract version 5 are excluded from merging with version 6; any out-of-tree readers expecting the old UsageBucket shape or merge-compatible range will need updating

Macroscope summarized 3c8d99d.

Summary by CodeRabbit

  • New Features

    • Usage tracking now includes token history and model breakdowns from multiple configured Claude and Codex instances.
    • Provider transcript locations are resolved across instance-specific settings and environments, with duplicate paths removed.
    • Usage results now prevent overlapping provider sources from being counted more than once.
  • Bug Fixes

    • Improved handling of duplicate and overlapping usage sources to avoid inflated totals.
  • Documentation

    • Updated usage documentation to explain multi-instance provider history coverage.

@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 02d0b9ae-430f-4ebe-bc0b-43690af4e2c8

📥 Commits

Reviewing files that changed from the base of the PR and between 31c1c59 and e1cae5e.

📒 Files selected for processing (6)
  • apps/server/src/usage/UsageService.ts
  • apps/server/src/usage/usageProviderHomes.test.ts
  • apps/server/src/usage/usageProviderHomes.ts
  • docs/user/usage.md
  • packages/shared/src/usageMerge.test.ts
  • packages/shared/src/usageMerge.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

The usage scan now resolves transcript homes from all configured provider instances. It supports custom Claude and Codex homes, preserves Grok resolution, deduplicates paths, and changes usage merging to claim overlapping provider sources by environment.

Changes

Usage discovery and merge

Layer / File(s) Summary
Provider home resolution
apps/server/src/usage/usageProviderHomes.ts, apps/server/src/usage/usageProviderHomes.test.ts
Resolves Claude, Codex, and Grok transcript locations from provider instances, effective environments, explicit paths, and legacy settings. Tests cover overrides, suppression, invalid configurations, deduplication, and disabled instances.
Transcript scan integration
apps/server/src/usage/UsageService.ts, docs/user/usage.md
Scans all resolved Claude and Codex directories, deduplicates probed Claude paths, and documents multi-instance usage aggregation.
Usage source ownership
packages/shared/src/usageMerge.ts, packages/shared/src/usageMerge.test.ts
Claims overlapping environment/provider groups by directory count and environment ID. Dropped paths are reported in duplicateSources, with tests for subset and tie cases.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: ⚪ Minimal · up to e1cae

The PR expands usage totals to include configured provider instances and deduplicates shared homes; no actionable merge-blocking risk remains beyond normal checks and review.

Suggested reviewers: t3dotgg, juliusmarminge

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the primary change: usage now counts every configured provider instance.
Description check ✅ Passed The description explains the problem, implementation, scope, tests, screenshots, and issue reference. It does not use the template headings or include the checklist, but it provides the required infor…
Linked Issues check ✅ Passed The changes satisfy issue #5805 by discovering Codex homes from provider instances, including custom CODEX_HOME and shadow homes, scanning their sessions directories, and preventing duplicate counting…
Out of Scope Changes check ✅ Passed The Claude support, shared home resolver, Grok refactor, merge changes, tests, and documentation directly support the broader provider-instance usage-scanning objective. No unrelated product-area chan…
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 5 files. (1 skipped: 1 …
Full details: Description check

Explanation

The description explains the problem, implementation, scope, tests, screenshots, and issue reference. It does not use the template headings or include the checklist, but it provides the required information in equivalent sections.

Full details: Linked Issues check

Explanation

The changes satisfy issue #5805 by discovering Codex homes from provider instances, including custom CODEX_HOME and shadow homes, scanning their sessions directories, and preventing duplicate counting. Tests cover the relevant cases.

Full details: Out of Scope Changes check

Explanation

The Claude support, shared home resolver, Grok refactor, merge changes, tests, and documentation directly support the broader provider-instance usage-scanning objective. No unrelated product-area changes are evident.

Full details: Docstring Coverage

Explanation

Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 5 files. (1 skipped: 1 unsupported.)

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Your free Security trial is over. An organization admin can activate Security or dismiss this notice.


Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 28, 2026
Comment thread apps/server/src/usage/usageProviderHomes.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0f40cc244f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/server/src/usage/usageProviderHomes.ts Outdated
Comment thread apps/server/src/usage/usageProviderHomes.ts Outdated
Comment thread apps/server/src/usage/usageProviderHomes.ts Outdated
@macroscopeapp

macroscopeapp Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This change materially alters production usage and estimated-cost accounting across provider instances and environments, including source ownership and compatibility handling for older summaries. Its cross-cutting runtime and contract effects warrant human review.

You can add or adjust custom eligibility rules. Learn more.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2e02d6c. Configure here.

Comment thread apps/server/src/usage/UsageService.ts
@Jardo-51

Copy link
Copy Markdown
Contributor

Thanks for picking this up — this is the most complete take on the scanning half that I've seen.

Would you consider also attributing each bucket to the home it came from, so the Usage page renders one series per instance rather than pooling everything into a single "Claude" line? That's what #6920 is asking for: with several accounts configured (work vs. personal), a single combined total doesn't answer the question people actually have, which is what each account is spending against its own limit.

#5738 is a worked example of that half — UsageBucket gains homePath + homeLabel, UsageSource gains label, and each series is named after the configured instance (Codex · Personal). It was stacked on #5806 and never landed, so the approach is available to borrow.

Understood if you'd rather keep this PR to the scan fix and leave the split for a follow-up — in that case it would help a lot if resolveUsageProviderHomes kept the instance id/display name on each resolved home, so the follow-up doesn't have to re-derive the mapping.

@DonovanMontoya

Copy link
Copy Markdown
Author

Hi @Jardo-51

Thanks for laying this out and for pointing to the existing #5806#5738 split. I agree that separate, labelled usage per instance is the more useful end state for people with work and personal accounts, but I think I like keeping #8470 focused on the scanning/correctness half so it can land without expanding into contract and client changes. I considered retaining an instance ID/display name on each resolved home now, but multiple instances and Codex shadow overlays can resolve to the same transcript directory. So I think keeping individual attribution as a follow-up gives this fix a better chance of merging.

I did adopt the effective-environment behavior documented in #5806: Usage now inherits server-level CODEX_HOME and CLAUDE_CONFIG_DIR, with per-instance environment variables overriding them and configured/shadow homes retaining precedence. As that made a lot of sense.

That leaves #6920 as a clean follow-up based on the attribution work in #5738, rather than partially introducing those semantics here.

@FredericDierenBescherming

Copy link
Copy Markdown

Cant wait for this to be merged. Thank you for your effort!

Comment thread packages/shared/src/usageMerge.ts Outdated
@t3dotgg

t3dotgg commented Sep 4, 2026

Copy link
Copy Markdown
Member

Note

🤖 GPT-6 Astra (preview) responding on behalf of Theo

This note is part of an automated cleanup pass.

Carryover from #5806 at 0ed33dde6e: canonicalize transcript directories with FileSystem.realPath before deduplicating by provider and physical directory. Two configured homes or shadow overlays can name the same directory through symlinks. A missing home must remain visible as a missing source rather than disappearing during resolution. Keep this with the already adopted server/instance environment precedence, and check that partially overlapping environments retain their unique-home usage instead of dropping a whole provider aggregate.

@DonovanMontoya

Copy link
Copy Markdown
Author

Addressed the carryover in 62ef044:

  • Canonicalizes each final transcript directory with FileSystem.realPath before provider/path deduplication.
  • Falls back to the configured path when canonicalization fails, so missing homes still appear as missing sources.
  • Leaves the adopted server/instance environment precedence unchanged.
  • Associates every bucket with its source and claims duplicates per physical-directory fingerprint, so partially overlapping environments keep all unique-home usage instead of dropping a provider aggregate.
  • Bumps the usage contract because older pooled buckets cannot safely participate in source-level deduplication.

Added coverage for symlink aliases plus a missing home, source-indexed aggregation, the two-environment subset case, and the three-environment intersecting case from the review. Focused tests pass (43), affected server/contracts/shared/web/mobile typechecks pass, and focused lint passes.

@github-actions github-actions Bot added size:XXL 1,000+ changed lines (additions + deletions). size:L 100-499 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). size:XXL 1,000+ changed lines (additions + deletions). labels Sep 4, 2026
Comment thread docs/user/usage.md Outdated
DonovanMontoya and others added 8 commits September 5, 2026 15:10
The usage scan resolved one transcript directory per provider from the
legacy single-instance settings, so Claude and Codex instances configured
through providerInstances (separate accounts with their own config
directories) reported zero usage. Enumerate instance homes with the same
settings merge the runtime registry uses, honor CLAUDE_CONFIG_DIR for
homeless instances, and dedupe instances that share a directory.
Environment-provided homes (CLAUDE_CONFIG_DIR, CODEX_HOME) reach the
spawned CLI verbatim, so usage no longer tilde-expands them and only
honors absolute values; relative ones depend on each workspace's cwd and
have no single scan directory. Codex instances isolated purely through
an instance-level CODEX_HOME are now scanned too, matching the runtime's
config-over-environment precedence.
With a shadow overlay the runtime overrides CODEX_HOME and the shadow's
sessions symlink back to the shared home, so an instance-level CODEX_HOME
must only decide the scan directory when the layout yields no effective
home.
…ment

With multiple homes per provider, an environment's buckets aggregate every
home it scans, but the cross-environment merge claimed ownership per
directory. An environment owning only part of another's home set still
contributed its full per-provider aggregate, double counting the shared
directories. Claims are now the environment's whole fingerprint set for a
provider, with larger sets winning so a superset environment keeps its
unique homes.
Usage scans ignored server-level CODEX_HOME and CLAUDE_CONFIG_DIR even though provider processes inherit them. Resolve usage homes from the same effective environment while preserving configured-path precedence.\n\nEnvironment precedence informed by pingdotgg#5806.
Canonicalize resolved transcript directories before local deduplication while retaining unresolved paths as missing sources. Associate each usage bucket with its source so cross-environment merging drops only duplicate directories and keeps every unique home's usage.
Limit the multi-instance history claim to Claude Code and Codex, and document that Grok Build reads the server's single Grok home.
@DonovanMontoya
DonovanMontoya force-pushed the fix/usage-provider-instance-homes branch from cc8777d to 8ec5450 Compare September 5, 2026 19:10
@cursor

cursor Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

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

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Usage page misses Codex usage from provider instances with a custom CODEX_HOME

4 participants