Expose rate limit usage (session %, weekly %) to statusLine configuration

Status Fixed / completed
Maintainer reply ✓ Yes — claude[bot]
Activity 11 comments · opened Jan 24, 2026 · closed Apr 24, 2026
💡 Likely answer: A maintainer (claude[bot], contributor) responded on this thread — see the highlighted reply below.

Feature Request

Problem

The /usage command shows valuable rate limit information:

  • Current session: X% used (5-hour billing window)
  • Current week (all models): X% used (weekly limit)

However, this data is not available to the statusLine configuration. The statusLine only receives context window tokens and cost data, not the rate limit percentages.

Use Case

I want to see my session and weekly usage percentages persistently in the status bar without having to repeatedly open /usage. This would help me:

  • Know when I'm approaching limits before hitting them
  • Better pace my usage throughout the day/week
  • Avoid interruptions from unexpected rate limit hits

Current Workaround

None that provides the exact same data. Tools like ccusage track 5-hour blocks from JSONL files but may not match the percentages shown in /usage.

Proposed Solution

Add rate limit data to the JSON structure passed to statusLine scripts:

{
  "rate_limits": {
    "session": {
      "used_percentage": 91,
      "resets_at": "2026-01-24T13:59:00-06:00"
    },
    "weekly": {
      "used_percentage": 81,
      "resets_at": "2026-01-29T08:59:00-06:00"
    }
  }
}

This would allow users to display rate limit info in their custom status lines.

Environment

  • macOS Terminal
  • Claude Code CLI

View original on GitHub ↗

11 Comments

github-actions[bot] · 7 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/19374
  2. https://github.com/anthropics/claude-code/issues/20465
  3. https://github.com/anthropics/claude-code/issues/19385

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

dougbarlow · 6 months ago

To clarify the full scope of what's missing: the statusline JSON payload is currently missing two rate-limit fields that /status (Usage tab) exposes:

  1. Session rate-limit % ("Current session" in /status) — the 5-hour rolling token budget consumption
  2. Weekly rate-limit % ("Current week (all models)" in /status) — the weekly token budget consumption

The context_window.used_percentage field that is in the payload reflects context window fill (how full the 200K token context is), which is a different metric entirely and doesn't match what /status shows.

Suggested additions to the statusline JSON:

{
  "context_window": {
    "used_percentage": 73,
    "session_rate_limit_percentage": 49,
    "weekly_rate_limit_percentage": 32
  }
}
arowe-aei · 6 months ago

+1 to @dougbarlow's approach of nesting in context_window. I'd also include the reset timestamps from OP's proposal:

{
  "context_window": {
    "used_percentage": 73,
    "session_rate_limit_percentage": 49,
    "session_rate_limit_resets_at": "2026-01-24T13:59:00-06:00",
    "weekly_rate_limit_percentage": 32,
    "weekly_rate_limit_resets_at": "2026-01-29T08:59:00-06:00"
  }
}
TickTockBent · 6 months ago

Deep dive: the data already exists, here's exactly where

I spent time reverse-engineering how Claude Code handles rate limit data internally (v2.1.63 binary, strings + code analysis). Sharing findings here since they make the implementation case even stronger — this is genuinely a small change on the Claude Code side.

The internal data flow

Every API response from Anthropic includes these HTTP headers (per rate-limit "claim"):

| Header | Example value | What it is |
|--------|--------------|------------|
| anthropic-ratelimit-unified-5h-utilization | 0.34 | Session usage as a 0.0–1.0 float |
| anthropic-ratelimit-unified-5h-reset | 1709234567 | Unix timestamp for session reset |
| anthropic-ratelimit-unified-5h-surpassed-threshold | 0.75 | Threshold crossed |
| anthropic-ratelimit-unified-7d-utilization | 0.22 | Weekly usage float |
| anthropic-ratelimit-unified-7d-reset | 1709567890 | Weekly reset timestamp |
| anthropic-ratelimit-unified-status | allowed | Overall status |
| anthropic-ratelimit-unified-fallback | available | Fallback availability |
| anthropic-ratelimit-unified-overage-status | allowed | Overage status |
| anthropic-ratelimit-unified-overage-reset | 1709999999 | Overage reset timestamp |
| anthropic-ratelimit-unified-overage-disabled-reason | (various) | Why overage is off |
| anthropic-ratelimit-unified-representative-claim | (claim ID) | Which limit is binding |

The three claim windows are defined internally as:

MC1 = {"5h": "five_hour", "7d": "seven_day", overage: "overage"}

Already parsed into a Zod schema

Claude Code already parses these headers into a typed rate_limit_info object (internal schema em1):

{
  status: "allowed" | "allowed_warning" | "rejected",
  resetsAt?: number,          // unix timestamp
  rateLimitType?: "five_hour" | "seven_day" | "seven_day_opus" | "seven_day_sonnet" | "overage",
  utilization?: number,       // 0.0 to 1.0
  overageStatus?: "allowed" | "allowed_warning" | "rejected",
  overageResetsAt?: number,
  overageDisabledReason?: string,
  isUsingOverage?: boolean,
  surpassedThreshold?: number
}

This is emitted internally as rate_limit_event in the streaming JSON output (--output-format stream-json), but is not written to the JSONL transcript and not included in the statusLine JSON input.

The /usage command even sends a minimal throwaway API request (content: "quota") just to get fresh headers back — confirming the data is available on every single response.

The gap

The statusLine JSON currently includes:

  • model.id, model.display_name
  • workspace.current_dir, workspace.project_dir
  • cost.total_cost_usd (meaningless for subscription users)
  • context_window.used_percentage (context fill, NOT account usage)
  • vim.mode, agent.name

