Claude Code Usage Monitor: Build a 5-Hour and 7-Day Limit Status Line from rate_limits (Script, Tested)
Claude Code passes rate_limits to your status line script: percent used and reset time for the 5-hour and 7-day windows. We wrote a short bash script, tested it on six mock inputs, and ran ccusage 20.0.48 on local session data to compare what each shows.

Short answer: every time Claude Code refreshes the status line it pipes a JSON blob to your script on stdin, and its rate_limits field is the official limit data: percent used for the 5-hour window and the 7-day window, plus their reset times. About 30 lines of script turn that into 5h 24% (1h23m) | 7d 41% (2d7h). On November 10, 2026 we tested the script on six mock inputs and ran the community tool ccusage 20.0.48 on local session data to compare what each one shows. One limit up front: we have no signed-in subscription account, so we never saw real rate_limits values; the script was tested on mock data built from the documented JSON structure.
What rate_limits is in the official docs
Everything here comes from the official status line docs (fetched Nov 10, 2026):
| Field | Meaning |
|---|---|
rate_limits.five_hour.used_percentage / rate_limits.seven_day.used_percentage | Percent of the 5-hour or 7-day window used, 0 to 100 |
rate_limits.five_hour.resets_at / rate_limits.seven_day.resets_at | When that window resets, Unix epoch seconds |
rate_limits.spend_limit.* | Only behind a Claude apps gateway that sets a spend limit; this script does not handle it |
Things to know first (the docs’ meaning, not a verbatim quote):
rate_limitsappears only for claude.ai Pro, Max and Ultra subscribers (or behind a gateway with a spend limit). API-key users do not get it.- Even for subscribers it shows up only after the first API response in a session, and each window can be missing on its own. The script must handle “absent”.
- Once a window’s
resets_atpasses, Claude Code drops that window; the script also re-runs when a window reaches its reset time. - The status line runs locally and uses no API tokens. The script must exit 0 and print something, or the status line goes blank.
- The status line refreshes on a new assistant message, when
/compactfinishes, when the permission mode changes, when vim mode toggles and when thecommandchanges; you can addrefreshInterval(seconds, minimum 1) for a timer.
The script (tested)
Needs jq. Save it as ~/.claude/statusline.sh:
#!/bin/bash
# 5-hour / 7-day limit status line (reads the official rate_limits field)
input=$(cat)
MODEL=$(echo "$input" | jq -r '.model.display_name')
now=$(date +%s)
left() { # arg: resets_at (epoch seconds) -> prints time left, e.g. 1h23m
local s=$(( $1 - now ))
[ "$s" -le 0 ] && return
if [ "$s" -ge 86400 ]; then printf '%dd%dh' $((s/86400)) $(((s%86400)/3600))
else printf '%dh%02dm' $((s/3600)) $(((s%3600)/60)); fi
}
color() { # arg: percent -> ANSI color
local p=${1%.*}
if [ "$p" -ge 90 ]; then printf '\033[31m'
elif [ "$p" -ge 70 ]; then printf '\033[33m'
else printf '\033[32m'; fi
}
RESET='\033[0m'
OUT=""
for w in five_hour seven_day; do
pct=$(echo "$input" | jq -r ".rate_limits.$w.used_percentage // empty")
rs=$(echo "$input" | jq -r ".rate_limits.$w.resets_at // empty")
[ -z "$pct" ] && continue
[ "$w" = five_hour ] && label=5h || label=7d
seg="$(color "$pct")${label} $(printf '%.0f' "$pct")%${RESET}"
[ -n "$rs" ] && l=$(left "$rs") && [ -n "$l" ] && seg="$seg ($l)"
OUT="${OUT:+$OUT | }$seg"
done
if [ -n "$OUT" ]; then echo -e "[$MODEL] $OUT"; else echo "[$MODEL]"; fi
Then chmod +x ~/.claude/statusline.sh and add this to ~/.claude/settings.json:
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh"
}
}
Claude Code reloads settings automatically and the line appears. To keep the countdown moving while idle, add "refreshInterval": 60 (re-run every 60 seconds). The docs also warn that the status line stays blank until you accept the workspace trust dialog, and that on Windows paths need forward slashes or a PowerShell version; see the Windows section of the docs.
Color thresholds: green under 70%, yellow from 70% to 89%, red from 90% (the same thresholds as the official multi-line example). Percentages are rounded with printf '%.0f', so 23.5 shows as 24%.
What we tested
We built six inputs by hand from the documented JSON structure and piped them into the script (resets_at is the current time plus an offset). Output with color codes stripped:
5h 23.5%, 7d 41.2% → [Opus] 5h 24% (1h23m) | 7d 41% (2d7h)
5h 93%, 7d 72% → [Opus] 5h 93% (0h10m) | 7d 72% (1d1h)
no rate_limits → [Opus]
seven_day only, 8% → [Sonnet] 7d 8% (3d11h)
5h resets_at already past → [Opus] 5h 50%
spend_limit only (gateway) → [Opus]
We also looked at the color codes with cat -v: 93% is red, 72% yellow, the rest green. Not tested: real rate_limits values from a subscription account, and how Claude Code renders the script live (we piped JSON in; we did not mount the status line in an interactive session).
How it differs from /usage and ccusage
| Method | Where the data comes from | What you see |
|---|---|---|
| Status line + rate_limits (this post) | JSON Claude Code passes to the script, official field | Percent used and reset time for the 5-hour and 7-day windows |
/usage command | Official command; the error reference says it shows your plan’s windows and when they reset | Same plan windows, but you open it by hand |
| ccusage (community tool) | Local session files; its npm description is “Analyze coding (agent) CLI token usage and costs from local data” | Token counts and estimated cost by day, week, month and session |
| ccstatusline (community tool) | Named in the official status line docs’ tips; npm description “A customizable status line formatter for Claude Code CLI” | Ready-made status line formatting; we did not test it |
We did test ccusage: npx ccusage@latest --version printed ccusage 20.0.48. On a test directory containing only mock sessions, the daily command listed input, output and cache tokens and a Cost (USD) column by date, and blocks listed one active “session block” with time elapsed and time remaining plus a projection at the current rate. It reads session files under local ~/.claude, so it shows tokens and estimated cost recorded on your machine, not what percentage of your server-side 5-hour and 7-day windows you have used. The “time remaining” in blocks is its own inference from local records; we did not compare it with a real account, so we do not know how far it is from the official reset time. The docs also say cost.total_cost_usd is estimated client-side at list price and may differ from your bill.
So the split is: for “how close am I to the limit”, use the official rate_limits; for “how many tokens did I burn this week”, use a local tool such as ccusage. Do not mix the two numbers. For how the limits work and how Pro differs from Max, see Claude usage limits explained.
FAQ
5h and 7d do not show up
First: are you a subscriber? With an API key rate_limits never appears. Second: the session may not have had its first API response yet. Then follow the docs’ checks: is the script executable, does it print to stdout, does claude --debug show script errors.
Does the status line use my quota?
The docs say it runs locally and uses no API tokens.
I want more fields
The docs list them all, for example context window usage context_window.used_percentage, cost cost.total_cost_usd, the current model and git branch. Edit the jq lines in the script.
Related
Best Claude Code mods · Where settings.json lives · Claude Code error list