Skip to content

Add X Subscription usage collector to the agents panel - #15252

Open
the4rchangel wants to merge 6 commits into
omacom:quattrofrom
the4rchangel:feature/x-subscription-usage-tracker
Open

the4rchangel wants to merge 6 commits into
omacom:quattrofrom
the4rchangel:feature/x-subscription-usage-tracker

Conversation

@the4rchangel

@the4rchangel the4rchangel commented Oct 13, 2026 •

Copy link
Copy Markdown

Summary

  • Add omarchy-agent-usage-x so the stock Agents panel tracks The X Subscription shared first-party pool (Cursor + Grok).
  • Include dark/light X marks, enable x in the agents widget defaults, and document the collector (including that it depends on Cursor's private dashboard RPCs).
  • Cover plan/limits probing, cache reuse, auth failure fallback, transcript dating, and prompt counts with shell tests.

Test plan

  • ./test/shell.d/agent-usage-x-test.sh
  • Sign in with Cursor, run omarchy agent usage-update --force x, confirm x.json shows the shared pool meter and plan label (see comment with redacted output: Super · shared weekly pool)
  • Agents panel shows the X Subscription section with mark, plan, and limit row on a machine with Cursor auth
  • No separate Cursor tab is required for this shared-pool view (reconcile with Add every coding agent and provider to the agents panel and the default agent #14040 separately if that lands)

Track the shared Cursor + Grok first-party pool from Cursor's dashboard APIs as one agents record, with local prompt counts from Cursor transcripts.

Co-authored-by: Cursor <cursoragent@cursor.com>
@greptile-apps

greptile-apps Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 3/5

[Medium impact] Adds a new usage collector for the agents panel.

Fix duplicated synced token counts and failed requests erasing usage before merging.

Findings

  1. P1 Synced token counts double ▶
  2. P1 Failed requests erase usage ▶
  3. P2 Older active days disappear ▶

Summary

Adds an X Subscription collector to the Agents panel, using Cursor's private dashboard for shared-pool limits and token counts.

  • The Agents panel shows X Subscription’s shared Cursor and Grok pool.
  • X usage records show daily tokens and local prompt counts.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Auth["Cursor sign-in"] --> Limits["Plan and shared-pool limits"]
  Auth --> Tokens["Seven daily token requests"]
  Transcripts["Local Cursor transcripts"] --> Prompts["Prompt and session counts"]
  Limits --> Record["X usage record"]
  Tokens --> Record
  Prompts --> Record
  Record --> Panel["Agents panel"]
  Record --> Sync["Device snapshots"]
  Sync --> Panel
Loading

Reviews (4) · Last reviewed commit: "Fill X Subscription day tokens from Curs..." · Reviewed by Greptile

Comment thread bin/omarchy-agent-usage-x Outdated
Comment thread bin/omarchy-agent-usage-x Outdated
Comment thread bin/omarchy-agent-usage-x Outdated
Comment thread bin/omarchy-agent-usage-x Outdated
Comment thread bin/omarchy-agent-usage-x Outdated
Comment thread test/shell.d/agent-usage-x-test.sh Outdated
Always treat Cursor percent fields as 0–100, key the limits cache per sign-in, date prompts from transcript stamps, keep recentDays in tokens, and stop inventing activity from empty files.

Co-authored-by: Cursor <cursoragent@cursor.com>
@the4rchangel

Copy link
Copy Markdown
Author

Addressed the Greptile findings:

  • pct_to_unit always divides Cursor's 0–100 fields (so 1% is 0.01)
  • Limits cache is keyed + fingerprinted per Cursor access token
  • Prompt days come from transcript <timestamp> / turn timestamps; undated turns no longer land on today via mtime
  • recentDays.messageCount stays token totals (0 here); prompts remain in todayPrompts / totalPrompts
  • Empty / assistant-only transcripts no longer invent prompts or active days
  • Reuse test now passes real empty args and fails on unexpected API calls

@the4rchangel

Copy link
Copy Markdown
Author

Addressed the Greptile findings in a9cbcc7:

  • pct_to_unit always divides Cursor's 0–100 fields (so 1% is 0.01)
  • Limits cache is keyed + fingerprinted per Cursor access token
  • Prompt days come from transcript <timestamp> / turn timestamps; undated turns no longer land on today via mtime
  • recentDays.messageCount stays token totals (0 here); prompts remain in todayPrompts / totalPrompts
  • Empty / assistant-only transcripts no longer invent prompts or active days
  • Reuse test now passes real empty args and fails on unexpected API calls

@greptileai please recheck

Comment thread bin/omarchy-agent-usage-x Outdated
Transcript timestamps carry an offset; count them on the machine's local date so late-evening UTC-5 turns do not land on the wrong day after a timezone change.

Co-authored-by: Cursor <cursoragent@cursor.com>
@the4rchangel

Copy link
Copy Markdown
Author

Fixed the remaining P2: prompt <timestamp> offsets (and ISO/epoch times) convert into the machine's local calendar day before counting today/sessions.

@greptileai please recheck

@jandrusk

Copy link
Copy Markdown

A few questions before this is reviewable:

  • The manual items in the test plan (real Cursor sign-in, the panel showing the pool) are still unchecked. Could you run them and post the resulting x.json (redacted) or a screenshot?
  • It calls Cursor's internal DashboardService RPCs on api2.cursor.sh. Is that a documented/stable endpoint? If not, it would be good to say so in the README so breakage isn't a surprise.
  • It's turned on by default ("x": { "enabled": true }) for every install, including people with no Cursor login. Should it be opt-in, like the panel's other provider-specific extras?
  • Add every coding agent and provider to the agents panel and the default agent #14040 (open) adds a Cursor collector to the same panel, so the two will need to be reconciled.

Call out that the shared-pool meter still comes from undocumented DashboardService endpoints until xAI publishes a usage API for the merged plan.

Co-authored-by: Cursor <cursoragent@cursor.com>
@the4rchangel

Copy link
Copy Markdown
Author

Thanks for the questions — answers below.

Manual checks
Ran them on a real Cursor sign-in. Redacted x.json:

{
  "id": "x",
  "name": "X Subscription",
  "ready": true,
  "tierLabel": "Super · shared weekly pool",
  "limits": [
    {
      "label": "Included pool (Cursor + Grok)",
      "percent": 0.025,
      "resetsAt": "2026-10-20T05:15:23.057000Z",
      "title": "First-party"
    }
  ],
  "limitsStale": false,
  "todayPrompts": 13,
  "totalPrompts": 118,
  "totalSessions": 3
}

The Agents panel picks that up as an X Subscription section with the shared-pool meter. Test plan boxes are checked.

DashboardService stability
No, it isn’t documented. Same private api2.cursor.sh / DashboardService surface the Cursor UI uses for the included-usage meter. I looked for a cleaner X-native usage API for the merged Super plan; the xAI-facing snapshot routes need an identity assertion we don’t get from cursor-agent login, and the commerce bridge token is purchase-scoped only. So this is still the workable read path today. README now says that explicitly and that it can break if those RPCs move.

Default on
I left it default-enabled, same as Claude/Codex/Grok/Fireworks. With no Cursor login the collector writes an empty record and the panel already skips agents without data, so installs without Cursor shouldn’t grow a dead tab. Happy to flip it to opt-in if you’d rather treat this as a provider-specific extra.

#14040
Agreed they need reconciling. That PR’s Cursor collector is the broader Cursor story (same plan RPCs, plus aggregated token events and IDE auth). This one is intentionally the shared X Subscription pool view. If #14040 is the direction, I’m fine reshaping this to sit on top of it (or folding the Super/weekly pool labeling into that collector) rather than shipping two overlapping tabs. Want me to wait on #14040, or keep this as the pool-only record for now?

recentDays was left at zero after we stopped stuffing prompt counts into the token field; pull real per-day totals from GetAggregatedUsageEvents so the agents panel hero and meters have numbers again.

Co-authored-by: Cursor <cursoragent@cursor.com>
@the4rchangel

Copy link
Copy Markdown
Author

One more thing on the live record: tokens-by-day were showing 0 because we deliberately stopped putting prompt counts into recentDays.messageCount (the panel treats that field as tokens). Just pushed a follow-up that fills those days from GetAggregatedUsageEvents per local calendar day, so the hero’s “tokens this week” line and the day strip should have real numbers again while prompts stay in todayPrompts / totalPrompts.

Comment thread bin/omarchy-agent-usage-x
Comment on lines +576 to +579
stats["recentDays"] = tokens.get("recentDays") or stats.get("recentDays")
stats["todayTotalTokens"] = int(tokens.get("todayTotalTokens") or 0)
stats["todayTokensByModel"] = tokens.get("todayTokensByModel") or {}
stats["modelUsage"] = tokens.get("modelUsage") or {}

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.

P1 Synced token counts double

The new token totals cover the whole Cursor account, but the record uses the default device scope. If the same account is signed in on two synced machines, aggregateSnapshots adds the same dashboard totals twice. Separate account-wide token totals from device-local prompt counts so syncing does not inflate usage.

@the4rchangel the4rchangel Oct 13, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in 5ac0235: the collector record now sets scope: "account" so synced machines do not sum the same dashboard token totals.

Comment thread bin/omarchy-agent-usage-x Outdated
Comment on lines +223 to +226
except Exception:
payload = {}
rows = payload.get("aggregations") if isinstance(payload, dict) else None
usage = summarize_day_rows(rows if isinstance(rows, list) else [])

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.

P1 Failed requests erase usage

A failed daily request becomes zero usage, and cached_remote_token_stats writes that result over the last successful cache. A timeout or expired sign-in therefore erases known token counts from the panel, even when the limits request succeeds. Keep the cached counts for failed dates and mark them stale instead of treating failed requests as empty days.

@the4rchangel the4rchangel Oct 13, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in 5ac0235: a failed GetAggregatedUsageEvents day keeps the prior count for that date, marks tokens stale, and refuses to overwrite a good cache with a total failure.

Comment thread bin/omarchy-agent-usage-x Outdated
Comment on lines +581 to +584
prompt_days = stats.get("activeDates") or []
active = sorted(set(prompt_days) | set(token_days))
stats["activeDates"] = active[-30:]
stats["activeDays"] = len(active)

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.

P2 Older active days disappear

local_stats keeps the full activeDays count but only the last 30 entries in activeDates. The new merge rebuilds activeDays from that shortened list. A signed-in user with 80 active transcript dates and no dashboard token activity now reports 30 instead of 80. Preserve the full count when adding token dates, or merge against the full set of prompt dates.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in 5ac0235: activeDays is now max(prompt_active_days, len(merged_dates)) so truncating activeDates to 30 no longer shrinks the prompt-day count.

Mark dashboard aggregates as account-scoped, retain prior day counts when a request fails, and preserve the full prompt activeDays count when merging token dates.

Co-authored-by: Cursor <cursoragent@cursor.com>
@the4rchangel

Copy link
Copy Markdown
Author

Addressed the three new Greptile findings in 5ac0235:

  • Synced token counts double — record uses scope: "account"
  • Failed requests erase usage — failed day aggregates keep prior counts and mark tokens stale
  • Older active days disappear — activeDays keeps max(prompt count, merged dates)

Tests cover all three. Retriggered review.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants