Skip to content

fix(usage): read Cursor Unified Ultra current-period quotas - #31978

Merged
nwparker merged 5 commits into
mainfrom
nwparker/cursor-current-period-usage
Oct 23, 2026
Merged

nwparker merged 5 commits into
mainfrom
nwparker/cursor-current-period-usage

Conversation

@nwparker

@nwparker nwparker commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 1 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​282 0 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​282
Prod 13 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​148 $\color{#cf222e}{\Huge{\mathbf{−}}}$​37 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​111

ELI5

People on Cursor's new weekly plans saw Orca's Cursor usage stuck at 0%, with a reset date about a month away. Cursor moved these accounts to a weekly allowance. The old endpoint Orca reads still sends stale monthly zeros. The real numbers come from a newer endpoint.

With this PR, Orca reads that newer endpoint for those accounts, so it shows the actual usage (for example 1% Cursor Models) and the real weekly reset. Accounts that already show real usage make no extra request and behave exactly as before. The Accounts settings heading now reads "Plan usage" instead of "Monthly plan usage", because the period can be weekly.

What Changed

  • Which accounts ask for the current period. After the usual GET /api/usage-summary, Orca sends POST /api/dashboard/get-current-period-usage with body {} when either:
    • membershipType starts with unified_ (Cursor's weekly "X Subscription" family; unified_ultra is the confirmed case). These accounts trust the current period strictly.
    • the summary's Cursor/Other Models pools are all 0% and the summary does not say isUnlimited (unlimited non-unified plans keep main's no-bar result and make no extra request). That is the stale-zero symptom on weekly plans that don't use a unified_* membership, such as an enterprise seat moved to weekly Premium. These accounts only switch over when the current period is shorter than 27 days (a weekly window). If the period is monthly, or the request fails in any way, the summary is used unchanged. (added in de-risk pass)
  • The request uses the same selected credential and headers, with redirects and the cookie jar still disabled. planUsage goes through the existing pool mapper, which already handles clamping, numeric strings, epoch-millisecond date strings and named pools, using the window dates from the current-period response. On-demand keeps the summary's own billing period.
  • Fallback (endpoint gone): HTTP 404/405/501, or a non-JSON 200 body, falls back to the summary/legacy path. Cursor answers unknown /api/dashboard/* routes with a 200 HTML page, not a 404 (re-checked live).
  • Fallback (unusable data): valid JSON without usable cycle dates or percentages also falls back.
  • Unified plans, transient/auth failures: 401, 403, 429, 5xx and network errors come back as errors, so Orca never shows the stale 0% as healthy usage. The existing stale policy (applyStalePolicy in service-result-policy.ts) keeps showing the last good snapshot through these errors: up to 30 minutes, or 24 hours for 429.
  • Copy: "Monthly plan usage" becomes "Plan usage" in the Cursor Accounts heading, subtitle and two settings-search descriptions, in all 7 locales.

Linked Issue

Fixes #31803. Fixes #31804 (duplicate report, same account and same endpoint responses).

Evidence for the endpoint contract (upstream source, read-only clones)

I read six independent open-source Cursor usage trackers that call this endpoint:

  • Request shape: CursorMeter (docs/API_REFERENCE.md), Pulse (CursorUsageService.swift) and maxx-meter all use POST with {}, the Cookie header and Origin: https://cursor.com. That is the same request Orca sends.
  • Fields: they read root billingCycleStart/billingCycleEnd and planUsage.{autoPercentUsed, apiPercentUsed, totalPercentUsed}, the same fields Orca maps. Pulse's captured Premium fixture sends the dates as epoch-millisecond strings; parseCursorTimestampMs already handles those, and a new test uses that format.
  • Which plans are weekly: token-monitor, headroom, tokscale and Pulse all say weekly included usage covers the whole X Subscription family (Plus, Premium, Super, unified Ultra). headroom also records an enterprise seat moved to merged Premium on 2026-10-20 whose summary showed 0% while the week was 5.4% used. This is why gating on unified_ultra alone was too narrow. It is also why the second trigger (idle pools plus a weekly-length period) exists.
  • Monthly plans: CursorMeter's Ultra (monthly) capture shows the current period has the same cycle as the summary. So the sub-27-day check keeps monthly plans on the summary.
  • Team/enterprise seats get no planUsage from this endpoint (headroom). The mapper returns null, so these accounts keep the summary.

Verification

  • Bug reproduced on main: the regression file cursor-current-period-usage.test.ts fails on main's fetcher. The 4 new de-risk cases (enterprise seat on weekly Premium, plus idle-pool fallbacks for a monthly period, 429 and network failure) fail against the PR's previous fetcher and pass now.
  • pnpm test on the 6 Cursor rate-limit files (cursor-auth, cursor-current-period-usage, cursor-fetcher, cursor-session-token, cursor-usage-mapping, service-cursor-usage): 6 files / 99 tests pass after rebasing onto current origin/main (head 4ebe2d7). The new unlimited-plan case fails without the isUnlimited gate and passes with it.
  • Upstream check for the isUnlimited interaction: agi-cli (cli/src/lib/accounting/usage.ts) prefers the current-period reply for every account and ignores isUnlimited. So for unified_* accounts Orca still trusts the current period, and only the idle-pool trigger is gated.
  • Live checks against cursor.com (no real account credentials): GET on the endpoint returns 405 (the route exists and needs POST). POST to an unknown /api/dashboard/does-not-exist-xyz returns 200 text/html (the reason for the HTML fallback). An earlier run with Electron net.fetch and a rejected session got 401, which maps to "Cursor sign-in expired".
  • After the rebase: oxlint is clean on src/main/rate-limits, src/main/runtime/session-tabs, src/renderer/src/components/settings and src/shared/cursor-usage-buckets.ts; oxfmt --check is clean on all 14 changed files; full pnpm tc passes (node, cli, web, all configs).
  • CI note: the earlier red static analysis and typecheck run checked a merge ref from before fix(runtime): main lints and typechecks again after #32018 #32168 landed (oxlint max-lines on headless-terminal-tab-close.ts, a file this PR does not touch). This PR is now rebased onto a main that includes fix(runtime): main lints and typechecks again after #32018 #32168, which gives a fresh CI run that includes the gated unit-test job.
  • No Windows/Linux/remote exercise: the change is pure main-process HTTP and mapping, with no platform-specific code. No IPC or wire-schema changes, so mixed client/server versions are unaffected. Mobile reads the same ProviderRateLimits shape.

Visual Proof

Controlled responses in the real hidden Electron app on macOS (from the original author's run). The "before" data comes from the existing summary mapper. The "after" data comes through the production fetcher with synthetic HTTP responses copied from the issue. These are not live-account checks.

Legacy summary Current period
Legacy monthly zeroes Current weekly usage

Remaining Tradeoffs

  • Unified accounts with no earlier snapshot: a 5xx or network error on the current-period request shows an error, not the summary. This is on purpose, because for these accounts the summary is the known-stale 0% from the bug. Once a good snapshot exists, the stale policy keeps showing it (30 min, or 24 h for 429).
  • Unified + isUnlimited: a successful current-period reply is shown, not the barless unlimited result. This matches upstream trackers, which treat the current period as authoritative.
  • Extra request: one extra POST per refresh (default every 15 min) for unified_* accounts and for accounts whose summary pools are all 0%. Accounts with any real usage make no extra request.
  • Non-unified weekly seats depend on the endpoint being up. If the current-period request fails, they keep the old stale-zero summary. Orca can't tell those accounts are weekly without a successful reply.
  • Shape changes. If Cursor drops the percentage fields from the current-period reply, Orca falls back to the summary (possibly stale zeros) instead of showing an error.
  • Not verified with a real weekly account (none was available). The data shape comes from the issue reporter's capture plus the upstream trackers listed above. Both endpoints are undocumented.

Related

Earlier Cursor usage work: #22633, #24575, #25243, #28406. Thanks to @huangsky-stabo for the detailed issue with redacted endpoint captures.

Agent skill upstream boundary

  • Not applicable; no upstream skill-installer material copied.

@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d7d8032c-97ac-445d-87c3-3dbf08d3dd0b
📥 Commits

Reviewing files that changed from the base of the PR and between acb3d97faac441f6d918b71b24e23fdc52e60e3e and b19211f09686205ddf43a930639e2bbfea718a68.

📒 Files selected for processing: 2
  • src/main/rate-limits/cursor-current-period-usage.test.ts
  • src/main/rate-limits/cursor-fetcher.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review.

📝 Walkthrough

For Unified Ultra plans, the fetcher now requests Cursor’s current-period endpoint and maps valid usage and cycle dates. It retains summary handling when current-period data cannot be mapped or the endpoint returns HTTP 404, 405, or 501. Other request failures return errors. For non-unified plans, it uses current-period data only for qualifying short periods or idle summary pools; otherwise, summary data remains in use. Tests cover these paths. Cursor usage labels no longer describe plan usage as monthly.

Priority: ➖ Normal

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to b1921

The current-period usage change has no established merge-blocking issue after normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 7 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title "fix(usage): read Cursor Unified Ultra current-period quotas" names the main change: Orca now reads the Cursor current-period usage endpoint for Unified Ultra accounts. The PR also covers no…
Linked Issues check Passed [#31803, #31804] Both issues are open direct links that report the same bug. The requirement is that a selected unified_ultra account shows its current usage and weekly reset. The reviewed head impl…
Out of Scope Changes check Passed The core change set is the Cursor current-period fetch, its mapper, its tests, and the "Monthly plan usage" to "Plan usage" copy in the affected locale and search files. All of these connect to #31803…
Description check Passed The description is detailed and covers the user impact, implementation, linked issues, visual proof, testing, tradeoffs, compatibility, and agent-skill boundary. It does not include explicit Review, N…
Full details: Title check

Explanation

The title "fix(usage): read Cursor Unified Ultra current-period quotas" names the main change: Orca now reads the Cursor current-period usage endpoint for Unified Ultra accounts. The PR also covers non-unified idle-pool fallbacks and copy changes, which the title does not mention, but it does not need to cover every detail.

Full details: Linked Issues check

Explanation

[#31803, #31804] Both issues are open direct links that report the same bug. The requirement is that a selected unified_ultra account shows its current usage and weekly reset. The reviewed head implements this. fetchCursorRateLimits in src/main/rate-limits/cursor-fetcher.ts sends POST https://cursor.com/api/dashboard/get-current-period-usage with body {}, the selected session Cookie, and Content-Type: application/json. For membershipType values starting with unified_, it always requests the current period. mapCursorCurrentPeriodUsage in src/main/rate-limits/cursor-usage-mapping.ts validates billingCycleStart, billingCycleEnd and planUsage with zod. It rejects invalid or non-increasing dates and maps the pools through the existing summary mapper, which handles autoPercentUsed, apiPercentUsed and totalPercentUsed. The window dates come from the current-period response, and on-demand usage is kept from the summary. The requirement for defensive mapping is met. The requirement to keep the summary and legacy paths for older plans is met. HTTP 404, 405, 501, or an unparseable body fall back to the summary path. The diff does not touch account selection or credential storage, so the CLI/Keychain account stays separate from the IDE account. The regression test file cursor-current-period-usage.test.ts (+282 lines) covers these cases according to the PR evidence. I did not read the test bodies, so test coverage is taken from the summary and PR description.

Full details: Out of Scope Changes check

Explanation

The core change set is the Cursor current-period fetch, its mapper, its tests, and the "Monthly plan usage" to "Plan usage" copy in the affected locale and search files. All of these connect to #31803 and #31804. The copy change is needed because the reported period can be weekly. The non-unified path (summaryPoolsIdle with a period under 27 days) is a wider change than the issue text. It applies the same stale-zero fix and the same endpoint to non-unified plans whose summary pools are all 0%. The diff shows a sub-monthly period check and summary fallback for monthly or failed responses, so the scope stays on the Cursor usage symptom. No changes touch cursor-auth, account selection, credential storage, IPC, or platform code. Note for the reviewer: this adds one extra POST for idle non-unified accounts on each refresh, including monthly accounts that are idle. This cost is documented in the PR and is not a scope violation.

Full details: Description check

Explanation

The description is detailed and covers the user impact, implementation, linked issues, visual proof, testing, tradeoffs, compatibility, and agent-skill boundary. It does not include explicit Review, Notes, or Checklist sections, and it uses Verification instead of the template’s Testing heading, but the required information is largely present.

✨ Finishing Touches: 💡 2
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@nwparker
nwparker force-pushed the nwparker/cursor-current-period-usage branch 2 times, most recently from acb3d97 to b19211f Compare October 23, 2026 03:58
nwparker and others added 5 commits October 22, 2026 21:06
…HTML

Cursor answers unknown /api/dashboard routes with a 200 HTML app shell, so a
retired current-period endpoint would surface as a permanent parse error for
every Unified Ultra account instead of the summary fallback.

Co-Authored-By: Claude <noreply@anthropic.com>
Unified Ultra now reports a weekly period, so the Accounts heading and search
copy no longer promise a monthly window.

Co-Authored-By: Claude <noreply@anthropic.com>
…plans

Cursor's weekly X Subscription plans (Plus/Premium/Super/Ultra, incl. enterprise
seats moved to Premium) all keep stale monthly zeros in usage-summary. Gate on
unified_* membership, or on idle summary pools with a sub-monthly current period;
non-unified plans ignore current-period failures so their behavior is unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
…unified plans

Co-Authored-By: Claude <noreply@anthropic.com>
@nwparker
nwparker force-pushed the nwparker/cursor-current-period-usage branch from b19211f to 4ebe2d7 Compare October 23, 2026 04:07
@nwparker
nwparker merged commit 1ec8f07 into main Oct 23, 2026
44 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant