@excellent-so/usage-cache
v0.1.0
Published
Single-flight, file-cached reader for the Anthropic OAuth usage endpoint. Collapses many local clients (Claude Code statuslines, dev shells, menu bars) onto ONE network read per interval so they stop tripping the per-token rate limit.
Downloads
19
Maintainers
Readme
@excellent-so/usage-cache
A single-flight, file-cached reader for the Anthropic OAuth usage endpoint
(GET https://api.anthropic.com/api/oauth/usage — the one claude /usage reads).
Why
That endpoint rate-limits per token. A dev box typically runs many clients
sharing one Claude Code OAuth token against it — every claude session's
statusline, a dev shell, a menu-bar meter. When each polls independently they
collectively drain the token bucket and sit in a 429 storm, so the usage
numbers they show go stale (and UIs "flip to cash" or freeze at a wrong ~30%
while real usage is 34%).
This package makes them share one read:
- cache-first — within
ttlMs(default 60s) every caller returns the cached reading and touches no network at all. - single-flight — when the cache is stale, exactly one caller (whoever wins an atomic file lock) hits the endpoint; the rest wait briefly and read the cache. N clients → one network read per interval.
- hold through 429 — a reading only goes stale, never wrong, until its
5h/7d window resets. A rate-limited read HOLDS the last good reading (flagged
rateLimited/stale) instead of collapsing to nothing.
CLI
usage-cache # "34%" session 5h headline ("~30%" when held)
usage-cache --statusline # "34% (5h) · wk 61%"
usage-cache --json # the full result object
usage-cache --binding # headline = hottest window (5h/weekly/scoped)
usage-cache --offline # serve cache only, never hit the network
usage-cache --ttl 30 # cache freshness window, in secondsIt never errors (always exits 0) — safe to drop straight into a statusline command or shell prompt.
Claude Code statusline
// ~/.claude/settings.json
{ "statusLine": { "type": "command", "command": "usage-cache --statusline" } }Every claude session then reads the shared cache instead of hitting the
endpoint itself.
Library
const { readUsage } = require("@excellent-so/usage-cache");
const res = await readUsage();
// {
// ok: true,
// quota: { fiveHour: { pct, resetsAt, severity }, sevenDay, scoped: [...] },
// binding: { scope, label, pct, resetsAt, severity }, // hottest window
// fetchedAt, ageMs,
// source: "network" | "cache" | "cache-wait" | "none",
// stale: false, // held >15 min (render with a leading "~")
// rateLimited: false, // last attempt was a 429
// expired: false, // window reset → pct meaningless
// }pct is a percent (0..100) — the endpoint's native unit.
Options
| option | default | meaning |
|---|---|---|
| ttlMs | 60000 | serve cache without a network read if younger than this |
| waitMs | 3000 | if another process holds the fetch lock, wait this long for its result |
| timeoutMs | 8000 | network timeout for the one GET |
| force | false | ignore the TTL and force a (still single-flight) read |
| offline | false | never hit the network; serve cache only |
| cacheDir | ~/.cache/excellent-usage-cache | override the shared cache location |
The shared cache
One JSON file all clients agree on: ~/.cache/excellent-usage-cache/usage.json
($XDG_CACHE_HOME respected; override with $EXCELLENT_USAGE_CACHE_DIR). Writes
are atomic (temp file + rename). The fetch lock is a sibling directory
(fetch.lock) created with atomic mkdir; a lock older than ~15s is presumed
dead and broken so a crashed holder never wedges every client.
Privacy
One read-only GET, to Anthropic only (the vendor already holding this data).
Nothing is sent beyond the auth header. The OAuth token is read from the macOS
Keychain (Claude Code-credentials) or ~/.claude/.credentials.json, used for
the request, and dropped — never logged, never persisted, never refreshed.
License
MIT
