anthropics / anthropics/claude-code

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

Aperta
#93,107 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub
area:statusline enhancement platform:windows
Lingua principale
Python
Stelle
145k
Fork
23.1k
Metriche di merge delle PR
Metriche PR in attesa

Descrizione

## 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.

2. **`~/.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`.

3. **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`):

```json
"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

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Direzione di ricerca

Start by locating the status-line payload construction and the documentation section next to `spend_limit`; compare them with the `get_usage` control-request response described here. Confirm with maintainers whether Proposal A or B is in scope, then trace the chosen data path. Done means the per-model weekly window is exposed or its cache is refreshed on the stated cadence, existing consumers remain compatible, and the behavior is documented.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
go, typescript
Ambito
api, cli, developer-experience, documentation
Tipo di issue
Funzionalità
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Attiva
Chiarezza
Abbastanza chiara
Idoneità per principianti
45/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.