confirmed implementation details from claude code v2.1.88 source. not speculation — see incidents.md for the external record.
all run simultaneously. any one can independently reject a request.
| bucket | window | internal name | header prefix |
|---|---|---|---|
| session | rolling 5h | five_hour |
anthropic-ratelimit-unified-5h- |
| weekly aggregate | rolling 7d | seven_day |
anthropic-ratelimit-unified-7d- |
| weekly opus | rolling 7d | seven_day_opus |
via representative-claim |
| weekly sonnet | rolling 7d | seven_day_sonnet |
via representative-claim |
| extra usage | monthly | overage |
anthropic-ratelimit-unified-overage- |
source: claudeAiLimits.ts:29-35
every inference API response includes real-time utilization — higher resolution than the usage API.
anthropic-ratelimit-unified-5h-utilization float 0-1
anthropic-ratelimit-unified-5h-reset unix epoch seconds
anthropic-ratelimit-unified-5h-surpassed-threshold float (when warning fires)
anthropic-ratelimit-unified-7d-utilization float 0-1
anthropic-ratelimit-unified-7d-reset unix epoch seconds
anthropic-ratelimit-unified-7d-surpassed-threshold float
anthropic-ratelimit-unified-overage-utilization float 0-1
anthropic-ratelimit-unified-overage-surpassed-threshold float
source: claudeAiLimits.ts:164-179
ccmeter cannot access these. claude code consumes them internally and does not write them to JSONL. available via interactive and headless sessions alike — but only the client sees them. a proxy or the 1-token haiku probe (see below) could capture them directly.
the client computes warnings from time-relative utilization ratios. these are the exact values ccmeter uses in burn rate prediction (report.py:EARLY_WARNINGS).
5h window: warn at 90% utilization when ≤72% of window elapsed
7d window (graduated):
- 25% utilization when ≤15% elapsed
- 50% utilization when ≤35% elapsed
- 75% utilization when ≤60% elapsed
source: claudeAiLimits.ts:53-70
rate limits are NOT raw token counts. the client tracks cost using API pricing. cache reads are 10x cheaper than inputs — a session that's 90% cache hits costs ~10% of an uncached session for the same token count.
source: claude.ts:48-57
pricing confirmed at platform.claude.com/docs/en/about-claude/pricing:
| model | input | output | cache read | cache write 5m | cache write 1h |
|---|---|---|---|---|---|
| opus 4.6 | $5 | $25 | $0.50 | $6.25 | $10 |
| sonnet 4.6 | $3 | $15 | $0.30 | $3.75 | $6 |
| haiku 4.5 | $1 | $5 | $0.10 | $1.25 | $2 |
note: JSONL reports cache_creation_input_tokens without distinguishing TTL. ccmeter uses the 5m price. if claude code uses 1h caching for system prompts (likely), cache write costs are underestimated by ~60% on those tokens — roughly ~8% of total cost per percent.
this validates ccmeter's cost-per-percent approach as the correct normalization.
every inference response includes a status header:
anthropic-ratelimit-unified-status: allowed | allowed_warning | rejected
on rejection (429), additional headers identify the cause:
anthropic-ratelimit-unified-representative-claim: five_hour | seven_day | seven_day_opus | seven_day_sonnet
anthropic-ratelimit-unified-reset: <unix epoch>
anthropic-ratelimit-unified-fallback: available
retry-after: <seconds>
overage layer (when base budget exhausted):
anthropic-ratelimit-unified-overage-status: allowed | allowed_warning | rejected
anthropic-ratelimit-unified-overage-disabled-reason: <one of 12 enum values>
source: claudeAiLimits.ts:376-436
- 429 with retry-after < 20s → sleep and retry same model (preserves prompt cache)
- 429 with retry-after > 20s → fast mode cooldown (10-30min), fall back to standard speed
- 429 on opus, sonnet available →
FallbackTriggeredError, switches to sonnet - 529 overloaded → 3 retries for foreground, 0 for background, then fallback
- persistent mode (
CLAUDE_CODE_UNATTENDED_RETRY) → retries indefinitely, 5min max backoff, capped at 6h
source: withRetry.ts
for max/pro subscribers, the server sends x-should-retry: true but the client ignores it — the retry window would be hours, which is useless. only enterprise (PAYG) users respect it.
subscribers hitting a 429: the client shows the error and stops. no automatic retry. this means ccmeter data shows sharp utilization plateaus at the limit — utilization stops changing because no more calls are being made.
source: withRetry.ts:737-742
opus 4.6 defaults to medium effort for pro, max, and team subscribers. medium = less thinking = fewer output tokens = less budget consumed. not observable from JSONL — a known confounder for cost-per-percent.
source: effort.ts:307-319
interactive sessions send a 1-token haiku call at startup to populate rate limit state:
model=haiku, max_tokens=1, messages=[{role:'user', content:'quota'}]
non-interactive sessions (-p flag) skip this entirely — they get utilization from their first real call's response headers.
source: claudeAiLimits.ts:199-249
SHORT_RETRY_THRESHOLD_MS = 20s retry with same model below this
MIN_COOLDOWN_MS = 10min minimum fast mode cooldown
DEFAULT_FAST_MODE_HOLD_MS = 30min default fast mode cooldown
PERSISTENT_MAX_BACKOFF_MS = 5min max backoff for unattended retry
PERSISTENT_RESET_CAP_MS = 6h max total wait for persistent retry
MAX_529_RETRIES = 3 before model fallback
DEFAULT_MAX_RETRIES = 10 total retry attempts
BASE_DELAY_MS = 500ms exponential backoff base
HEARTBEAT_INTERVAL_MS = 30s keep-alive during long waits
integrated:
- early warning thresholds → burn rate prediction (shipped)
- cost-weighting confirmation → validates our approach
- bucket architecture → all confirmed buckets tracked
- rolling window semantics → informs burn rate math
- pricing → confirmed against official docs
not observable:
- per-response utilization headers (not in JSONL)
- effort level per session
- fast mode vs standard mode
- model fallback events
- cache write TTL (5m vs 1h)
future options:
- 1-token haiku probe for sub-minute utilization (cheap, returns utilization headers directly)
- proxy to capture per-response headers (invasive, fragile)