The rate_limit_info object is already in memory when the statusLine command runs. It just isn't passed through.

Why this matters: burn-rate analysis

For Max subscribers, the use case isn't just "show a percentage." It's velocity-aware budgeting:

  • Session is 34% used with 3h remaining → burning slow, plenty of room
  • Session is 34% used with 45min remaining → fine, almost reset anyway
  • Week is 82% used with 5 days remaining → need to throttle
  • Week is 82% used with 6 hours remaining → burn freely, it resets soon

Without the utilization + resetsAt pair exposed, users can't build this. The data exists in memory on every response — it just needs to be added to the statusLine JSON blob.

Proposed additions to statusLine JSON

Building on @dougbarlow and @arowe-aei's proposals above, here's what I'd suggest (keeping it flat and pragmatic):

{
  "rate_limit": {
    "status": "allowed",
    "session": {
      "utilization": 0.34,
      "resets_at": 1709234567
    },
    "weekly": {
      "utilization": 0.22,
      "resets_at": 1709567890
    },
    "overage": {
      "status": "allowed",
      "resets_at": null,
      "disabled_reason": null
    },
    "is_using_overage": false,
    "surpassed_threshold": null
  }
}

And separately, the same data should be available in hook event data (particularly Stop and PostToolUse) so users can build alerting, logging, and dashboards without needing the status line at all. See #29829 for that side of the request.

Current workarounds and why they're insufficient

| Approach | Problem |
|----------|---------|
| Parse JSONL transcripts | Headers aren't stored, only token counts. Local-only, can't account for web/mobile usage. |
| ccusage / Claude-Code-Usage-Monitor | Same limitation — local token sums, not server-side percentages |
| ANTHROPIC_BASE_URL reverse proxy | Works but requires running a separate TLS proxy process, self-signed certs, and NODE_TLS_REJECT_UNAUTHORIZED=0 |
| Periodic claude -p "ok" --output-format stream-json probe | Burns quota on every poll |

None of these match the accuracy or simplicity of just passing through what Claude Code already has in memory.

Astro-Han · 5 months ago

Great analysis @TickTockBent. The fact that rate_limit_info is already in memory and just needs to be piped through makes this even more frustrating.

In the meantime, I've been using claude-lens as a workaround -- it queries the OAuth usage endpoint with stale-while-revalidate caching (5min TTL, async background refresh) and shows both 5h/7d remaining percentages plus a pace delta (are you burning faster or slower than expected). ~150 lines of Bash + jq, no Node/npm required.

Still hoping this gets native support so we can retire the API polling approach entirely.

dopeamine · 5 months ago

For anyone on Windows looking for this - I built claude-usage-monitor as a cross-platform alternative.

Inspired by @Astro-Han's claude-lens which covers macOS/Linux.
Both use the OAuth API to show 5h/7d quota remaining in the statusline.

Would love for this data to be included natively in the statusline JSON though!

<img width="650" height="150" alt="Image" src="https://github.com/user-attachments/assets/273ec84a-a3c3-48f9-818a-3e94e0f0296f" />

yurukusa · 5 months ago

Here's a hook-based workaround that approximates rate limit tracking in your status line:
Approach: Use a Notification hook to capture rate limit warnings and a PostToolUse hook to count API calls, then display via statusLine.
1. Rate limit warning capture (~/.claude/hooks/rate-limit-tracker.sh):

INPUT=$(cat)
MSG=$(echo "$INPUT" | jq -r '.message // empty')
if echo "$MSG" | grep -qiE 'rate limit|usage limit|out of.*usage'; then
  echo "{\"event\":\"rate_limit\",\"time\":\"$(date -Iseconds)\",\"msg\":\"$MSG\"}" \
    >> /tmp/claude-rate-events.jsonl
fi

2. Session turn counter (~/.claude/hooks/turn-counter.sh):

STATE="/tmp/claude-session-turns"
COUNT=$(($(cat "$STATE" 2>/dev/null || echo 0) + 1))
echo "$COUNT" > "$STATE"

3. Status line script (~/.claude/status-line.sh):

TURNS=$(cat /tmp/claude-session-turns 2>/dev/null || echo 0)
LAST_WARNING=$(tail -1 /tmp/claude-rate-events.jsonl 2>/dev/null | jq -r '.time // empty' | cut -dT -f2 | cut -d+ -f1)
if [ -n "$LAST_WARNING" ]; then
  echo "⚠ Rate warn@${LAST_WARNING} | ${TURNS} turns"
else
  echo "✓ ${TURNS} turns"
fi

4. Settings (.claude/settings.json):

{
  "hooks": {
    "Notification": [{ "command": "bash ~/.claude/hooks/rate-limit-tracker.sh" }],
    "PostToolUse": [{ "command": "bash ~/.claude/hooks/turn-counter.sh" }],
    "SessionStart": [{ "command": "echo 0 > /tmp/claude-session-turns; : > /tmp/claude-rate-events.jsonl" }]
  },
  "statusLine": "bash ~/.claude/status-line.sh"
}

Limitations: This tracks tool calls and rate limit warnings, not the actual usage percentage from /usage. It's a proxy — you'll see when you're warned, but not the 91% number. True percentage tracking would require the upstream feature you're requesting.
For more granular tracking, ccusage parses JSONL session files and can give cost/token breakdowns per 5-hour window, which you could pipe into the status line.

claude[bot] contributor · 4 months ago

This issue was fixed as of version 2.1.80.

github-actions[bot] · 4 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.