feat(usage): add subscription limit reporting for Claude, Codex, Grok, and OpenCode - #8515
feat(usage): add subscription limit reporting for Claude, Codex, Grok, and OpenCode#8515AhmedShareef wants to merge 10 commits into
Conversation
- Expose usage-limits RPC with defensive Claude OAuth parsing - Add Usage/Limits dashboard with refresh and reset countdowns - Document subscription limit behavior
- Read Codex rate limits through its app server - Add auth parsing, plan labels, window mapping, and tests
- Read account authentication state alongside usage windows - Parse raw rate-limit responses and prioritize account-wide buckets
- Fetch and expose Claude and Codex account emails - Group and label usage cards by account identity - Extend usage contracts and parser tests
- Read Grok OIDC billing windows and display them in Limits - Add defensive parsers, tests, contracts, and user documentation
- Treat missing proto3 usage percentages as zero for valid credits documents - Add regression coverage for zero-usage billing windows
- Parse OpenCode credentials and Zen rate windows - Show OpenCode limits across contracts, UI, and docs - Add defensive parser tests
- Replace the usage breadcrumb with an accessible heading and inline date range
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
There was a problem hiding this comment.
One convention issue found: the new UsageLimitsService reads process.env directly instead of acquiring the HostProcessEnvironment reference from the Effect environment, hiding an environment dependency in a module global. Everything else (module order, inline Context.Service interface, make/layer/layerTest exports, dependency acquisition via yield*, namespace imports, in-band failure modelling) matches the repository's Effect service conventions.
Posted via Macroscope — Effect Service Conventions
There was a problem hiding this comment.
Two consistency findings in the new Limits view. Both are small, local fixes.
Posted via Macroscope — UI Consistency
| } | ||
| } | ||
|
|
||
| return GROK_DEFAULT_PROXY_BASE_URL; |
There was a problem hiding this comment.
🟠 High usage/usageLimitsGrok.ts:107
When a user configures a team proxy only through [endpoints].cli_chat_proxy_base_url and models_cache.json is absent or stale, resolveGrokProxyBaseUrl returns GROK_DEFAULT_PROXY_BASE_URL, so the caller sends the team-scoped bearer to the public endpoint. The resolver never reads or receives the CLI config value; include that endpoint in resolution and return null when it cannot be parsed instead of falling back to the default.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/usage/usageLimitsGrok.ts around line 107:
When a user configures a team proxy only through `[endpoints].cli_chat_proxy_base_url` and `models_cache.json` is absent or stale, `resolveGrokProxyBaseUrl` returns `GROK_DEFAULT_PROXY_BASE_URL`, so the caller sends the team-scoped bearer to the public endpoint. The resolver never reads or receives the CLI config value; include that endpoint in resolution and return `null` when it cannot be parsed instead of falling back to the default.
There was a problem hiding this comment.
Partially addressed in 876c8e2: a cached origin that is present but unparseable now fails closed instead of falling back to the public default. The config-file-only case (proxy set via [endpoints] cli_chat_proxy_base_url with no models cache yet) is deliberately left on the default: resolving it would mean re-parsing the CLI's TOML config (new dependency, duplicated CLI internals) to cover a transient state that ends the moment the CLI writes its models cache — and the bearer is an xAI credential reaching xAI's own default endpoint, not a third party. The resolver's doc comment now states this limitation explicitly.
There was a problem hiding this comment.
Sorry, I'm unable to act on this request because you do not have permissions within this repository.
…ides - Read env through HostProcessEnvironment like the sibling UsageService - Expand and resolve GROK_HOME/GROK_AUTH_PATH overrides before use - Honor ambient CODEX_HOME in the auth pre-check to match the app server - Report a settings-read failure as unavailable instead of unsupported - Fail closed on a malformed cached Grok proxy origin - Survive overflowing Codex reset instants, invalid Claude currency codes, array-shaped OpenCode usage, and empty Grok period objects
- Use the Button primitive for the refresh action like the usage header - Track the runtime contrast adjustment for the OpenCode series color
| const state = parseOpenCodeAuthState(injected); | ||
| if (state !== null) return state; |
There was a problem hiding this comment.
🟡 Medium usage/UsageLimitsService.ts:574
When OPENCODE_AUTH_CONTENT is a valid document with no recognized credential, readOpenCodeAuthState falls through to the on-disk auth.json and may report/use a stale Zen key that OpenCode is not using. Return the parsed injected state directly, including null, so a successfully parsed injected document suppresses disk auth.
- if (state !== null) return state;
+ return state;🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/usage/UsageLimitsService.ts around lines 574-575:
When `OPENCODE_AUTH_CONTENT` is a valid document with no recognized credential, `readOpenCodeAuthState` falls through to the on-disk `auth.json` and may report/use a stale Zen key that OpenCode is not using. Return the parsed injected state directly, including `null`, so a successfully parsed injected document suppresses disk auth.
|
Note 🤖 GPT-5.6 Sol responding on behalf of Theo We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together. We are keeping #1732 as the provider-limit source, #8445 as its separate composer follow-up, and #8456 for OpenCode reporting. This branch is an alternate 22-file service, and keeping it would split parser, cache, and contract ownership. If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed. |
The usage page showed transcript-based activity but nothing about how much of a subscription's rate limits were left, so users driving agents all day had no way to see a window running hot before hitting it.
This adds a Limits view to the usage page, backed by a new
UsageLimitsServiceon the server that reads each provider's local credentials/telemetry and reports subscription rate-limit windows over a newusageLimitscontract:Each provider is a separate commit and reviewable on its own. Parsers are defensive and covered by focused tests (215 passing across
apps/server/src/usage/). Providers without support render as placeholders, so the view degrades cleanly.Note
Draft: before/after screenshots and a short recording of the Limits view are pending; will attach before marking ready.
Built by Claude (Fable 5) via Claude Code.
Note
Add subscription limit reporting for Claude, Codex, Grok, and OpenCode
UsageLimitsServiceand dedicated parser modules to read auth state and rate-limit windows from Claude, Codex, Grok, and OpenCode CLI tools.server.getUsageLimitsWebSocket RPC and auseUsageLimitsReact hook to fetch and aggregate provider limits across environments.UsageLimitsServicespawns external processes (securitykeychain tool on macOS,codex app-server) with bounded scopes and timeouts; ensure process cleanup handles edge cases without leaking.📊 Macroscope summarized c92b495. 17 files reviewed, 9 issues evaluated, 0 issues filtered, 9 comments posted
🗂️ Filtered Issues