Skip to content

Instantly share code, notes, and snippets.

@lexfrei
Last active January 25, 2026 15:38
Show Gist options
  • Select an option

  • Save lexfrei/b70aaee919bdd7164f2e3027dc8c98de to your computer and use it in GitHub Desktop.

Select an option

Save lexfrei/b70aaee919bdd7164f2e3027dc8c98de to your computer and use it in GitHub Desktop.
Claude Code statusline with real usage limits from Anthropic API

Claude Code Statusline with Real Usage Limits

Enhanced statusline for Claude Code that shows real quota usage from Anthropic API instead of estimates.

Features

  • πŸŸ’πŸŸ‘πŸŸ πŸ”΄ Rate indicators β€” compares usage% with elapsed time%
  • 5-hour window β€” always shown with time remaining
  • 7-day window β€” shown only when β‰₯70% used
  • 60-second cache β€” avoids excessive API calls
  • Timezone-aware β€” works correctly in any timezone

Example Output

πŸ€– Opus 4.5 | πŸ’° $2.53 session / $46.11 today | πŸ”₯ $7.79/hr | 🟠 7d: 73% (2d 5h) | 🟒 5h: 30% (3h 32m)

Statusline Blocks Explained

Block Meaning
πŸ€– Opus 4.5 Current model being used
πŸ’° $2.53 session / $46.11 today Estimated cost for current session and total today (based on token prices)
πŸ”₯ $7.79/hr Current burn rate β€” how fast you're spending
🟠 7d: 73% (2d 5h) 7-day quota usage with rate indicator and time until reset (only shown β‰₯70%)
🟒 5h: 30% (3h 32m) 5-hour quota usage with rate indicator and time until reset

Rate Indicator Logic

Indicator Meaning
🟒 On track or under (usage ≀ time elapsed)
🟑 Slightly ahead (1-5% over)
🟠 Ahead (6-15% over)
πŸ”΄ Way ahead, will likely hit limit (>15% over)

The rate indicator compares your usage percentage with time elapsed percentage in the current window. For example, if 50% of the 5-hour window has passed and you've used 45% of quota β€” you're on track (🟒). If you've used 70% β€” you're way ahead (πŸ”΄).

Installation

  1. Save statusline-usage.sh to ~/.claude/hooks/:
mkdir -p ~/.claude/hooks
# Download from this gist
chmod +x ~/.claude/hooks/statusline-usage.sh
  1. Add to ~/.claude/settings.json:
{
  "statusLine": {
    "type": "command",
    "command": "$HOME/.claude/hooks/statusline-usage.sh",
    "padding": 0
  }
}
  1. Restart Claude Code session.

Dependencies

  • ccusage β€” install via brew install ccusage (other options)
  • jq β€” JSON parsing (brew install jq)
  • curl β€” API requests (pre-installed on macOS)
  • macOS Keychain with Claude Code credentials

How It Works

  1. Receives JSON input from Claude Code statusline hook
  2. Passes it through ccusage statusline for base info (model, costs, context)
  3. Fetches real usage data from https://api.anthropic.com/api/oauth/usage
  4. Calculates rate indicators by comparing usage% with time elapsed%
  5. Caches API response for 60 seconds

Credits

License

BSD-3-Clause

