Rate-limit vitals for Claude Code — burn rate, cache health, and baseline shift detection.
Project description
claude-code-vitals
Know your limits before they know you.
A passive, always-on rate limit monitor for Claude Code. Tracks drift, predicts depletion, detects cache resets, and tells you when to switch models. Zero token cost. Zero external dependencies.
Opus 4.6 (1M context) | 5h: 87% left | 7d: 84% left | resets 2h 17m
Percentages are color-coded: green (<50% used), yellow (50-80%), red (>80%).
The Problem
You're deep in a coding session. Claude starts responding slower, or cuts off early, or just stops working. You have no idea if:
- You used too much quota today
- Your rate limit ceiling shifted without warning
- There's a temporary throttle during a model transition
- Your cache just reset and you're burning 5x more budget
Existing tools show current usage. Nobody tracks whether the ceiling itself changed, predicts when you'll run out, or watches your prompt cache health.
Install
pipx install claude-code-vitals
ccvitals init
# Restart Claude Code — done.
Or with pip:
pip install claude-code-vitals
ccvitals init
That's it. ccvitals init configures your Claude Code status bar automatically.
What You See
Normal — clean single row
Usage spike — drift detected, with attribution
Running low — depletion ETA, compact warning, switch hint
A week with ccvitals in 30 seconds
Simulated readings, real pipeline: the 5h window sawtooths all week with zero false alarms; a sustained ceiling shift is confirmed after three consecutive readings.
Multi-Row Progressive Disclosure
Row 1 always shows essentials (model, percentages, countdown). Row 2 appears only when something needs attention (alerts, cache issues, depletion warnings). Clean when everything is fine.
How It Works
flowchart TD
A["Anthropic API servers"] -->|"HTTP headers: anthropic-ratelimit-unified-*"| B["Claude Code (parses headers internally)"]
B -->|"stdin JSON with rate_limits, cost, model, context_window"| C["ccvitals run"]
C --> D["Log to ~/.claude-code-vitals/history.jsonl"]
C --> E["Compare to rolling median baseline"]
C --> F["Compute per-prompt delta"]
C --> G["Track context + cache state"]
D --> H["Build burn rate profile\n(how fast utilization % increases per hour)"]
H --> I{"Same burn rate,\nbut hitting limits sooner?"}
I -->|"Yes"| J["USAGE SPIKE\n(baseline shift)"]
I -->|"No — burn rate increased"| K["USAGE SPIKE\n(you're using more)"]
E --> L{"Current vs. median:\ndeviation > threshold?"}
L -->|"Yes, 3+ consecutive"| M["Signal: USAGE SPIKE or USAGE DROP"]
L -->|"No"| N["STABLE (hidden — clean status bar)"]
F --> O["Per-prompt delta display\n+1.2% last prompt"]
G --> S{"Cache hit rate\ndropping?"}
S -->|"Yes"| T["Cache miss warning\n+ root cause detection"]
S -->|"No"| U["Cache healthy — hidden\n(shown only when <80%)"]
G --> V{"Context near\ncompact threshold?"}
V -->|"Yes"| W["Compact warning\n(per-model thresholds)"]
The key insight
Every interaction with Claude Code generates a reading. Over time, claude-code-vitals builds your burn rate -- how fast your utilization increases per hour of usage.
- Same burn rate + hitting limits sooner -- the ceiling shifted. You're using the same amount but getting less headroom.
- Higher burn rate + hitting limits at the same time -- your consumption increased. The ceiling is unchanged.
This is how claude-code-vitals separates a ceiling shift from a behavior change -- with math, not guesswork.
Features
Rate Limit Intelligence
- Drift detection -- rolling median baseline comparison with attribution ("you're using more" vs. "baseline shift")
- Four signals -- USAGE SPIKE (yellow), USAGE DROP (blue), COLLECTING (building baseline), STABLE (hidden)
- Per-model burn-rate tracking -- the 5h/7d windows are shared across all models; each model's burn rate against that shared window is tracked separately (Opus drains it ~3-5x faster than Sonnet)
- Burn rate + depletion prediction -- "runs out 45m" based on your current consumption rate (red <60min, yellow <5hr)
- Model switch suggestions -- "try Sonnet (slower burn)" when you're on Opus and the shared window is >70% used
- Reset countdown -- time until your 5-hour window resets
Per-Prompt Delta
- +2.3% last prompt shown after every response
Context + Cache Intelligence
- Context tracking -- "ctx: 48% (96k)" with color-coded percentage
- Cache hit rate -- shown only when degraded (<80%); hidden when healthy to keep the bar clean
- Cache miss detection -- identifies root cause when cache drops
- Compact warnings -- alerts before auto-compaction resets your cache chain
- Idle gap warnings -- notifies when 5-minute cache TTL is at risk
All cache/context elements use progressive disclosure -- they only appear when something needs your attention.
Display
- Color-coded urgency -- green (<50% used), yellow (50-80%), red (>80%)
- Cost display -- "$3.50" session cost (toggleable)
Passive by Design
- Zero API calls -- reads data Claude Code already provides
- Zero token cost -- purely passive observation
- Zero external dependencies -- pure Python standard library, runs in well under 100ms
Progressive Disclosure
The status bar shows only what matters right now. When everything is fine, you see 4 elements. Alerts, cache warnings, and switch hints only appear when they need your attention. For the full picture anytime: ! ccvitals status --all-models.
Commands
ccvitals init # One-time setup
ccvitals status # Show current drift analysis
ccvitals status --all-models # Show all models at once
ccvitals status --show-readings # Include readings count
ccvitals status --show-remaining # Show remaining % instead of used %
ccvitals budget # How long the shared window lasts per model
ccvitals suggest # Models ranked by burn rate
ccvitals baseline # Show/maintain rolling baselines (reset|freeze|window)
ccvitals explain # Full status bar guide
ccvitals explain cache # Prompt cache mechanics
ccvitals explain compact # Auto-compaction + cache chain breaks
ccvitals explain models # Model differences + shared window
ccvitals config list # View all settings
ccvitals config set <key> <value> # Change any setting
ccvitals privacy # View privacy policy
ccvitals uninstall # Remove configuration
ccvitals --version # Show version
Configuration
View and change settings from the CLI -- no file editing needed:
ccvitals config set show_remaining true # Show remaining % instead of used
ccvitals config set show_readings true # Show readings count in status bar
ccvitals config set show_cost true # Show session cost ($) in status bar
ccvitals config set show_pattern true # Show time-of-day patterns
ccvitals config set all_models true # Always show all models in status
ccvitals config set compact true # Single-line or expanded view
ccvitals config set show_source true # Show data source in status bar
ccvitals config set threshold_pct 15 # Adjust drift sensitivity
ccvitals config set color false # Disable ANSI color output
ccvitals config list # See all current settings
All settings live in ~/.claude-code-vitals/config.toml:
[tracking]
baseline_window_days = 7 # Rolling window (1-84 days)
threshold_pct = 10 # % deviation to trigger signal
debounce_count = 3 # Consecutive readings to confirm
[display]
compact = true # Single-line (true) or expanded (false)
show_pattern = true # Show time-of-day patterns
show_remaining = false # true = show 88% left, false = show 12% used
show_readings = false # Show readings count in status bar
all_models = false # Show all models in status command
show_cost = false # Show session cost ($) in status bar
show_source = false # Show data source in status bar
color = true # ANSI color output
Session Tracking
claude-code-vitals records your Claude Code session ID with each reading and uses it internally to keep burn-rate math honest — consumption deltas are only computed between readings from the same session, so a parallel session can't inflate your burn rate.
Known limitation: Session detection is best-effort. With multiple concurrent sessions, cross-session readings are excluded from burn-rate pairs, which can delay a burn-rate estimate until two same-session readings exist.
Architecture
Claude Code -> stdin JSON -> ccvitals
|-> logger.py (append to history.jsonl)
|-> detector.py (rolling median + drift + burn rate)
|-> renderer.py (ANSI status bar + cache + delta)
Zero external dependencies. Pure Python standard library. Runs in well under 100ms.
Key Discoveries
Things we learned by watching the data that Anthropic doesn't document:
- Shared window, per-model burn rate -- the 5h and 7d windows are shared across all models (and across Claude Code, chat, and Cowork); switching models does not reset them. But the heavy models (Opus, Fable) burn the shared window fastest and each have their own tighter cap, so switching to a lighter model extends how long the window lasts and lets you keep working past the Opus/Fable limit.
- Opus costs 3-5x more -- Opus consumes roughly 3-5x more rate limit budget per request than Sonnet.
- 5-minute cache TTL -- prompt cache entries expire after 5 minutes of inactivity. Taking a break costs money on your next prompt.
- Auto-compact resets cache -- when Claude Code auto-compacts your context, the entire cache chain resets. The first prompt after compaction is expensive.
See ccvitals explain cache and ccvitals explain models for details.
FAQ: Where did my usage go?
Claude Code shows a single percentage, so a ceiling change and a behavior change look identical. When your limit seems to vanish, it's usually one of six things -- and ccvitals is built to tell them apart:
- One shared pool. The 5h and 7d windows are shared across every model (and across Claude Code, chat, and Cowork). There's no separate per-model balance. →
ccvitals suggest,ccvitals budget - Heavy models burn faster. Opus and Fable drain the shared window several times faster per request than Sonnet/Haiku -- Fable is the heaviest. →
ccvitals suggestranks models by burn rate - Cache invalidation. A 5-minute idle gap or an auto-compact resets your prompt cache; the next prompt is expensive. →
ccvitals explain cache,ccvitals explain compact - Context growth. A larger context costs more per prompt. → the
ctx:indicator in the status bar - The ceiling itself moved. Your limit can change (plan changes, promotions). ccvitals flags this as a baseline shift -- same burn rate, but hitting the wall sooner. → the drift signal in the status bar
Model eligibility and limits vary by plan and change over time -- ccvitals reports only what it can observe (your utilization and burn rate), never your plan tier. For current limits, Fable access, and any promotions, see Anthropic's pricing.
Data Stored
Each observation in ~/.claude-code-vitals/history.jsonl:
{
"ts": "2026-03-30T14:22:00Z",
"provider": "anthropic",
"model_id": "claude-opus-4-6",
"model_name": "Opus 4.6",
"session_5h_pct": 42.0,
"weekly_7d_pct": 67.0,
"source": "statusline"
}
Privacy
Everything stays local. Nothing is sent anywhere. No analytics, no telemetry, no phone-home.
Future versions may add opt-in anonymous crowdsourcing (utilization percentages only -- never prompts, keys, or identity). See ccvitals privacy for details.
Roadmap
- Phase 1: Local monitoring + drift detection with attribution
- Per-model burn-rate tracking (Opus, Sonnet, Haiku burn rates tracked separately)
- Reset countdown + color-coded thresholds
- CLI config management (
config set/list) - Session cost display
- Self-documenting (
ccvitals explainwith subtopics) - Burn rate + depletion prediction
- Per-prompt delta
- Model switch suggestions
- Phase 2: Context + cache intelligence
- Cache hit rate monitoring with per-model thresholds
- Compact warnings + idle gap detection
-
suggestandbudgetcommands - Multi-provider support (OpenAI, Google)
- Crowdsourced baseline (solve cold-start problem)
- Public dashboard
Why This Exists
15+ GitHub issues on the Claude Code repo requesting rate limit visibility in the statusline. Multiple community workarounds built. Users reverse-engineering undocumented OAuth endpoints. The demand is overwhelming.
claude-code-vitals goes further: it doesn't just show you where you are now. It tracks changes over time, predicts when you'll run out, watches your cache health, and flags when something shifted -- the only tool that does all of this.
License
MIT
Author
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file claude_code_vitals-0.4.0.tar.gz.
File metadata
- Download URL: claude_code_vitals-0.4.0.tar.gz
- Upload date:
- Size: 63.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3c3a838eac04b308060ccc2d538dea8b6a4b1e6a6c98b56c616aafb603fa7578
|
|
| MD5 |
4586c31790c988cb161cfa3493e8f95b
|
|
| BLAKE2b-256 |
d96c1266772461beb234707897bc42754a497eafdce93805e3596e943bbcdcf9
|
File details
Details for the file claude_code_vitals-0.4.0-py3-none-any.whl.
File metadata
- Download URL: claude_code_vitals-0.4.0-py3-none-any.whl
- Upload date:
- Size: 46.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1b553f66f2afd753ba826e573bd41e9ccf689902e4cbd9ea0beba5d4dff69f61
|
|
| MD5 |
668cfbcc3987193365f64f9ca21b9391
|
|
| BLAKE2b-256 |
402f9ad6fe65525c47ca1fd5611ea21087ade98141789dcfd6a79daa04926818
|