Expose /usage subscription quota data in statusLine JSON payload

Status Closed — duplicate
Maintainer reply ✓ Yes — claude[bot]
Activity 15 comments · opened Feb 26, 2026 · closed Apr 26, 2026
💡 Likely answer: A maintainer (claude[bot], contributor) responded on this thread — see the highlighted reply below.

Problem

The /usage REPL command shows subscription plan quota (daily limit, remaining messages, rate limit status) for Claude Max/Pro subscribers. However, this data is not included in the JSON payload piped to the statusLine command.

This means there is no way to display subscription usage in the status line, even though Claude Code already has internal access to this data.

Current workaround

Users have to open the Claude Desktop App or run /usage interactively to check their remaining quota. This is inconvenient and — in the case of the Desktop App — can cause .claude.json corruption due to concurrent file writes from both processes (see #3847 or similar).

Requested fields in statusLine JSON

{
  "usage": {
    "daily_messages_used": 42,
    "daily_messages_limit": 100,
    "daily_remaining_percentage": 58,
    "rate_limit_reset_at": "2025-02-26T14:00:00Z",
    "plan": "max_5x"
  }
}

(Field names are suggestions — any structured representation would work.)

Why this matters

  • The statusLine feature is designed for at-a-glance session info
  • Subscription quota is the #1 thing users want to monitor continuously
  • Without it, users resort to keeping the Desktop App open alongside CLI, which causes file contention on ~/.claude.json

Environment

  • Windows 11, Claude Code CLI v2.1.59
  • Claude Max subscription
  • Using statusLine with jq filter

View original on GitHub ↗

15 Comments

pa-create-19931007 · 6 months ago

Feature request: Please expose Pro plan quota/usage data (5-hour session limit and weekly limit remaining) in Stop hook JSON payload or statusLine JSON.

Currently, the Stop hook JSON contains no fields for subscription usage data (daily_messages_used, weekly_remaining, rate_limit_reset_at, etc.), making it impossible to build hooks that automatically trigger session wrap-up logic before hitting usage limits.

Our use case: We need a Stop hook to detect when approaching the 5-hour or weekly Pro plan limit, and automatically execute a handover document generation and session state persistence before Claude Code shuts down.

Without this, the only available workaround is the undocumented https://api.anthropic.com/api/oauth/usage endpoint, which is not officially supported and could break at any time.

Requested fields (minimum viable):

  • quota.session_5h_remaining_pct (percentage remaining in current 5-hour window)
  • quota.weekly_remaining_pct (percentage remaining in current weekly window)
  • quota.session_reset_at (ISO8601 timestamp)
  • quota.weekly_reset_at (ISO8601 timestamp)

Related issues: #27829, #13585

TKMD · 6 months ago

I'm using Claude Max (20x) on Linux with a tmux-based system monitoring dashboard. I wanted to keep /usage rate limit info visible at all times alongside docker stats, nvidia-smi, and htop.

Since statusLine JSON doesn't include utilization data, I wrote a shell script that polls the undocumented OAuth usage endpoint every 60 seconds and renders the 5h/7d percentages as bars in a tmux pane:

<img width="1920" height="1080" alt="Image" src="https://github.com/user-attachments/assets/0c73446a-d28c-4dfb-ab93-9cef781026be" />

If the statusLine JSON payload included the utilization fields (five_hour, seven_day, seven_day_sonnet — matching what /usage already displays), this would be trivially solvable without hitting any extra endpoints. It would also enable other creative integrations like polybar/waybar widgets, conky displays, etc.

+1 for this feature.

BareTread · 5 months ago

Consolidation: 10+ duplicate issues requesting this exact feature

This issue captures the ask well, but it's worth highlighting how fragmented the demand has become. Here are all the open issues requesting quota/usage data in the statusLine JSON:

| Issue | Title | Filed |
|-------|-------|-------|
| #18121 | Expose rate limit/session usage data to statusLine configuration | Jan 29 |
| #22731 | Feature: Expose account usage/quota data to statusline | Feb 5 |
| #23843 | Expose rate limit / usage quota info in statusLine JSON input | Feb 7 |
| #26219 | Expose Plan Quota/Usage Data to StatusLine | Feb 16 |
| #27829 | Expose subscription quota/reset info in statusLine JSON | Feb 22 |
| #27915 | Expose rate-limit / plan quota usage in statusLine JSON input | Feb 22 |
| #28820 | Expose plan usage quota in statusLine JSON | Feb 25 |
| #28999 | Expose /usage subscription quota data in statusLine JSON payload | Feb 27 |
| #29911 | Expose rate-limit / plan quota data in statusline JSON stdin | Mar 1 |
| #30561 | Expose session/weekly token usage quota in statusLine JSON input | Mar 3 |

That's 10 independent issues from different users, all asking for the same thing: pipe the data that /usage already displays into the statusLine JSON payload.

Why this matters

The statusLine hook was a brilliant addition — it lets users build custom dashboards, waybar/polybar widgets, tmux panes, and terminal prompts. But without quota data, every user who wants usage visibility has to either:

  1. Manually run /usage (interrupts flow)
  2. Poll undocumented internal endpoints (fragile, as @TKMD demonstrated above)

The data clearly exists server-side. The /usage command already surfaces it. This is a plumbing change, not a new capability.

Proposed payload addition

{
  "quota": {
    "five_hour_used_pct": 42.5,
    "seven_day_used_pct": 18.3,
    "seven_day_sonnet_used_pct": 5.1,
    "reset_at": "2026-03-06T14:00:00Z",
    "plan": "max_20x"
  }
}

This would unblock an entire category of community tooling. Happy to help test if a preview lands.

cc @anthropics — can we get eyes on this? The volume of duplicates suggests strong community demand.

unphased · 5 months ago

Please add this. Being able to view limit usage is the only reason to customize the statusline.

MattBudz · 5 months ago

Another statusLine user here. I have a custom status line showing model, context tokens, cwd, and git branch. Plan quota (5h burst + weekly limit + reset times) is the last missing piece — I'd display it immediately if it were in the JSON payload. +1 for the proposed quota fields.

TKMD · 5 months ago

I've implemented a workaround for this using the OAuth API (/api/oauth/usage) with the anthropic-beta: oauth-2025-04-20 header. My statusline now shows:

  • 5h burst utilization + remaining time
  • 7d weekly (all models / Sonnet / Opus) + remaining time
  • Extra usage credits ($used/$limit)
  • Model name, cwd, git branch, context window %

The approach uses stale-while-revalidate caching (5min TTL, 15min error backoff) to avoid rate limits within the 5s statusline timeout.

It works but requires extracting the OAuth token from ~/.claude/.credentials.json. Native quota fields in the statusline JSON payload would be much cleaner — no external API calls, no caching layer, no auth token handling.

Mik13 · 5 months ago
I've implemented a workaround

Care to share?

GuiSim · 5 months ago

Claude cooked this setup for me
(replaced YOUR_MACOS_USERNAME with your macOS username)
Requires jq.

.claude/statusline-command.sh

#!/usr/bin/env bash
# Claude Code statusline — shows 5h/7d usage quota
# Stale-while-revalidate caching (3min TTL)

CACHE_FILE="/tmp/claude-usage-cache.json"
CACHE_MAX_AGE=180

cat > /dev/null  # consume stdin

# --- Fetch usage (background-safe) ---
fetch_usage() {
  local token
  token=$(security find-generic-password -s "Claude Code-credentials" -a "YOUR_MACOS_USERNAME" -w 2>/dev/null | jq -r '.claudeAiOauth.accessToken // empty')
  [ -z "$token" ] && return 1

  local resp
  resp=$(/usr/bin/curl -s --max-time 4 "https://api.anthropic.com/api/oauth/usage" \
    -H "Authorization: Bearer $token" \
    -H "anthropic-beta: oauth-2025-04-20" \
    -H "Accept: application/json" 2>/dev/null)

  echo "$resp" | jq -e '.five_hour' >/dev/null 2>&1 || return 1
  jq -n --argjson data "$resp" '{ts: now, data: $data}' > "$CACHE_FILE" 2>/dev/null
}

# --- Refresh if stale ---
cache_age=999999
if [ -f "$CACHE_FILE" ]; then
  cached_ts=$(jq -r '.ts // 0' "$CACHE_FILE" 2>/dev/null)
  now=$(date +%s)
  cache_age=$(( now - ${cached_ts%.*} ))
fi

if [ "$cache_age" -ge "$CACHE_MAX_AGE" ]; then
  fetch_usage &
fi

# --- Format remaining time from ISO8601 UTC timestamp ---
fmt_remaining() {
  local iso="$1"
  # Parse UTC time using Python for reliable ISO8601 handling
  local reset_epoch
  reset_epoch=$(date -u -jf "%Y-%m-%dT%H:%M:%S" "${iso%%.*}" +%s 2>/dev/null)
  [ -z "$reset_epoch" ] && return
  local now_epoch
  now_epoch=$(date +%s)
  local remaining=$(( reset_epoch - now_epoch ))
  [ "$remaining" -le 0 ] && echo "now" && return

  local days=$(( remaining / 86400 ))
  local hrs=$(( (remaining % 86400) / 3600 ))
  local mins=$(( (remaining % 3600) / 60 ))

  if [ "$days" -gt 0 ]; then
    echo "${days}d${hrs}h"
  elif [ "$hrs" -gt 0 ]; then
    echo "${hrs}h${mins}m"
  else
    echo "${mins}m"
  fi
}

# --- Build output from cache ---
if [ -f "$CACHE_FILE" ]; then
  five_hr=$(jq -r '.data.five_hour.utilization // empty' "$CACHE_FILE" 2>/dev/null)
  five_reset=$(jq -r '.data.five_hour.resets_at // empty' "$CACHE_FILE" 2>/dev/null)
  seven_day=$(jq -r '.data.seven_day.utilization // empty' "$CACHE_FILE" 2>/dev/null)
  seven_reset=$(jq -r '.data.seven_day.resets_at // empty' "$CACHE_FILE" 2>/dev/null)

  parts=""

  if [ -n "$five_hr" ]; then
    five_remaining=$(fmt_remaining "$five_reset")
    parts="5h: ${five_hr%.*}%"
    [ -n "$five_remaining" ] && parts="$parts (${five_remaining})"
  fi

  if [ -n "$seven_day" ]; then
    seven_remaining=$(fmt_remaining "$seven_reset")
    [ -n "$parts" ] && parts="$parts | "
    parts="${parts}7d: ${seven_day%.*}%"
    [ -n "$seven_remaining" ] && parts="$parts (${seven_remaining})"
  fi

  printf "%s" "$parts"
else
  printf "loading..."
fi

And of course you add to your ~/.claude/settings.json

 "statusLine": {
    "type": "command",
    "command": "bash /Users/YOUR_MACOS_USERNAME/.claude/statusline-command.sh"
  },
Astro-Han · 5 months ago

I built claude-lens to solve this -- similar approach to @GuiSim's script (OAuth API + background refresh + file cache), but with a few extras:

  • Pace tracking: shows whether you're burning faster or slower than expected given the time remaining in the window (+17% = headroom, -12% = slow down)
  • Reset countdown for both 5h and 7d windows
  • Conditional display (extra usage only shows when 5h >= 80%)
  • Stale-while-revalidate with 5min TTL, async background refresh so the statusline never blocks

~150 lines of Bash + jq, two commands to install:

curl -o ~/.claude/statusline.sh https://raw.githubusercontent.com/Astro-Han/claude-lens/main/claude-lens.sh
claude config set statusLine.command ~/.claude/statusline.sh

Would love to see this data natively in the JSON payload though -- the OAuth API workaround adds latency and complexity that shouldn't be necessary.

BareTread · 5 months ago

Update (2026-03-19): Community workaround now available — @Astro-Han's claude-lens (~150 lines Bash + jq) solves this via the OAuth usage API with async background refresh, stale-while-revalidate caching (5min TTL), pace tracking, and Linux/macOS support.

Two-command install:

curl -o ~/.claude/statusline.sh https://raw.githubusercontent.com/Astro-Han/claude-lens/main/claude-lens.sh
claude config set statusLine.command ~/.claude/statusline.sh

Native support is still the right fix — this shouldn't require polling an undocumented endpoint and doing your own auth token management — but claude-lens is a solid interim solution while this waits for prioritization.

Astro-Han · 5 months ago

@BareTread wow, this consolidated tracking is incredible, must have taken a while to dig up all 10 issues. And thanks for the claude-lens shoutout with full install commands! Really means a lot. Let me know if anything breaks or if you have ideas for improvements.

joallard · 5 months ago

Shipped in 2.1.80 as rate_limits, thank you so much for this!

My status line now reads:

$0.00 | ◑ 59% → 5am (4h34m) | ◔ 17% → fri 12am (6d23h) | 0% ctx

Significant UX upgrade.

yurukusa · 5 months ago

A PostToolUse hook can maintain approximate usage tracking that a statusLine script can read:

STATE="/tmp/cc-usage-state.json"
if [ ! -f "$STATE" ]; then
    echo '{"calls": 0, "chars": 0, "start": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'", "errors": 0}' > "$STATE"
fi
INPUT=$(cat)
OUTPUT_LEN=$(echo "$INPUT" | jq -r '.tool_output // empty' | wc -c)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty')
jq --argjson c 1 --argjson o $OUTPUT_LEN '
    .calls += $c |
    .chars += $o |
    .last_tool = "'$TOOL'" |
    .updated = "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
' "$STATE" > "${STATE}.tmp" && mv "${STATE}.tmp" "$STATE"
exit 0

Then in your statusLine script, read the tracker:

INPUT=$(cat)
USAGE="/tmp/cc-usage-state.json"
if [ -f "$USAGE" ]; then
    CALLS=$(jq '.calls' "$USAGE" 2>/dev/null || echo 0)
    CHARS=$(jq '.chars' "$USAGE" 2>/dev/null || echo 0)
    CHARS_K=$((CHARS / 1000))
    TOKENS_K=$((CHARS / 4000))
    CTX_USED=$(echo "$INPUT" | jq -r '.context_window.used // 0')
    CTX_MAX=$(echo "$INPUT" | jq -r '.context_window.max // 200000')
    CTX_PCT=$((CTX_USED * 100 / CTX_MAX))
    echo "📊 ${CALLS} calls | ~${TOKENS_K}K tok | ctx: ${CTX_PCT}%"
else
    echo "📊 starting..."
fi

Add to settings:

{
  "statusLine": {
    "command": "bash ~/.claude/statusline.sh"
  }
}

This gives you a live usage display: tool call count, approximate token consumption, and context window percentage — all updated in real-time via the PostToolUse hook.

claude[bot] contributor · 4 months ago

This is a duplicate of #18121, which was fixed as of version 2.1.80.

github-actions[bot] · 3 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.