Skip to content

Instantly share code, notes, and snippets.

@andesco
Created March 27, 2026 19:42
Show Gist options
  • Select an option

  • Save andesco/b3e53a7ad3c70be64b4a5f5ffde81e86 to your computer and use it in GitHub Desktop.

Select an option

Save andesco/b3e53a7ad3c70be64b4a5f5ffde81e86 to your computer and use it in GitHub Desktop.
Claude Code statusline with 5h/7d pacing indicators
#!/usr/bin/env bash
# Claude Code status line script
# Format: {dir} | context: {remaining%} | 5h: {actual_remaining%} {expected_remaining%} {hh:mm} | 7d: {actual%} {expected%} {dd}
input=$(cat)
now=$(date +%s)
# Working day configuration for 7d pacing
# Adjust these to match your typical usage hours
WORK_TZ="America/Toronto" # Your timezone (used for active window calculation)
WORK_START_HOUR=8 # Hour you start using Claude (24h, in $WORK_TZ)
WORK_END_HOUR=24 # Hour you stop (24 = midnight, in $WORK_TZ)
# Colorize a percentage: green >50, orange >10, red <=10
colorpct() {
local val="$1"
if [ "$val" -gt 50 ]; then
printf '\033[32m%s%%\033[0m' "$val" # green
elif [ "$val" -gt 10 ]; then
printf '\033[33m%s%%\033[0m' "$val" # orange/yellow
else
printf '\033[31m%s%%\033[0m' "$val" # red
fi
}
# Directory name
dir_path=$(echo "$input" | jq -r '.workspace.current_dir // empty')
if [ -n "$dir_path" ]; then
dir_name=$(basename "$dir_path")
else
dir_name=""
fi
# Context window remaining
ctx_remaining=$(echo "$input" | jq -r '.context_window.remaining_percentage // empty')
ctx_str=""
if [ -n "$ctx_remaining" ]; then
ctx_int=$(printf '%.0f' "$ctx_remaining")
ctx_str="context: $(colorpct "$ctx_int")"
fi
# 5-hour window
five_used=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
five_resets=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty')
five_str=""
if [ -n "$five_used" ]; then
five_used_int=$(printf '%.0f' "$five_used")
five_remaining_int=$(( 100 - five_used_int ))
# Calculate expected remaining % based on elapsed time in the 5-hour window
# expected_remaining = (1 - elapsed_minutes / 300) * 100
five_expected_remaining_str=""
if [ -n "$five_resets" ]; then
five_start=$(( five_resets - 5 * 3600 ))
five_expected_remaining_str=$(awk "BEGIN {
elapsed_min = ($now - $five_start) / 60
if (elapsed_min < 0) elapsed_min = 0
if (elapsed_min > 300) elapsed_min = 300
expected_remaining = (1 - elapsed_min / 300) * 100
if (expected_remaining < 0) expected_remaining = 0
printf \"%.0f%%\", expected_remaining
}")
fi
# Color actual remaining % based on how far behind expected pace
# Green: actual remaining within 5pp of expected remaining or better (using less than expected)
# Orange: actual remaining is 5-10pp below expected remaining
# Red: actual remaining is more than 10pp below expected remaining
if [ -n "$five_expected_remaining_str" ]; then
five_expected_remaining_int=$(echo "$five_expected_remaining_str" | tr -d '%')
five_color=$(awk "BEGIN {
diff = $five_expected_remaining_int - $five_remaining_int
if (diff <= 5) print \"green\"
else if (diff <= 10) print \"orange\"
else print \"red\"
}")
case "$five_color" in
green) five_remaining_colored=$(printf '\033[32m%s%%\033[0m' "$five_remaining_int") ;;
orange) five_remaining_colored=$(printf '\033[33m%s%%\033[0m' "$five_remaining_int") ;;
red) five_remaining_colored=$(printf '\033[31m%s%%\033[0m' "$five_remaining_int") ;;
esac
else
five_remaining_colored=$(printf '%s%%' "$five_remaining_int")
fi
# Time remaining in 5-hour window as hh:mm
five_time=""
if [ -n "$five_resets" ]; then
five_secs=$(( five_resets - now ))
if [ "$five_secs" -gt 0 ]; then
five_time=$(awk "BEGIN {
h = int($five_secs / 3600)
m = int(($five_secs % 3600) / 60)
printf \"%d:%02d\", h, m
}")
else
five_time="0:00"
fi
fi
five_str="5h: ${five_remaining_colored}"
[ -n "$five_expected_remaining_str" ] && five_str="${five_str} ${five_expected_remaining_str}"
[ -n "$five_time" ] && five_str="${five_str} ${five_time}"
fi
# 7-day window
week_used=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
week_resets=$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at // empty')
week_str=""
if [ -n "$week_used" ]; then
week_remaining=$(echo "$week_used" | awk '{printf "%.0f", 100 - $1}')
# Time remaining in 7d window as decimal days (e.g. 6.5d)
week_time=""
week_expected_str=""
if [ -n "$week_resets" ]; then
week_secs=$(( week_resets - now ))
if [ "$week_secs" -gt 0 ]; then
week_time=$(awk "BEGIN {printf \"%.1fd\", $week_secs / 86400}")
else
week_time="0.0d"
fi
# Calculate expected remaining % based on active usage hours (8 AM - midnight ET)
# Billing period starts at 2 PM ET (week_start); active window = 8 AM to midnight ET = 16h/day
# We sum active hours elapsed since week_start, second by second, by iterating calendar days.
#
# Algorithm (all in awk, operating on Unix timestamps):
# For each calendar day boundary since week_start up to now, accumulate the overlap
# between [day_start_ET_8am, day_end_ET_midnight] and [week_start, now].
week_start=$(( week_resets - 7 * 86400 ))
# ET UTC offset in seconds (awk needs it as an integer)
et_offset_sec=$(TZ="$WORK_TZ" date +%z | awk '{
sign = ($0 ~ /^-/) ? -1 : 1
s = substr($0,2)
h = substr(s,1,2)+0; m = substr(s,3,2)+0
print sign * (h*3600 + m*60)
}')
week_expected_str=$(awk "BEGIN {
week_start = $week_start
now = $now
et_off = $et_offset_sec # seconds east of UTC (negative for ET)
work_start_h = $WORK_START_HOUR
work_end_h = $WORK_END_HOUR
total_active = 7 * (work_end_h - work_start_h)
# Find the midnight in local TZ that is <= week_start, then walk forward day by day
first_day = int((week_start + et_off) / 86400)
active_elapsed = 0
for (d = first_day; d <= first_day + 8; d++) {
# Local midnight for this day as Unix timestamp
day_midnight_utc = d * 86400 - et_off
# Active window for this day
win_start = day_midnight_utc + work_start_h * 3600
win_end = day_midnight_utc + work_end_h * 3600
# Clamp to [week_start, now]
clamp_start = (win_start > week_start) ? win_start : week_start
clamp_end = (win_end < now) ? win_end : now
if (clamp_end > clamp_start) {
active_elapsed += (clamp_end - clamp_start) / 3600
}
# Once we've passed 'now' there's nothing more to accumulate
if (day_midnight_utc + 24 * 3600 > now) break
}
expected_remaining = (1 - active_elapsed / total_active) * 100
if (expected_remaining < 0) expected_remaining = 0
printf \"%.0f%%\", expected_remaining
}")
fi
# Color 7d remaining based on how far behind the expected pace it is
# Thresholds: 4h behind, 8h behind (as percentage points of total active hours)
if [ -n "$week_expected_str" ]; then
week_expected_int=$(echo "$week_expected_str" | tr -d '%')
week_color=$(awk "BEGIN {
diff = $week_expected_int - $week_remaining
total = 7 * ($WORK_END_HOUR - $WORK_START_HOUR)
pp4h = 4 / total * 100
pp8h = 8 / total * 100
if (diff <= pp4h) print \"green\"
else if (diff <= pp8h) print \"orange\"
else print \"red\"
}")
case "$week_color" in
green) week_remaining_colored=$(printf '\033[32m%s%%\033[0m' "$week_remaining") ;;
orange) week_remaining_colored=$(printf '\033[33m%s%%\033[0m' "$week_remaining") ;;
red) week_remaining_colored=$(printf '\033[31m%s%%\033[0m' "$week_remaining") ;;
esac
else
week_remaining_colored=$(colorpct "$week_remaining")
fi
week_str="7d: ${week_remaining_colored}"
[ -n "$week_expected_str" ] && week_str="${week_str} ${week_expected_str}"
[ -n "$week_time" ] && week_str="${week_str} ${week_time}"
fi
# Assemble output
parts=()
[ -n "$dir_name" ] && parts+=("$dir_name")
[ -n "$ctx_str" ] && parts+=("$ctx_str")
[ -n "$five_str" ] && parts+=("$five_str")
[ -n "$week_str" ] && parts+=("$week_str")
output=""
for part in "${parts[@]}"; do
if [ -z "$output" ]; then
output="$part"
else
output="$output | $part"
fi
done
printf "%s" "$output"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment