Sprag

Claude Code statusline behind LiteLLM and other gateways

How the Sprag statusline reads spend, budgets and cache TTL when Claude Code runs through LiteLLM or another API gateway, and why the cache countdown can look frozen.

🌐 Behind a gateway (Bedrock / Vertex)

A gateway reports the cache-creation total but never the 5m/1h split. That left the tool unable to tell "nothing cached yet" from "this provider does not say", and the fallback assumed an hour — for a window that is really five minutes on Bedrock, overstating it twelvefold.

Since v3.26.0 the gateway is detected from the model ids in the transcript, which fixes:

Cost and routing savings on a gateway use the gateway's prices. A Claude session with a gateway ANTHROPIC_BASE_URL is billed by the gateway, so Actual cost, Sep spend and Routing saved are computed from its /model/info prices (refreshed with the model map, valid for seven days). A model the gateway does not price stays unpriced: the session is left out and counted (+N unpriced) instead of being filled in from the Anthropic list prices. Sessions that do not go through a gateway keep using the list prices below. A delegation to a pricier model is recorded as a loss (-$0.12), not clamped to zero.

If the detection is wrong, pin it with sprag mode ttl=5m (or ttl=1h). An explicit value outranks the measurement.

LiteLLM: your key budget stands in for the missing 5h/7d caps (v3.35.0)

Behind a LiteLLM proxy (Bedrock and friends), Claude Code's stdin never carries rate_limits, so the ✦ current / 📅 weekly gauges simply do not exist. LiteLLM does track per-key budgets, so the statusline draws a budget gauge in their place.

claude.ai Enterprise: usage-credit budget gauge (v3.93.0)

Enterprise users who sign in with claude.ai do not get rate_limits in the statusline input either. The statusline now reads extra_usage from GET https://api.anthropic.com/api/oauth/usage and draws 💳 budget ▰▱ 54% $271/$500 in the same place.

One related non-bug: if your session model is already sonnet, a sonnet-delegation (T1) rule can never save anything, because there is no price gap to capture. That is correct, but route-scan rules displayed it identically to "no delegations yet", so it now says outright that the rule does not apply at the current default model.

LiteLLM: model aliases come from the gateway (sprag profile-map --refresh)

Behind a LiteLLM gateway, sprag profile-map --refresh reads model aliases straight from the gateway's own GET /model/info, so route-scan no longer needs to wait on learned votes or a hand-edited profile-map.json. The refresh uses the same 5-minute check and 24-hour cache as the LiteLLM budget gauge. It never stores your auth token: each refresh reads it from apiKeyHelper at call time and lets it expire on the helper's own schedule. The three-step resolution order and the manual profile-map.json format are in route-scan.

Pricing (Jul 2026)

Per million tokens (USD), as used by the cost estimator:

TierModelsInput5m Write1h WriteReadOutput
claude-fable-5-1Fable 5.1 / Mythos 5.1$10$12.50$20$0.25$50
claude-fable-5Fable 5 / Mythos 5$10$12.50$20$1$50
claude-opus-5-5Opus 5.5$4$5$8$0.20$20
claude-opus-newOpus 4.5 / 4.6 / 4.7 / 4.8 / 5$5$6.25$10$0.50$25
claude-opus-legacyOpus 4 / 4.1 / 3$15$18.75$30$1.50$75
claude-sonnet-5-5Sonnet 5.5$2$2.50$4$0.10$10
claude-sonnet-5Sonnet 5$2$2.50$4$0.20$10
claude-sonnetSonnet 3.7 / 4 / 4.5 / 4.6$3$3.75$6$0.30$15
claude-haiku-5-5Haiku 5.5 (prompt ≤ 100k tokens)$0.10$0.125$0.20$0.01$0.50
claude-haiku-5-5 (long)Haiku 5.5 (prompt > 100k tokens)$0.50$0.625$1$0.05$2.50
claude-haiku-4-5Haiku 4.5$1$1.25$2$0.10$5

Source: Anthropic pricing docs. Sonnet 5 stays at $2/$10; the planned rise to $3/$15 was cancelled. Haiku 5.5 prices each request by its own prompt length (input + cache writes + cache reads), so a request over 100k tokens pays the long rates. Versions ≤ 2.16.x priced Fable 5 at the Sonnet tier (~3× under-estimate) — upgrade to 2.17.0+.

Cache TTL by plan

PlanTTLControlled by
Max ($100–200/mo)1h autotengu_prompt_cache_1h_config flag
Pro ($20/mo)5m fixednot configurable
API key5m default (1h via beta header)cache_control.ttl

FAQ

Is this the same tool as claude-token-saver? Yes. Sprag is the new name and the npm package is sprag-cli. The old claude-token-saver package stopped updating at 3.55.0, so move to sprag-cli to keep receiving releases.

Does it call an LLM or need an API key? No. Everything is post-hoc analysis of the session logs Claude Code already writes on your machine. No extra model calls, no key, no telemetry leaves your computer.

Will it change how I prompt? No. It installs hooks and a statusline once, then works from what you already do. Rules, delegation, and warnings show up inside your normal sessions.

Where do the savings numbers come from? Each delegated run writes a ledger entry with the actual price difference. The tier criteria behind the routing are benchmarked on public data; the method is in docs/BENCHMARK.md.

How it works · Environment

Claude Code logs every API call to ~/.claude/projects/<dir>/<session>.jsonl. This tool dedupes streaming chunks by requestId and aggregates cache_read_input_tokens / cache_creation.ephemeral_5m/1h_input_tokens by day and session.

Node.js ≥ 20 · macOS / Linux / Windows / WSL · zero dependencies.

Known quirks · Migration · Background

IntelliJ Claude Code plugin — the statusline widget fuses frames at the character level when emoji are present (59:548 artifacts). v2.8.5+ detects TERMINAL_EMULATOR=JetBrains-JediTerm and falls back to text mode automatically.

If the countdown looks frozen: ticking while idle requires Claude Code to re-run the statusline command on a timer, controlled by statusLine.refreshInterval (seconds, Claude Code v2.1.97+) in ~/.claude/settings.json. Without it the line only redraws when the conversation updates. If behavior differs per terminal, check three things: ① that machine's Claude Code is ≥ 2.1.97; ② no project .claude/settings.json / settings.local.json overrides statusLine without a refreshInterval; ③ the statusline wrapper actually finds sprag on PATH instead of falling back to a multi-second npx run on every render (typical when nvm is not loaded in non-login shells). Re-running sprag install restores refreshInterval=5.

Migration from claude-cache-monitor:

npm uninstall -g claude-cache-monitor && npm i -g sprag-cli

Also update statusLine.command in ~/.claude/settings.json to sprag ….

Background: GitHub Issue #46829 (cache TTL regression) · HN discussion


More docs