#!/bin/sh # Claude Code statusLine script # Format: user@host /path/base | Model ·effort | ctx:N% | 5h:N%→proj% 7d:N%→proj% # # The arrow/projection for 5h and 7d rate limits is a "quota pacer": # - current usage % → projected final usage % (based on current burn rate) # - color reflects projected exhaustion risk: # green = projected ≤ 80% (safe) # yellow = projected 80–100% (warning) # red = projected > 100% (will exhaust before reset) # - no projection shown until ≥5% of the window has elapsed (avoids noise) # # The effort meter shows the current reasoning effort level (low/med/high/max/auto). # Source priority: $CLAUDE_CODE_EFFORT_LEVEL env var > .effortLevel in # ~/.claude/settings.json. Omitted if neither is set. Note: /effort max does # not persist to settings.json, so it will only appear if the env var is set. input=$(cat) user=$(whoami) host=$(hostname -s) dir=$(echo "$input" | jq -r '.workspace.current_dir // .cwd // "?"') base=$(basename "$dir") parent=$(dirname "$dir") if [ "$parent" = "/" ]; then parent_prefix="/" else parent_prefix="$parent/" fi model=$(echo "$input" | jq -r '.model.display_name // "Claude"' | sed -E 's/\([^)]*1M[^)]*\)/(1M)/') ctx_used=$(echo "$input" | jq -r '.context_window.used_percentage // empty') five_used=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty') five_reset=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty') week_used=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty') week_reset=$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at // empty') now=$(date +%s) # Compute a pacer fragment: "label:NN%→MM%" with the arrow+projection colored # by risk. Prints only the label+current if not enough data to project. # If unit="m", appends " (Nm)" (minutes until reset) in dim gray. # If unit="d", appends " (N.Nd)" (days until reset, one decimal) in dim gray. # If unit="" (or anything else), no time suffix. # # Args: label, used%, resets_at_epoch, window_seconds, unit ("m"|"d"|"") pacer() { label="$1" u="$2" reset="$3" window="$4" unit="$5" if [ -z "$u" ]; then return fi if [ -z "$reset" ] || [ "$reset" = "null" ]; then printf " %s:%.0f%%" "$label" "$u" return fi awk -v label="$label" -v u="$u" -v reset="$reset" -v window="$window" -v now="$now" -v unit="$unit" 'BEGIN { start = reset - window elapsed = now - start if (elapsed < 1) elapsed = 1 elapsed_pct = (elapsed / window) * 100 time_suffix = "" if (unit == "m") { mins_left = int((reset - now) / 60) if (mins_left < 0) mins_left = 0 time_suffix = sprintf(" \033[0;90m(%dm)\033[0m", mins_left) } else if (unit == "d") { days_left = (reset - now) / 86400 if (days_left < 0) days_left = 0 time_suffix = sprintf(" \033[0;90m(%.1fd)\033[0m", days_left) } # Not enough data yet: show current only. # 5% for short windows (5h → 15min blackout); 1% for the 7d window # (drops blackout from 8.4h to 1.7h while keeping early projections sane). threshold = (unit == "d") ? 1 : 5 if (elapsed_pct < threshold) { printf " %s:%.0f%%%s", label, u, time_suffix exit } # Burn rate per % of elapsed time, projected to end of window burn = u / elapsed_pct projected = u + (burn * (100 - elapsed_pct)) if (projected > 100) { color = "0;31" # red — will exhaust } else if (projected > 80) { color = "0;33" # yellow — warning } else { color = "0;32" # green — safe } printf " %s:%.0f%%\033[%sm→%.0f%%\033[0m%s", label, u, color, projected, time_suffix }' } # Effort level: env var wins, then settings.json, otherwise omit. effort="" if [ -n "$CLAUDE_CODE_EFFORT_LEVEL" ]; then effort="$CLAUDE_CODE_EFFORT_LEVEL" elif [ -f "$HOME/.claude/settings.json" ]; then effort=$(jq -r '.effortLevel // empty' "$HOME/.claude/settings.json" 2>/dev/null) fi # No space between model and · when model already ends with ")", # otherwise use a single space separator. case "$model" in *")") eff_sep="" ;; *) eff_sep=" " ;; esac effort_part="" case "$effort" in low) effort_part=$(printf "%s\033[0;90m·low\033[0m" "$eff_sep") ;; medium) effort_part=$(printf "%s\033[0;32m·med\033[0m" "$eff_sep") ;; high) effort_part=$(printf "%s\033[0;33m·high\033[0m" "$eff_sep") ;; max) effort_part=$(printf "%s\033[1;35m·max\033[0m" "$eff_sep") ;; auto) effort_part=$(printf "%s\033[0;36m·auto\033[0m" "$eff_sep") ;; esac ctx_part="" if [ -n "$ctx_used" ]; then ctx_part=$(printf " | ctx:%.0f%%" "$ctx_used") fi rate_part="" if [ -n "$five_used" ] || [ -n "$week_used" ]; then rate_part=" |" rate_part="${rate_part}$(pacer 5h "$five_used" "$five_reset" 18000 m)" rate_part="${rate_part}$(pacer 7d "$week_used" "$week_reset" 604800 d)" fi printf "\033[1;32m%s@%s\033[0m \033[0;90m%s\033[0m\033[1;34m%s\033[0m | \033[0;33m%s\033[0m%s%s%s" \ "$user" "$host" "$parent_prefix" "$base" "$model" "$effort_part" "$ctx_part" "$rate_part"