Uh oh!
There was an error while loading. Please reload this page.
feat(usage): Limits tab with provider quota windows and Codex banked resets - #9421
feat(usage): Limits tab with provider quota windows and Codex banked resets#9421StiensWout wants to merge 18 commits into
Conversation
…x banked resets Users had no way to see how much of their Codex or Claude Code subscription quota was left, or when it resets. Both providers already emitted a rate-limits runtime event, but its payload was untyped and the server dropped it. Adapters now normalise those payloads into typed limit windows. Codex is also read on demand through a short-lived app-server, and Claude Code through the claude.ai usage endpoint with the CLI's stored sign-in, so the numbers show without an open thread. A small in-memory service keeps the latest snapshot per provider instance and streams it to clients. The Usage page gains a Limits tab with one section per provider: a bar per window in use, a marker for even pacing, a pace icon, countdowns, and Codex banked resets with a confirmed redeem action. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This PR introduces a cross-cutting Limits product feature with new provider account integrations, OAuth credential access, live RPC state, and an irreversible Codex reset-credit redemption action. Its authorization and account-affecting behavior require reviewer validation beyond an auto-approval assessment. You can add or adjust custom eligibility rules. Learn more. |
Time out Codex account requests and fall back to a fresh app-server when a stale session cannot answer, refresh before the first limits snapshot so an empty boot map never reads as nothing reported, prune limits for removed instances, accept scoped weekly Claude event types so turns merge onto the rows the on-demand read created, surface failed environment subscriptions, and share one ProviderMark between the usage page and the Limits tab. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Mirrors the web Limits tab: one block per provider with a bar per window in use, a marker at the elapsed share of the window, the pace against the clock, the reset countdown, and banked Codex resets. Redeeming stays web-only for now. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Live Codex sessions get an 8 second budget before the read falls through to a fresh app-server, which has its own 20 second budget and a stable error detail. Reset redemption is single-flight per instance. Slow reads no longer overwrite windows an event updated meanwhile, events cannot resurrect a removed instance, the service interface lives inline on its tag, and the web page only subscribes to limits while the Limits tab is mounted. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
The window stamp check and the state write were separate Ref operations with a yield between them, so two concurrent applies could interleave and a stale read could still overwrite a newer event. Stamps now live beside the limits in one Ref and the check and write are a single update. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…er's limits Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…newer plan and credits Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
…d limits The registry's continuation identity changes with the configured home, so the service stores it per instance and starts clean whenever it differs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
…ilures, instance-aware Claude credentials Reset redemption is serialised per instance and keeps one idempotency key until Codex reports an outcome, and it never falls through to a fresh app-server after a session failure, so a retry re-sends the same attempt rather than spending a second credit. Full account reads now delete windows the account no longer reports while sparse turn events keep merging. A failed on-demand read is recorded on the snapshot next to the last good numbers instead of vanishing into the log. The Claude credential reader honours the instance's CLAUDE_CONFIG_DIR and HOME like the CLI it mirrors. Tests cover each of these. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…bile One shared module defines elapsed share and pace for both clients, with its own tests. Both views name environments still reading or failed, show a read failure beside the last good numbers, and the mobile heading wraps instead of clipping. The web bar is keyboard focusable with an accessible summary, and mobile pull-to-refresh holds until limits are re-read. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3953dca. Configure here.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
… complete reads carry extra usage, web shows a loading state Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
#9507) Users on Codex or Claude Code subscriptions could not see how much quota was left or when it resets without leaving T3 Code. A user whose CLIs route through a CLIProxyAPI hub could not see it at all. Each driver now returns `usageLimits` on its own snapshot (Codex from `account/rateLimits/read`, Claude from the SDK's `get_usage`), adapters normalise turn-driven rate-limit events at the boundary, and a driver-blind ingestion layer folds them onto the owning instance. The Usage page gains a Limits tab (mobile a card) with a bar per window, elapsed marker, pace, and reset countdown. CLIProxyAPI hubs can be added as read-only usage-limit sources; their accounts show badged "via CLIProxyAPI" with emails blurred. Distilled from #1732 (server model, provider rows) and #9421 (Limits tab, window bars, pace maths). Closes#228. Co-authored-by: Aditya Mer <101453576+Aditya190803@users.noreply.github.com> Co-authored-by: Wout Stiens <71498452+StiensWout@users.noreply.github.com> Co-authored-by: Claude Code <noreply@anthropic.com>
juliusmarminge
commented
Sep 4, 2026
Superseded by #9507, which landed the usage Limits tab (distilled from this PR's Limits-tab placement, window bars, and pace maths). Closing as superseded — thank you @StiensWout. |
Codex grants a reset credit when it has rate-limited an account unfairly; redeeming one clears the current windows. The credit count and soonest expiry now ride on the provider's usageLimits, and a confirmed "Use a reset credit" action on the Limits tab redeems one. Redemption is an account-level operation, so it lives on ProviderInstance (beside refreshModels) rather than on the thread-routed adapter. The Codex driver opens a short-lived app-server through the opener the status and skills probes now share, sends account/rateLimitResetCredit/consume, and re-probes so the cleared windows show. It is single-flight per instance and keeps one idempotency key until Codex reports an outcome, so a retry after a timeout re-sends the same attempt. Design from #9421. Co-authored-by: Wout Stiens <71498452+StiensWout@users.noreply.github.com> Co-Authored-By: Claude Code <noreply@anthropic.com>
Follow-up to #9507, carrying over the reset-credit redemption from #9421. Codex grants a reset credit when it has rate-limited an account unfairly (`"Thanks for using Codex! You've been granted one free rate limit reset."`). Redeeming one clears the current 5h/weekly windows. The Limits tab now shows how many are banked and when the next expires, with a confirmed **Use a reset credit** action. ## How it works - `ServerProviderUsageLimits.resetCredits` carries the count and soonest expiry; the Codex probe reads it from the same `account/rateLimits/read` it already makes. - `ProviderInstance.consumeResetCredit` is a new optional hook — account-level, so it sits beside `refreshModels` rather than on the thread-routed adapter. The Codex driver implements it over a short-lived app-server (via `withCodexAppServerClient`, factored out of the status and skills probes which duplicated the setup), then re-probes. - Single-flight per instance with one idempotency key kept until Codex reports an outcome, so a retry after a timeout does not open a second attempt. - New `provider.consumeResetCredit` RPC under the operate scope; the outcome (`reset` / `nothingToReset` / `noCredit` / `alreadyRedeemed`) is shown inline. Only Codex reports credits today. A provider without the hook gets a clear "does not bank reset credits" error; one without credits shows nothing. ## Screenshots The local Codex row with one banked credit (the same account via the CLIProxyAPI hub above it shows no credit, as expected — the hub does not relay them):  Close-up of the row:  Clicking it opens the confirmation; nothing is sent until **Use credit**:  ## Verification - Mapper tests for the credit summary; provider, contract, and Usage page suites pass; typecheck clean. - Verified against a real Codex Pro account holding one credit: summary and expiry render, the confirm dialog opens. **Not redeemed** — that would spend the credit. Written by Claude Fable 5 via Claude Code; design and single-flight approach from @StiensWout's #9421. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Redemption spends real account credits over a new RPC; correctness depends on per-account locking and idempotency, though disabled instances and non-Codex providers are rejected explicitly. > > **Overview** > Adds **end-to-end redemption of banked Codex rate-limit reset credits** from the Limits UI on web and mobile, backed by a new operate-scoped `provider.consumeResetCredit` RPC. > > **Contracts and server:** `ServerProviderUsageLimits` can include `resetCredits` (count + next expiry). Codex probes attach that from `account/rateLimits/read`. Optional `ProviderInstance.consumeResetCredit` is implemented for Codex via a scoped app-server call to `account/rateLimitResetCredit/consume`, then a limits refresh. `CodexResetCreditCoordinator` serializes redemptions per Codex account directory, reuses one idempotency key until Codex returns an outcome, and times out hung requests. `withCodexAppServerClient` is extracted so status, skills, and redemption share the same short-lived app-server setup. > > **Clients:** Limits rows show banked credits and a confirmed **Use a reset credit** action that calls `serverEnvironment.consumeResetCredit` and surfaces outcomes (`reset`, `nothingToReset`, etc.) or errors. > > **Web usage sources (same PR):** Adding/removing CLIProxyAPI hubs and the add dialog target a **selected connected environment** (with picker when several are connected), gated by operate access—not only the primary environment. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 98f32e6. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Wout Stiens <71498452+StiensWout@users.noreply.github.com> Co-authored-by: Claude Code <noreply@anthropic.com>
…resets Squash of upstream pingdotgg#9421 (StiensWout, head 3e02d2e).

Users on Codex or Claude Code subscriptions had no way to see how much of their quota was left or when it resets without leaving T3 Code. Both providers already emit a rate-limits event during turns, but its payload was untyped and the server dropped it on the floor.
This adds a Limits tab to the Usage page, next to Cost and Tokens. Each connected environment reports the account limits its providers know about, and the page shows one section per provider: a bar per window in use, filled by the share of quota spent, with a marker at how far into the window you are. Because the bar is the whole window, that marker is also where even spending would have put the fill, so a pace icon says whether you are ahead of, on, or under pace. Hovering a bar gives the exact figures and the reset time. Codex accounts with banked reset credits show the count with a confirmed Use a reset action.
How it works
UsageLimitsUpdate. Codex mapsaccount/rateLimits/updated, Claude Code mapsrate_limit_event, and both keep window ids stable so turn-driven updates merge onto the same rows.codex app-serverprocess, so limits never need an open thread. Reads may retry on a fresh process after a session failure; a redemption never does. Redemption is single-flight per instance and keeps one idempotency key until Codex reports an outcome./usagedialog uses, with the OAuth token Claude Code stored on disk. The token never leaves the server. It reads the endpoint's structuredlimitsarray, which is where model-scoped weekly buckets such as Fable carry their real names, and falls back to the legacy named keys. On macOS the credentials live in the Keychain and reading them from another process triggers a prompt on every refresh, so macOS relies on turn events until that becomes an explicit opt-in.UsageLimitsServicekeeps the latest snapshot per provider instance, folds in runtime events, refreshes on every subscribe and on every provider instance change, and streams changes over a newsubscribeUsageLimitsRPC. Full account reads replace the window set; sparse turn events merge by id. A failed read is recorded on the snapshot beside the last good numbers. Limits are account state rather than thread history, so nothing is persisted or event-sourced.Verification
Not in this PR
After
Light:
Dark:
Built with Claude Fable 5.1 in T3 Code.
Note
Medium Risk
Touches provider adapters, OAuth token reads for Claude limits, and Codex reset consumption with idempotency; incorrect merge on complete reads could briefly drop windows, though stamps protect newer turn events.
Overview
Adds subscription quota visibility on Usage via a new Limits metric alongside Cost and Tokens (web tab + mobile card). Clients subscribe per environment only while Limits is open; pull-to-refresh also re-fetches limits.
Server: Introduces typed
usageLimitscontracts,UsageLimitsService(in-memory snapshots, merge by window id, refresh on subscribe/instance changes), and WebSocketsubscribeUsageLimitsplusserverConsumeUsageLimitReset. Codex and Claude adapters now emit normalisedUsageLimitsUpdatefrom turn events and optional on-demand reads (Codex via live or short-lived app-server; Claude via claude.ai usage API with stored OAuth, skipping macOS file creds to avoid Keychain prompts). Codex reset redemption is single-flight with stable idempotency keys.UI: Bars per active window with elapsed marker, pace vs. even spend, reset countdowns, and web-only confirmed Use a reset for banked Codex credits. Shared
@t3tools/shared/usageLimitskeeps pace math consistent across web and mobile.Reviewed by Cursor Bugbot for commit 3e02d2e. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add Limits tab with provider quota windows and Codex banked resets
UsageLimitsServicebackend in UsageLimitsService.ts. It reads account limits from Codex and Claude adapters, merges sparse runtime events, and serves snapshots over WebSocket.UsageLimitsUpdateschema with windows, percentages, reset timestamps, and plan labels.UsageLimitsService.makestores state in memory. Themake.applymerge operation removes stale windows during complete adapter reads unless a newer runtime event touched them.Macroscope summarized 3e02d2e.