A ready-to-use prompt for Claude Code that sets up a live terminal statusline: rate-limit progress bars, session tokens, and an all-time counter.
Add a custom status line to my Claude Code setup. Here is the script — save it as `~/.claude/statusline.sh`, make it executable (`chmod +x`), and register it in `~/.claude/settings.json` as:
```json
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh"
}
```
The script shows: model | current dir | 5h and 7d rate-limit progress bars (green <50%, yellow 50–79%, red ≥80%) with a dynamic countdown to the 5h limit reset | tokens used by the current session | all-time token total (Σ).
The all-time total works by incrementally summing token usage from all local session transcripts (`~/.claude/projects/**/*.jsonl`) into a cache file (`~/.claude/.statusline-token-cache`); cache entries survive transcript cleanup, so the total keeps accumulating. An optional baseline file (`~/.claude/.statusline-token-baseline`, plain number of tokens) is added on top to cover account history older than local transcript retention — calibrate it once so the displayed total matches the account's "Total tokens" figure.
Note: the script uses macOS BSD stat (`/usr/bin/stat -f '%m:%z %N'`). If this machine is Linux, replace both stat calls with GNU stat: `stat -c '%Y:%s %n'` for the list and `stat -c '%Y:%s'` for a single file. Verify the script works by piping a sample status-line JSON payload into it.
Here is the script:
```bash
#!/bin/bash
# Claude Code status line: model, cwd, and live rate-limit usage (5h / 7d windows) with progress bars
input=$(cat)
model=$(echo "$input" | jq -r '.model.display_name // empty')
dir=$(basename "$(echo "$input" | jq -r '.workspace.current_dir // empty')")
five_pct=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
seven_pct=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
five_reset=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty')
transcript=$(echo "$input" | jq -r '.transcript_path // empty')
GREEN=$'\033[32m'
YELLOW=$'\033[33m'
RED=$'\033[31m'
RESET=$'\033[0m'
# bar <percentage> — renders e.g. ████░░░░░░ 42%, colored green <50%, yellow <80%, red >=80%
bar() {
local pct=${1%.*}
local width=10
local filled=$(( pct * width / 100 ))
[ "$filled" -gt "$width" ] && filled=$width
local empty=$(( width - filled ))
local color=$GREEN
if [ "$pct" -ge 80 ]; then color=$RED
elif [ "$pct" -ge 50 ]; then color=$YELLOW
fi
local b=""
for ((i=0; i<filled; i++)); do b+="█"; done
for ((i=0; i<empty; i++)); do b+="░"; done
echo "${color}${b} ${pct}%${RESET}"
}
# all-time tokens: sum usage across every local session transcript, incrementally cached.
# Cache format: path<TAB>mtime:size<TAB>tokens. Entries for deleted transcripts are kept,
# so the total keeps accumulating even after old transcripts are cleaned up.
token_cache="$HOME/.claude/.statusline-token-cache"
touch "$token_cache"
sum_file_tokens() {
jq -Rn '[inputs | fromjson? | .message.usage? // empty
| (.input_tokens // 0) + (.output_tokens // 0)
+ (.cache_creation_input_tokens // 0) + (.cache_read_input_tokens // 0)]
| add // 0' "$1" 2>/dev/null
}
statlist=$(find "$HOME/.claude/projects" -type f -name '*.jsonl' -exec /usr/bin/stat -f '%m:%z %N' {} + 2>/dev/null)
# transcripts that are new or changed since last cached
to_parse=$(printf '%s\n' "$statlist" | awk '
FILENAME != "-" { split($0, a, "\t"); ckey[a[1]] = a[2]; next }
NF { key = $1; path = substr($0, length(key) + 2); if (ckey[path] != key) print path }
' "$token_cache" -)
if [ -n "$to_parse" ]; then
# drop stale entries for files being re-parsed, then append fresh counts one by one
awk -F'\t' 'NR==FNR { skip[$0]=1; next } !($1 in skip)' \
<(printf '%s\n' "$to_parse") "$token_cache" > "$token_cache.tmp" \
&& mv "$token_cache.tmp" "$token_cache"
while IFS= read -r f; do
[ -f "$f" ] || continue
k=$(/usr/bin/stat -f '%m:%z' "$f" 2>/dev/null) || continue
t=$(sum_file_tokens "$f")
printf '%s\t%s\t%s\n' "$f" "$k" "${t:-0}" >> "$token_cache"
done <<< "$to_parse"
fi
fmt_tok() {
awk -v t="$1" 'BEGIN {
if (t >= 1000000000) printf "%.2fB", t/1000000000;
else if (t >= 1000000) printf "%.1fM", t/1000000;
else if (t >= 1000) printf "%.1fk", t/1000;
else printf "%d", t
}'
}
# tokens eaten by the current session (its transcript is already in the cache)
session_tokens=""
if [ -n "$transcript" ]; then
session_raw=$(awk -F'\t' -v p="$transcript" '$1 == p { print $3 }' "$token_cache")
[ -n "$session_raw" ] && [ "$session_raw" -gt 0 ] 2>/dev/null && session_tokens=$(fmt_tok "$session_raw")
fi
# all-time total = locally summed transcripts + baseline covering history that predates
# local transcript retention (calibrated to the account's "Total tokens" figure).
# Recalibrate anytime: echo <tokens-to-add> > ~/.claude/.statusline-token-baseline
baseline_file="$HOME/.claude/.statusline-token-baseline"
baseline=0
if [ -f "$baseline_file" ]; then
baseline=$(tr -cd '0-9' < "$baseline_file")
baseline=${baseline:-0}
fi
total_raw=$(awk -F'\t' -v b="$baseline" '{ s += $3 } END { printf "%.0f", s + b }' "$token_cache")
total_tokens=""
[ "$total_raw" -gt 0 ] 2>/dev/null && total_tokens=$(fmt_tok "$total_raw")
out="$model | $dir"
if [ -n "$five_pct" ]; then
reset_str=""
if [ -n "$five_reset" ]; then
now=$(/bin/date +%s)
remaining=$(( ${five_reset%.*} - now ))
if [ "$remaining" -gt 0 ]; then
h=$(( remaining / 3600 ))
m=$(( (remaining % 3600) / 60 ))
if [ "$h" -gt 0 ]; then
reset_str=" (resets in ${h}h ${m}m)"
else
reset_str=" (resets in ${m}m)"
fi
fi
fi
out="$out | 5h $(bar "$five_pct")${reset_str}"
fi
if [ -n "$seven_pct" ]; then
out="$out | 7d $(bar "$seven_pct")"
fi
if [ -n "$session_tokens" ]; then
out="$out | sesja ${session_tokens}"
fi
if [ -n "$total_tokens" ]; then
out="$out | Σ ${total_tokens} tok"
fi
echo "$out"
```