feat(usage): show Codex and Claude subscription limits on a Limits tab - #9507
Conversation
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. Each driver decides for itself whether it has subscription usage and returns it on its own `ServerProvider` snapshot as `usageLimits`: Codex from `account/rateLimits/read` during the status probe, Claude from the SDK's `get_usage` control request on the capabilities query it already opens. Adapters normalise the turn-driven rate-limit events at the boundary into a typed update, and a small driver-blind ingestion layer folds them onto the owning instance through `applyUsageLimits`, so the bars move while a turn runs without a central service that switches on driver kind. The Usage page gains a Limits tab next to Cost and Tokens, and mobile a Limits card, both reading the provider snapshots clients already hold. Each window is a bar across its whole duration with a marker at the elapsed share, a pace icon, and a reset countdown anchored to render time. Distilled from #1732 (server model, provider rows) and #9421 (Limits tab, window bars, pace maths). 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>
…view A user whose CLIs route through a CLIProxyAPI hub sees no subscription windows locally: the Claude CLI treats the proxy token as an API key and the Codex login on the box may not be the one the hub uses. The hub already knows every pooled account's windows. Usage-limit sources are settings entries (`usageLimitSources`) polled on the provider health interval by a small `UsageLimitSources` service and published over the config stream, gated by a client capability flag like environment themes. This is deliberately not a provider: nothing here can run a turn, and one source reports many accounts. The management key goes to the secret store and settings keep a redaction marker. The Limits view groups each hub's accounts under its name, badges every row "via CLIProxyAPI" so a pooled account is not mistaken for the local login, blurs emails until clicked as provider settings do, and labels plans the way the matching provider would. A dialog on the view adds a hub; each hub has a remove control. Co-Authored-By: Claude Code <noreply@anthropic.com>
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
The form hand-rolled its padding, which also skipped the panel's scroll area, scroll fade, and the header-spacing rule keyed on data-slot="dialog-panel". Wrap it in DialogPanel like the other dialogs. Co-Authored-By: Claude Code <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 ON, but a cloud agent failed to start.
Reviewed by Cursor Bugbot for commit 0786184. Configure here.
- The Claude capabilities probe test's fake CLI only answered `initialize`, so the new `get_usage` request hung until the suite timed out; it now answers both and the test asserts the usage it returns. - `serverRefreshProviders` awaited the usage-source refresh instead of forking it into an RPC scope that closed before the hub answered. - A bad `usageLimitSources[].url` is reported on that source's row instead of failing the whole refresh batch; refreshes are serialised so a slow read cannot resurrect a source removed meanwhile. - The overage-included bucket name is taken from the first scoped entry that drew a row, so a null-utilization entry cannot open a stray row. - Hub auth-file emails keep hyphenated local parts. - The add-hub dialog keeps dots and dashes in the host when deriving the id, and Cancel clears the typed key. - Remove is offered only for the primary environment's own sources; a remote environment's row with the same id is read-only. Co-Authored-By: Claude Code <noreply@anthropic.com>
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This PR adds a new Limits capability, changes provider probing and live runtime updates, and introduces an authenticated CLIProxyAPI integration with persistent secret handling. The breadth of the runtime and security-sensitive changes warrants human review. You can add or adjust custom eligibility rules. Learn more. |
Codex and hub read failures were copied verbatim onto the snapshot, which put request URLs and response bodies on the wire and could produce an empty string the contract rejects. Both now narrow the typed failure to a short category (JSON-RPC code, HTTP status, timeout, bad URL, bad shape) and log the raw cause. The Effect `catch` also stops returning a global Error, which the repo's diagnostics flag. Add and remove read the current source map at click time so two edits before the first write echoes back cannot resurrect a removed hub. Co-Authored-By: Claude Code <noreply@anthropic.com>
Adding or removing a hub sent the whole map, so two edits before the first echoed back clobbered each other. The patch now names only the entries it changes, with `null` removing one, and the server merges it into its current map. `InvalidUrl` is a tagged error that keeps the URL and the underlying cause for the log. Co-Authored-By: Claude Code <noreply@anthropic.com>
… nothing Codex sends account/rateLimits/updated beside every token-usage tick, almost always with unchanged numbers. The merge now compares per window on the way through and hands back the published object itself when nothing moved, so the ingestion path drops the event by identity without allocating a snapshot or running a structural equality. Also records in resolveUsageLimitsAfterProbe why a successful probe replaces a runtime update that landed while it ran. 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>
…ity ACP, browser import, settings reorg, limits tab) Brings the fork up to upstream/main fee2e0f. Highlights: Google Antigravity via the official ACP agent (pingdotgg#9348) + model manifest refreshes, browser-cookie import (Chrome/Edge/Brave/Firefox, pingdotgg#7255/pingdotgg#7260/pingdotgg#7261), settings page reorg (pingdotgg#9354), Codex/Claude subscription Limits tab (pingdotgg#9507, pingdotgg#9534), context compaction command (pingdotgg#9293), async Codex questions (pingdotgg#9512), full-access OpenCode threads skip approvals (pingdotgg#9282), project icons default (pingdotgg#9457). Unification decisions (keep-both unless noted): - BrowserImport: upstream implementation wins (Linux libsecret, Windows DPAPI unwrap, writeCookies); fork's Safari engine ported in (jar definition, candidate path, profile listing, running check, count skip, import branch, FullDiskAccess wizard step + SafariCookies kept, domain widened only for dotted hosts). - Antigravity: upstream ACP provider/adapter/driver/textgen win; fork branding ported (providerDisabledMessage), AntigravitySettings unified (fork fields + upstream auth fields; enabled stays default-on). - contracts/model: Antigravity defaults follow upstream's manifest model. - ClaudeAdapter compact_boundary: fork's resolve helper kept, renamed to upstream's compactedUsage to match downstream. - Claude capabilities probe: fork's timeout races kept; upstream's raw usage fetch added under the same timeout so stalled usage still degrades. - Codex provider: upstream's withCodexAppServerClient + enriched rate-limits probe win (fork title branding already inside buildCodexInitializeParams). - ProviderCommandReactor: fork goal-continuation + correction-aware first-turn kept; upstream compact-command exclusion added. - OpenCodeAdapter ask path: fork's pendingGate/acceptingRequests gate kept; upstream full-access autoReply + terminal guard + emitUnsafe added. - makeManagedServerProvider: fork probe-timeout protection kept; upstream usage-limits reconciliation applied to the checked snapshot. - Manager.ts preview CDP: fork reuse-if-attached + detach resilience kept; upstream wcDebugger hardening applied. - mobile threadSyncPhase pill dropped (upstream ThreadDetail redesign covers loading/sync presentation); outbox deliveryMode + goal handling kept. - Usage: fork client-version projection kept; upstream pricing()/refreshRates adopted on both clients. - Settings: fork sections (MT Teams+badge, voice, notifications, account sign-in) kept; upstream reorg (ids, submenus, behaviour section) adopted. - README: fork copy kept; Antigravity added to provider lists. - Cursor skill test macOS /var-vs-/private/var path failure is pre-existing upstream breakage, unrelated to this merge. Fork guard script OK.
Second sync of 2026-09-04: 108 upstream commits (9c9ae3d..c8f77e0), 32 of 33 fork commits replayed. - Entry 22's server half is superseded by upstream's Limits tab work (pingdotgg#9507, pingdotgg#9534, pingdotgg#9584); its web half is re-derived onto ServerProvider.usageLimits and the fork's server files are dropped. - Entry 14 declines upstream's two new workflows (windows-tests.yml on a Blacksmith runner, cursor-hygiene-webhook.yml needing Cursor secrets). - Entry 7's history store moves to upstream's createDeferredStorage; entry 19's colour ramp is read as colors[0] by upstream's new UsageLimits.tsx. - FORK.md section 2 records the rebase; every entry's check note and the superseded table move to c8f77e0; README banner refreshed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LyxmS9VVThN5D4JqXrB4CY
When the provider instance behind a thread reports an exhausted usage window, the composer shows the reset time and offers to snooze the thread until a minute past it. Derived on the client from the provider snapshot that pingdotgg#9507 already publishes, so no contract, server, or migration change. Built with Claude Fable 5.1 in Claude Code.
When the provider instance behind a thread reports an exhausted usage window, the composer shows the reset time and offers to snooze the thread until a minute past it. Derived on the client from the provider snapshot that pingdotgg#9507 already publishes, so no contract, server, or migration change. Built with Claude Fable 5.1 in Claude Code.
When the provider instance behind a thread reports an exhausted usage window, the composer shows the reset time and offers to snooze the thread until a minute past it. Derived on the client from the provider snapshot that pingdotgg#9507 already publishes, so no contract, server, or migration change. Built with Claude Fable 5.1 in Claude Code.
When the provider instance behind a thread reports an exhausted usage window, the composer shows the reset time and offers to snooze the thread until a minute past it. Derived on the client from the provider snapshot that pingdotgg#9507 already publishes, so no contract, server, or migration change. Built with Claude Fable 5.1 in Claude Code.
When the provider instance behind a thread reports an exhausted usage window, the composer shows the reset time and offers to snooze the thread until a minute past it. Derived on the client from the provider snapshot that pingdotgg#9507 already publishes, so no contract, server, or migration change. Built with Claude Fable 5.1 in Claude Code.
* fix(web): send cited messages with Cmd+Enter (pingdotgg#9307) * fix(web): preserve explicit preview navigation URLs (pingdotgg#8902) * fix(web): prevent loading ssh environments from overriding navigation (pingdotgg#9168) * fix(mobile): skip unsupported shared settings targets (pingdotgg#9381) * fix(web): avoid duplicate Antigravity install status (pingdotgg#9419) * fix(composer): mute fast icon when collapsed (pingdotgg#9451) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(web): unify skeleton loading animations on one pulse (pingdotgg#9448) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(web): prioritize authored pull requests (pingdotgg#9453) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(web): make project icons the default (pingdotgg#9457) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(server): reuse pr state when settling threads (pingdotgg#9459) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(web): keep agent images collapsed (pingdotgg#9460) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(web): banner buttons no longer expand the resting composer (pingdotgg#9452) * fix(web): stop clipping the traits chevron on long Codex effort labels (pingdotgg#9433) Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): make right panel tabs easier to scroll (pingdotgg#9461) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(web): render transparent previews on white (pingdotgg#9463) * fix(mobile): show loading and syncing in the working pill (pingdotgg#9466) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * fix(server): keep a/ and b/ prefixes in rendered git patches (pingdotgg#9438) * fix(server): full-access OpenCode threads no longer ask for approvals (pingdotgg#9282) Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> * fix(web): reuse pull request list data while loading (pingdotgg#9467) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * feat(web): let users turn off composer collapse on blur and scroll (pingdotgg#9469) Co-authored-by: Claude Code <noreply@anthropic.com> * fix(web): move workflow approval beside checks (pingdotgg#9465) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(desktop): refresh generated annotation styles (pingdotgg#9488) * fix(web): let the PR reviewer and label search boxes take keystrokes (pingdotgg#9479) Co-authored-by: Claude Code <noreply@anthropic.com> * fix(web): dont collapse composer when interacting with bottom row (pingdotgg#9490) * fix(desktop): restore second-press quit fallback (pingdotgg#9485) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(web): keep opencode icon hollow in collapsed composer (pingdotgg#9492) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(web): keep agent browser preview visible (pingdotgg#9484) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(mobile): keep the machine glyph next to the environment label (pingdotgg#9486) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * fix(mobile): let back swipe pop from horizontal scroll edges (pingdotgg#9493) Co-authored-by: Claude Code <noreply@anthropic.com> * fix(antigravity): discover legacy workspace skills (pingdotgg#9410) Co-authored-by: Simone <185146821+Lucenx9@users.noreply.github.com> * fix(mobile): resolve Antigravity provider icon and normalize driver matching (pingdotgg#9495) * fix(antigravity): forward Google sign-in URLs from browser helper (pingdotgg#9425) * feat(desktop): import browser cookies into a profile (pingdotgg#7255) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(desktop): import from Chrome, Edge, Brave, Vivaldi, Opera, Arc and Firefox (pingdotgg#7260) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(desktop): resolve Chromium cookie keys on Linux (pingdotgg#7261) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(antigravity): allow slow runtime startup during setup (pingdotgg#9510) * fix(antigravity): keep model choices up to date (pingdotgg#9511) * fix(antigravity): handle native sign-in URLs on stderr (pingdotgg#9514) * fix(antigravity): update managed runtime to 1.1.1 (pingdotgg#9509) * fix(desktop): address the browser import review left over from the stack (pingdotgg#9516) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Utkarsh Patil <73941998+UtkarshUsername@users.noreply.github.com> * feat(antigravity): show subagent calls and results (pingdotgg#9515) * fix(web): let paste expand a resting composer (pingdotgg#9498) Co-authored-by: Claude Code <noreply@anthropic.com> * fix(web): keep the composer open while selecting timeline text (pingdotgg#9499) Co-authored-by: Claude Code <noreply@anthropic.com> * fix(web): return focus to the composer after closing a media preview (pingdotgg#9513) Co-authored-by: Claude Code <noreply@anthropic.com> * fix(server): keep events during thread subscription startup (pingdotgg#9521) * chore: forward issue/PR/discussion events to Cursor hygiene (pingdotgg#9518) Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com> * fix(auth): keep pairing credentials out of access read models (pingdotgg#9523) * chore: drop comment events from Cursor hygiene forwarder (pingdotgg#9527) * feat(codex): support async questions (pingdotgg#9512) * fix(web): keep right panel controls clickable (pingdotgg#9517) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * feat(usage): show Codex and Claude subscription limits on a Limits tab (pingdotgg#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 pingdotgg#1732 (server model, provider rows) and pingdotgg#9421 (Limits tab, window bars, pace maths). Closes pingdotgg#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> * feat(web): reorganize settings pages (pingdotgg#9354) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(server): settle branch threads immediately on pull request merge (pingdotgg#9528) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(server): back off relay client restarts after rapid exits (pingdotgg#8788) * fix(codex): accept rate limit errors on thread resume (pingdotgg#8897) * fix(desktop): preview CDP sessions no longer hard-crash the app (pingdotgg#9068) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * Fix worktree removal timing out on large install trees (pingdotgg#3902) * fix(web): settle the resting composer layout with a pixel of slack (pingdotgg#9482) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(web): keep automatic project icons consistent (pingdotgg#9535) * fix(server): include SQLite conditions in persistence errors Include SQLite conditions and schema issue tags without copying query data. Continue @Sy-D's [pingdotgg#4837](pingdotgg#4837). Add the missing Bun error codes and test the real SQL client. Created with GPT-6 Astra (preview) in Codex. Co-authored-by: Sy-D <8460326+Sy-D@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> * fix(dev): keep shared dev reloads and hot updates working (pingdotgg#9543) * feat(providers): add context compaction command (pingdotgg#9293) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(mobile): keep store screenshots free of system banners and show dictation (pingdotgg#9548) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * fix(web): restore composer controls as space becomes available (pingdotgg#9539) * fix(web): measure collapsed model labels at their visible width (pingdotgg#9540) * fix(web): close composer menus when their controls hide (pingdotgg#9541) * fix(web): thread error banner no longer shifts the chat (pingdotgg#9473) * fix(server): reveal normalized paths in File Explorer (pingdotgg#9551) * feat(marketing): fresh screenshot and floating marks on the homepage (pingdotgg#9547) Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> * feat(usage): redeem Codex reset credits from the Limits tab (pingdotgg#9534) Follow-up to pingdotgg#9507, carrying over the reset-credit redemption from pingdotgg#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 pingdotgg#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> * fix(server): find newly opened pull requests after agent turns (pingdotgg#9125) Refresh missing PR associations after agent turns on the thread's current branch. Preserve background policy, known PR caches, and failed-lookup backoff. Serialize status loads and refreshes to prevent stale responses from hiding a PR. Find branches pushed under their own name while still tracking the default branch. Original work by Theo Browne with Claude Fable 5.1 in Claude Code. Takeover fixes created with GPT-6 Astra (preview) in Codex. Co-authored-by: Theo Browne <me@t3.gg> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> * ci: add on-demand Windows test workflow (pingdotgg#9538) Co-authored-by: Claude Code <noreply@anthropic.com> * fix(web): simplify expanded tool details (pingdotgg#9549) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(web): keep the last message visible when the resting composer expands (pingdotgg#9553) Scrolling a long thread to the end with the composer at rest landed flush against the short composer. The expansion that followed then covered the last rows, because the timeline reserves only the live overlay height and does not move for footer growth. The timeline now keeps the expanded composer's height clear while the composer rests, so expanding it again changes nothing above the composer. The composer reports its resting flag from a layout effect and publishes a fresh overlay height whenever that flag changes, so the reservation is always computed from a height that belongs to the same layout. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test(web): fix flaky startup and Tailwind tests (pingdotgg#9558) * fix(web): keep codex restart responses continuous (pingdotgg#9560) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(web): make settings sidebar sub-section buttons full width (pingdotgg#9562) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * fix(web): render settings sidebar immediately (pingdotgg#9563) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * chore: vouch august contributors (pingdotgg#9557) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(web): stabilize right panel transitions (pingdotgg#9554) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix: better shell syntax handling for labels (pingdotgg#9371) * fix(web): align the sidebar wordmark by baseline (pingdotgg#9578) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(antigravity): keep subagent batches active after launch (pingdotgg#9579) * fix(mobile): render workspace images in markdown file previews (pingdotgg#8769) * fix(usage): deduplicate CLI proxy subscription accounts (pingdotgg#9584) * fix(web): bound disconnected send toasts (pingdotgg#9592) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(desktop): restore panel titlebar interactions (pingdotgg#9591) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(connect): refresh authorization without disconnecting (pingdotgg#9582) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(web): show context meter in compact composer (pingdotgg#9430) * fix(pull-requests): refresh data after thread turns (pingdotgg#9496) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(web): render draft PRs in gray (pingdotgg#9537) * refactor(web): move usage provider controls to settings (pingdotgg#9599) * fix: show idle subagent batches without completion marks (pingdotgg#9616) * fix(web): group image views like other tool calls (pingdotgg#9597) Co-authored-by: Claude Code <noreply@anthropic.com> * fix: preserve tool icons on failed calls (pingdotgg#9606) * fix(connect): diagnose incomplete headless server setup (pingdotgg#9602) * fix(web): keep command palette above composer menus (pingdotgg#9613) * fix(web): snooze menu no longer overlaps thread details (pingdotgg#9601) * fix(web): match composer pull request state icons (pingdotgg#9375) * fix(server): load OpenCode workspace skills via SDK to avoid 64KB CLI pipe truncation (pingdotgg#9585) * fix(web): mute sidebar branch name to match worktree icon (pingdotgg#9622) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * fix(web,mobile): fold context compaction under settled turn folds (pingdotgg#9623) Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> * feat(mobile): make chat text selectable on Android (pingdotgg#8779) Co-authored-by: shivam <91240327+shivamhwp@users.noreply.github.com> * fix(web): toggle a single stashed prompt with Cmd+S (pingdotgg#9644) Cmd+S opened the stash menu even when the composer was empty and only one prompt was stashed. It now restores that prompt directly, so repeated presses toggle between the draft and stash. Multiple entries and images that are still saving open the menu. The stash badge still opens the menu. Validation: 94 focused stash, shortcut, and attachment tests pass. Web typecheck and formatting pass. Targeted lint has no new warnings or errors. Browser checks were skipped at Theo's request. Original implementation by Theo Browne. No code changes were needed during the takeover audit. Audited with GPT-6 Astra (preview) in Codex. * fix(server): prevent duplicate desktop clients after restart Replace stale local desktop sessions in one transaction. Preserve paired clients and browser sessions, and keep the previous credential valid if replacement fails. Closes pingdotgg#6283. Original implementation by seeb1337. Reviewed and verified with GPT-6 Astra (preview) in Codex. Co-authored-by: seeb1337 <63622047+seeb1337@users.noreply.github.com> Co-authored-by: Theo Browne <me@t3.gg> * fix(web): resume Antigravity threads without repeated sign-in (pingdotgg#9647) Allow Antigravity threads to resume while saved Google sign-in is unchecked after a server restart. Keep confirmed authentication failures and installation errors visible. Validated with 136 focused tests, web typecheck, targeted lint, and CI. Browser verification was omitted at the maintainer's request. Created with GPT-6 Astra (preview) in Codex. * feat(mobile): paste the phone clipboard into the terminal (pingdotgg#9199) Co-authored-by: Jake Leventhal <jakeleventhal@me.com> Co-authored-by: shivam <91240327+shivamhwp@users.noreply.github.com> * feat(web): show which sidebar threads hold an unsent draft (pingdotgg#9658) Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> * fix(server): unblock OpenCode approvals and stop (pingdotgg#9653) OpenCode could show an Approval badge with no controls, appear stuck on TodoWrite, and keep showing a running turn after Stop. - Show every permission, including old saved requests. Keep failed replies retryable and close completed requests even when reply events are lost. - Keep OpenCode output pipes drained and automatic replies out of the event loop. Handle disconnects, reconnects, and confirmed stops without stale requests or running states. - Show native task progress and command results. Do not treat TodoWrite or approval history as file edits or executed commands. - Ignore late aborts and task updates after a turn finishes. Fixes pingdotgg#4795 Fixes pingdotgg#7113 Fixes pingdotgg#5760 Created with GPT-6 Astra (preview) in Codex. Reviewed and merged with Claude Fable 5.1 in Claude Code. * fix(desktop): quit immediately on a second shortcut press (pingdotgg#9657) * fix(server): update Claude Agent SDK to 0.3.260 (pingdotgg#9135) Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> * perf(server): stop loading message bodies for thread summaries (pingdotgg#9662) * perf(web): speed up terminal snapshots (pingdotgg#9663) * Complete upstream sync adaptations and validate Claude authentication * Fix reviewed Coder sync regressions and add focused coverage * Include orchestration regression suites in Coder tests --------- Co-authored-by: Exotic <118054752+extoci@users.noreply.github.com> Co-authored-by: Yukun Shan <92423096+nateEc@users.noreply.github.com> Co-authored-by: oliver <97427849+flamboh@users.noreply.github.com> Co-authored-by: Simone <lucenz@proton.me> Co-authored-by: Rakshith Bhat <88523594+RakshithBhat03@users.noreply.github.com> Co-authored-by: maria <maria@kuuro.net> Co-authored-by: maria-rcks <254055478+maria-rcks@users.noreply.github.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: Zortos <zortosdev@proton.me> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Utkarsh Patil <73941998+UtkarshUsername@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Igor Makowski <56691628+Mnigos@users.noreply.github.com> Co-authored-by: shivam <91240327+shivamhwp@users.noreply.github.com> Co-authored-by: Simone <185146821+Lucenx9@users.noreply.github.com> Co-authored-by: Invictine <72551038+Invictine@users.noreply.github.com> Co-authored-by: WellyngtonF <59291417+WellyngtonF@users.noreply.github.com> Co-authored-by: Theo Browne <me@t3.gg> Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com> 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: Derek Trimm <275381468+derektrimm@users.noreply.github.com> Co-authored-by: Seth Webster <sethwebster@gmail.com> Co-authored-by: Jake Leventhal <jakeleventhal@me.com> Co-authored-by: Matheus Timbó Pereira <matheusfild4@hotmail.com> Co-authored-by: Sy-D <8460326+Sy-D@users.noreply.github.com> Co-authored-by: Yash Singh <saiansh2525@gmail.com> Co-authored-by: Dara Adedeji <76637177+SunkenInTime@users.noreply.github.com> Co-authored-by: Guilherme Vieira <46866023+GuilhermeVieiraDev@users.noreply.github.com> Co-authored-by: Guillermo Casanova <75276669+Gigioxx@users.noreply.github.com> Co-authored-by: Barry <43803274+BarryHenryJr@users.noreply.github.com> Co-authored-by: seeb1337 <63622047+seeb1337@users.noreply.github.com> Co-authored-by: Lars Nieuwenhuis <35393046+lnieuwenhuis@users.noreply.github.com>

Closes #228.
Users on Codex or Claude Code subscriptions could not see how much of their quota was left, or when it resets, without leaving T3 Code. And a user whose CLIs route through a CLIProxyAPI hub could not see it at all: the Claude CLI treats the proxy token as an API key, and the hub's Codex login is not the one on disk.
What changed
Limits tab on the Usage page (web) and a Limits card (mobile), next to Cost and Tokens. Each provider that knows its subscription usage gets a section with one row per window: label and percent, a bar spanning the whole window with a hairline at the elapsed share ("where even spending would be"), a pace icon, and a reset countdown. Hover a bar for the exact reset time in your configured clock format. Emails are blurred until clicked, as in provider settings.
Each driver owns its data.
checkProviderreturnsusageLimitson the driver's ownServerProvidersnapshot — Codex fromaccount/rateLimits/readduring the probe it already runs, Claude from the SDK'sget_usagecontrol request on the capabilities query it already opens. Adapters normalise their turn-driven rate-limit events at the boundary into a typedProviderUsageLimitsUpdate, and a ~40-line driver-blind ingestion layer folds them onto the owning instance throughapplyUsageLimits, so bars move mid-turn without a central service that switches on driver kind. Claude's model-scoped weekly bucket (Fable today) is read fromrate_limits.model_scoped[]; the probe records the model's name so the streamedseven_day_overage_includedevent lands on the same row.CLIProxyAPI hubs as usage-limit sources (second commit).
settings.usageLimitSourcesentries are polled on the provider health interval and published over the config stream, gated by a client capability flag the way environment themes are. Not a provider — nothing here can run a turn, and one source reports many accounts. The management key goes to the secret store; settings keep a redaction marker. Hub accounts show under the hub's name, badged via CLIProxyAPI so a pooled account is not mistaken for the local login. Add CLIProxyAPI hub on the view adds one; Remove confirms before deleting the key.Cursor, Grok, OpenCode, and Antigravity report nothing — their drivers never set
usageLimits, so they have no row. Adding one later is "returnusageLimitsfromcheckProvider" with no central change.Provenance
Distilled from two earlier PRs rather than merged from either:
claude --print /usageoutput that current CLIs no longer print, and its Cursor/Grok paths drove interactive TUIs; those are replaced or left out, and are welcome back as follow-ups againstcheckProviderif a non-scraping source appears.packages/shared, and anchoring countdowns to render time. Its centralUsageLimitsServiceand reset-credit redemption are not carried over.Both are co-authors on the first commit.
Screenshots
The local Codex row shows a 401 because that box's
~/.codexlogin is revoked; the same account via the hub is healthy. The local Claude row is an API-key session (proxy token), so it says so.Verification
yauzl/mobile-markdown-texterrors onmain.fablewindow.get_usagewindows (every Claude login on the test box goes through the hub, so the CLI reports API-key mode). The mapper is tested against the SDK's documented shape and the CLI's actualmodel_scopedoutput; the bars are proven with stubbed data.Follow-ups
Written by Claude Fable 5 via Claude Code, with the design and server model from the two PRs above.
Note
Medium Risk
Touches provider probes, runtime event shape (
limitsvsrateLimits), config streaming, and secret-store settings—clients must opt into new events; incorrect merge logic could show stale or wrong quota.Overview
Adds a Limits view on Usage (web tab + mobile section) that shows subscription quota windows per connected environment—bars, pace vs. elapsed time, and reset countdowns—using shared helpers from
@t3tools/shared/usageLimits.Provider snapshots now carry normalized
usageLimits: Codex readsaccount/rateLimits/readon probe; Claude adds SDKget_usageon the capabilities probe and maps streamedrate_limit_eventinto the same window ids (including model-scoped weekly via probe-recorded names).account.rate-limits.updatedemits typedlimitsinstead of raw payloads; ProviderUsageLimitsIngestion merges updates throughServerProviderShape.applyUsageLimitsonmakeManagedServerProvider(sparse merge by window id, keep last good bars on probe failure).CLIProxyAPI hubs can be configured under
settings.usageLimitSources(management key in secret store, redacted on disk).UsageLimitSourcespolls hubs and streamsusageLimitSourcesUpdatedwhen clients opt in via capability/subscription flags; refresh providers also refreshes sources. Web UI can add/remove hubs; mobile shows pooled accounts without emails.Reviewed by Cursor Bugbot for commit 20594ca. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add Codex and Claude subscription limits to a Limits tab
usageLimitSourcescapability.AccountRateLimitsUpdatedPayloadreplaces the untypedrateLimitsfield with a structuredlimitsfield usingProviderUsageLimitsUpdate; settings persistence now writes management keys to the secret store and only persists redaction markers inusageLimitSources.Macroscope summarized 20594ca.