#!/bin/bash
# Fetch real usage limits from Anthropic API and combine with ccusage statusline
set -euo pipefail
export PATH="/opt/homebrew/bin:$PATH"
# Cache settings
CACHE_FILE="/tmp/claude-usage-cache.json"
CACHE_TTL=60 # seconds
# Get cached or fresh usage data
get_usage() {
local now
now=$(date +%s)
# Check cache
if [[ -f "$CACHE_FILE" ]]; then
local cache_time
cache_time=$(stat -f %m "$CACHE_FILE" 2>/dev/null || echo 0)
if (( now - cache_time < CACHE_TTL )); then
cat "$CACHE_FILE"
return
fi
fi
# Get credentials from Keychain
local creds token
creds=$(security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null) || return 1
token=$(echo "$creds" | jq -r '.claudeAiOauth.accessToken // empty' 2>/dev/null) || return 1
if [[ -z "$token" ]]; then
return 1
fi
# Fetch usage from API
local response
response=$(curl --silent --max-time 5 \
--header "Authorization: Bearer $token" \
--header "anthropic-beta: oauth-2025-04-20" \
"https://api.anthropic.com/api/oauth/usage" 2>/dev/null) || return 1
# Cache response
echo "$response" > "$CACHE_FILE"
echo "$response"
}
# Calculate time remaining (in minutes) from ISO timestamp (UTC)
time_remaining_mins() {
local reset_at=$1
local now reset_ts diff
now=$(date +%s)
# Parse ISO timestamp as UTC
# Remove microseconds and timezone suffix, parse in UTC
local ts_clean="${reset_at%%.*}"
ts_clean="${ts_clean//T/ }" # Replace T with space
reset_ts=$(TZ=UTC date -j -f "%Y-%m-%d %H:%M:%S" "$ts_clean" +%s 2>/dev/null) || return 1
diff=$((reset_ts - now))
echo $(( diff / 60 ))
}
# Format minutes to human readable
format_time() {
local mins=$1
if (( mins <= 0 )); then
echo "now"
return
fi
local days hours minutes
days=$((mins / 1440))
hours=$(((mins % 1440) / 60))
minutes=$((mins % 60))
if (( days > 0 )); then
echo "${days}d ${hours}h"
elif (( hours > 0 )); then
echo "${hours}h ${minutes}m"
else
echo "${minutes}m"
fi
}
# Get rate indicator based on usage% vs time elapsed%
# Usage: rate_indicator <usage%> <time_remaining_mins> <total_window_mins>
rate_indicator() {
local usage=$1
local remaining_mins=$2
local total_mins=$3
# Calculate time elapsed percentage
local elapsed_mins=$((total_mins - remaining_mins))
if (( elapsed_mins < 0 )); then elapsed_mins=0; fi
local time_pct
if (( total_mins > 0 )); then
time_pct=$((elapsed_mins * 100 / total_mins))
else
time_pct=0
fi
# Compare usage% with time%
local diff=$((usage - time_pct))
if (( diff <= 0 )); then
echo "🟒" # On track or under
elif (( diff <= 5 )); then
echo "🟑" # Slightly ahead
elif (( diff <= 15 )); then
echo "🟠" # Ahead
else
echo "πŸ”΄" # Way ahead, will likely hit limit
fi
}
# Main - receives JSON from Claude Code via stdin
main() {
# Read stdin (Claude Code passes JSON)
local input
input=$(cat)
# Get base statusline from ccusage (pass through the input)
local base
base=$(echo "$input" | ccusage statusline --offline --visual-burn-rate off 2>/dev/null) || base=""
# Remove fields not useful on subscription (ccusage doesn't have options for these)
# - (Xh Ym left): we show real time from API
# - / $X.XX block: not relevant for subscription
# - 🧠 context: shows cumulative tokens, not actual context usage (bug in ccusage)
base=$(echo "$base" | sed -E 's/ *\([0-9]+h [0-9]+m left\)//g; s| */ *\$[0-9]+\.[0-9]+ block||g; s/\| *🧠 [^|]*//g')
# Get usage data from API
local usage five_hour seven_day
usage=$(get_usage 2>/dev/null) || usage=""
if [[ -n "$usage" ]]; then
five_hour=$(echo "$usage" | jq -r '.five_hour.utilization // empty' 2>/dev/null)
five_hour_resets=$(echo "$usage" | jq -r '.five_hour.resets_at // empty' 2>/dev/null)
seven_day=$(echo "$usage" | jq -r '.seven_day.utilization // empty' 2>/dev/null)
seven_day_resets=$(echo "$usage" | jq -r '.seven_day.resets_at // empty' 2>/dev/null)
local quota_info=""
# 7d only if >= 70%
if [[ -n "$seven_day" ]]; then
local seven_day_int
seven_day_int=$(printf "%.0f" "$seven_day")
if (( seven_day_int >= 70 )); then
local seven_day_remaining_mins seven_day_indicator seven_day_time_str
seven_day_remaining_mins=$(time_remaining_mins "$seven_day_resets" 2>/dev/null) || seven_day_remaining_mins=0
seven_day_indicator=$(rate_indicator "$seven_day_int" "$seven_day_remaining_mins" 10080) # 7d = 10080 mins
seven_day_time_str=$(format_time "$seven_day_remaining_mins")
quota_info+="${seven_day_indicator} 7d: ${seven_day_int}% (${seven_day_time_str})"
fi
fi
# 5h always shown
if [[ -n "$five_hour" ]]; then
local five_hour_int five_hour_remaining_mins five_hour_indicator five_hour_time_str
five_hour_int=$(printf "%.0f" "$five_hour")
five_hour_remaining_mins=$(time_remaining_mins "$five_hour_resets" 2>/dev/null) || five_hour_remaining_mins=0
five_hour_indicator=$(rate_indicator "$five_hour_int" "$five_hour_remaining_mins" 300) # 5h = 300 mins
five_hour_time_str=$(format_time "$five_hour_remaining_mins")
[[ -n "$quota_info" ]] && quota_info+=" | "
quota_info+="${five_hour_indicator} 5h: ${five_hour_int}% (${five_hour_time_str})"
fi
if [[ -n "$quota_info" ]]; then
echo "${base} | ${quota_info}"
else
echo "$base"
fi
else
echo "$base"
fi
}
main
@kvaps
Copy link

kvaps commented Jan 20, 2026

Thanks for the awesome script! πŸ™Œ

I forked it to remove the bunx dependency since I have ccusage installed via homebrew:
https://gist.github.com/kvaps/84fa5963df1bff9cec65b57afd54e1e4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment