A sh script for Claude Code's statusLine hook that shows, in order:
██░░░░░░░░ 22% session limit | ████░░░░░░ 42% weekly limit | Opus 5 (High) | 94.2k tokens
- Session limit — 5-hour rolling usage bar (
rate_limits.five_hour.used_percentage) - Weekly limit — 7-day rolling usage bar (
rate_limits.seven_day.used_percentage) - Model + effort — e.g.
Opus 5 (High) - Tokens used — current conversation's token usage, colorized once it gets large:
- default color: ≤ 200k tokens
- yellow: > 200k tokens
- orange: > 300k tokens
Both usage bars only appear once Claude Code's backend starts reporting them (after your first API response in a session, and only for Claude.ai subscription plans) — the script degrades gracefully and just omits a segment if the field isn't present.
jq(install viabrew install jqon macOS)- A terminal font with full block-character coverage (
█U+2588,░U+2591) — most modern monospace / Nerd Fonts work. If the bars render as broken boxes, your terminal font is missing these glyphs; switch fonts or swap the characters inmake_bar()for plain ASCII (#/-).
-
Save the script below as
~/.claude/statusline-command.shand make it executable:chmod +x ~/.claude/statusline-command.sh -
Point Claude Code at it in
~/.claude/settings.json:{ "statusLine": { "type": "command", "command": "~/.claude/statusline-command.sh" } } -
Restart Claude Code (or start a new session) — the status line updates automatically as the conversation progresses.
#!/bin/sh
# Claude Code statusLine
# Shows: session-limit bar | weekly-limit bar | model (effort) | used tokens
input=$(cat)
model=$(echo "$input" | jq -r '.model.display_name // ""')
# Reasoning effort level (low/medium/high). Only emitted for models that
# support effort levels, so treat it as optional.
effort=$(echo "$input" | jq -r '.effort.level // empty')
if [ -n "$effort" ]; then
effort_display=$(printf '%s' "$effort" | awk '{print toupper(substr($0,1,1)) substr($0,2)}')
model="${model} (${effort_display})"
fi
# Compute used tokens directly from current_usage fields so the count matches
# what /context reports (e.g. 19.8k) rather than back-calculating from the
# already-rounded used_percentage (which would give 20.0k for 10%).
# current_usage is null before the first API call, fall back to empty in that case.
used_tok=$(echo "$input" | jq -r '
.context_window.current_usage
| if . == null then empty
else (.input_tokens // 0)
+ (.cache_creation_input_tokens // 0)
+ (.cache_read_input_tokens // 0)
end
')
# Format a raw number with k suffix when >= 1000, always one decimal place
fmt_k1() {
printf '%s' "$1" | awk '{
n = int($1)
if (n >= 1000) {
printf "%.1fk", n / 1000
} else {
printf "%d", n
}
}'
}
# Build a 10-block progress bar from a percentage value (0-100).
# Filled blocks: █ Empty blocks: ░
make_bar() {
pct="$1"
filled=$(printf '%s' "$pct" | awk '{print int($1 / 10 + 0.5)}')
empty=$((10 - filled))
bar=""
i=0
while [ "$i" -lt "$filled" ]; do
bar="${bar}█"
i=$((i + 1))
done
i=0
while [ "$i" -lt "$empty" ]; do
bar="${bar}░"
i=$((i + 1))
done
printf '%s' "$bar"
}
# Colorize the token count once it gets large: yellow above 200k, orange
# above 300k, default color below that.
colorize_tokens() {
text="$1"
tok="$2"
if [ "$tok" -gt 300000 ] 2>/dev/null; then
printf '\033[38;5;208m%s\033[0m' "$text" # orange
elif [ "$tok" -gt 200000 ] 2>/dev/null; then
printf '\033[38;5;220m%s\033[0m' "$text" # yellow
else
printf '%s' "$text"
fi
}
# Plan usage: rate_limits.five_hour.used_percentage / rate_limits.seven_day.used_percentage
# Only present for Claude.ai subscribers after the first API response.
five_hr_pct=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
seven_day_pct=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
# Assemble
if [ -n "$used_tok" ]; then
used_display=$(colorize_tokens "$(fmt_k1 "$used_tok") tokens" "$used_tok")
out=$(printf '%s | %s' "$model" "$used_display")
else
out=$(printf '%s' "$model")
fi
# Prepend weekly-limit bar when available
if [ -n "$seven_day_pct" ]; then
weekly_pct_display=$(printf "%.0f" "$seven_day_pct")
weekly_bar=$(make_bar "$seven_day_pct")
out="${weekly_bar} ${weekly_pct_display}% weekly limit | ${out}"
fi
# Prepend session-limit bar when available
if [ -n "$five_hr_pct" ]; then
limit_pct_display=$(printf "%.0f" "$five_hr_pct")
limit_bar=$(make_bar "$five_hr_pct")
out="${limit_bar} ${limit_pct_display}% session limit | ${out}"
fi
printf '%s' "$out"- Change token color thresholds: edit the
300000/200000values incolorize_tokens(). - Change bar width: edit the
10inmake_bar()'spct / 10calculation (and note the fixed-width loop assumes 10 segments). - Drop the weekly bar: delete the "Prepend weekly-limit bar" block.
- Font issues (bars render as broken boxes): swap
█/░for ASCII equivalents like#/-inmake_bar().