Status line: expose per-model weekly rate limit (Fable) in rate_limits, or keep cachedUsageUtilization fresh

Status Open
Maintainer reply None cached
Activity 0 comments · opened Sep 9, 2026

Problem

/usage shows a per-model weekly window ("Current week (Fable)"). A status line cannot show that row today: the stdin payload does not carry it, and the only on-disk copy is written solely when the user opens /usage, so it is usually stale or absent.

What exists today

  1. Status line payload. rate_limits carries only five_hour, seven_day and spend_limit (each with used_percentage and resets_at). There is no per-model window. Confirmed by capturing a live payload and against https://code.claude.com/docs/en/statusline.
  1. ~/.claude.json. The per-model row exists only in cachedUsageUtilization.utilization.limits[]:

``json
{"kind":"weekly_scoped","group":"weekly","percent":57,"resets_at":"…","scope":{"model":{"id":null,"display_name":"Fable"}}}
``

Claude Code writes this record only from its own /usage fetch, throttled to once per 5 minutes, and its own reader discards it after 1 hour. On my machine the record sat untouched from 2026-08-28 to 2026-09-09 while the file itself was rewritten constantly. A status line that reads it shows stale data or nothing unless the user opens /usage.

  1. Claude Code already produces the needed shape for another surface. The stream-json control request

``json
{"type":"control_request","request":{"subtype":"get_usage","skip_behaviors":true}}
``

returns rate_limits.model_scoped: [{display_name:"Fable", utilization:57, resets_at:"2026-09-10T05:59:59Z"}]. The SDK types describe it as "Per-model weekly windows from the server limits[] array, filtered by the overage-included-models allowlist. Additive — present only when the server emits them." The TypeScript Agent SDK exposes it as usage_EXPERIMENTAL_MAY_CHANGE_DO_NOT_RELY_ON_THIS_API_YET(). It needs no model call.

Why the workarounds do not fit

A status line runs on every refresh (every 10 s here). Measured cost per refresh:

  • claude -p --safe-mode … plus the get_usage control request: ≈1.4 s CPU, 340 MB peak RSS.
  • Python Agent SDK: ≈2.5 s CPU, 430 MB peak RSS.
  • Calling /api/oauth/usage directly: ≈50 ms, but it forces the status line to read the OAuth token from .credentials.json / Keychain. A status line script is the wrong place for a bearer token.

Proposal A: add model_scoped to the status line payload (preferred)

Mirror the shape Claude Code already emits for get_usage, using the payload's existing conventions (used_percentage, epoch-second resets_at):

"rate_limits": {
  "five_hour": { "used_percentage": 75, "resets_at": 1788963000 },
  "seven_day": { "used_percentage": 28, "resets_at": 1789020000 },
  "model_scoped": [
    { "display_name": "Fable", "used_percentage": 57, "resets_at": 1789020000 }
  ]
}
  • Additive and optional: absent when the server emits no per-model windows, so every existing script keeps working.
  • Same source as get_usage: the server limits[] array filtered by the overage-included-models allowlist. No new fetch.
  • Document it next to spend_limit in the statusline docs.

Concrete consumer: https://github.com/AbdallaM-Ibrahim/claude-code-statusline (Go, single binary, no network, no subprocesses; reads the stdin payload and local files only). The payload is parsed in internal/limits/limits.go, which already handles five_hour / seven_day and would pick up model_scoped from the same struct.

If you would take a PR for this, please say so here before I open one so I can match whatever naming or gating you prefer.

Proposal B: keep cachedUsageUtilization fresh (fallback if A is rejected)

Refresh cachedUsageUtilization on the same 5-minute cadence Claude Code already uses for its own limit warnings, not only when /usage is opened, so a file-reading status line can trust fetchedAtMs.

A dedicated small file (for example ~/.claude/usage-cache.json) is preferable to ~/.claude.json: that file is ~100 KB and rewritten constantly, so polling it every refresh means re-reading and re-parsing the whole config to extract one array, and racing its frequent writes.

Environment

  • Claude Code v2.1.266
  • Windows 11
  • Team subscription

View original on GitHub ↗