Skip to content

Instantly share code, notes, and snippets.

@msadig
Last active April 16, 2026 13:52
Show Gist options
  • Select an option

  • Save msadig/bf3f4b3a0659b63f44a86457cbb030bd to your computer and use it in GitHub Desktop.

Select an option

Save msadig/bf3f4b3a0659b63f44a86457cbb030bd to your computer and use it in GitHub Desktop.
Claude Code statusline
#!/bin/bash
# Enhanced Claude Code statusline with session-specific context tracking
input=$(cat)
# Extract basic values using jq with safe defaults
MODEL_ID=$(echo "$input" | jq -r '.model.id // ""')
MODEL_DISPLAY=$(echo "$input" | jq -r '.model.display_name // "Claude"')
PROJECT_DIR=$(echo "$input" | jq -r '.workspace.project_dir // ""')
CURRENT_DIR=$(echo "$input" | jq -r '.workspace.current_dir // ""')
SESSION_ID=$(echo "$input" | jq -r '.session_id // ""')
CLAUDE_VERSION=$(claude --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' || echo "?")
# Extract cost and metrics information (these remain global across sessions)
TOTAL_COST=$(echo "$input" | jq -r '.cost.total_cost_usd // 0')
TOTAL_DURATION=$(echo "$input" | jq -r '.cost.total_duration_ms // 0')
LINES_ADDED=$(echo "$input" | jq -r '.cost.total_lines_added // 0')
LINES_REMOVED=$(echo "$input" | jq -r '.cost.total_lines_removed // 0')
# Git branch detection
GIT_BRANCH=""
if git rev-parse --git-dir > /dev/null 2>&1; then
BRANCH=$(git branch --show-current 2>/dev/null)
if [ -n "$BRANCH" ]; then
GIT_BRANCH=" | 🌿 \033[94m$BRANCH\033[0m "
fi
fi
# Context usage from Claude Code's built-in calculation
CONTEXT_USED_PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
# Context limit warning thresholds (Claude auto-compacts at ~95%)
COMPACT_THRESHOLD=95
WARNING_THRESHOLD=80
# Format cost display
if (( $(echo "$TOTAL_COST < 0.01" | bc -l 2>/dev/null || echo "1") )); then
COST_DISPLAY=$(printf "%.4f" "$TOTAL_COST")
else
COST_DISPLAY=$(printf "%.2f" "$TOTAL_COST")
fi
# Format session duration
DURATION_SEC=$((TOTAL_DURATION / 1000))
DURATION_MIN=$((DURATION_SEC / 60))
DURATION_HOURS=$((DURATION_MIN / 60))
if [ $DURATION_HOURS -gt 0 ]; then
DURATION_DISPLAY="${DURATION_HOURS}h $((DURATION_MIN % 60))m"
elif [ $DURATION_MIN -gt 0 ]; then
DURATION_DISPLAY="${DURATION_MIN}m"
else
DURATION_DISPLAY="${DURATION_SEC}s"
fi
# Color coding based on context usage (not remaining)
if [ $CONTEXT_USED_PCT -lt $WARNING_THRESHOLD ]; then
CONTEXT_COLOR="\033[32m" # Green - safe usage
elif [ $CONTEXT_USED_PCT -lt $COMPACT_THRESHOLD ]; then
CONTEXT_COLOR="\033[33m" # Yellow - approaching auto-compact
else
CONTEXT_COLOR="\033[31m" # Red - will auto-compact soon
fi
RESET_COLOR="\033[0m" # Reset color
# Additional subtle colors for different info types
TIME_COLOR="\033[36m" # Cyan for time information
COST_COLOR="\033[33m" # Yellow for cost/financial
METRIC_COLOR="\033[35m" # Magenta for metrics/tokens
# Format directory display
PROJECT_NAME="${PROJECT_DIR##*/}"
CURRENT_NAME="${CURRENT_DIR##*/}"
if [ "$PROJECT_NAME" = "$CURRENT_NAME" ] || [ -z "$PROJECT_NAME" ]; then
DIR_DISPLAY="πŸ“ $CURRENT_NAME"
else
DIR_DISPLAY="🎯 $PROJECT_NAME: πŸ“ $CURRENT_NAME"
fi
# Context status message
if [ $CONTEXT_USED_PCT -ge $COMPACT_THRESHOLD ]; then
CONTEXT_STATUS="auto-compact soon"
elif [ $CONTEXT_USED_PCT -ge $WARNING_THRESHOLD ]; then
CONTEXT_STATUS="approaching limit"
else
CONTEXT_STATUS="healthy"
fi
# Global rate limit reset calculation (most APIs reset hourly)
CURRENT_EPOCH=$(date +%s)
CURRENT_HOUR=$(date +%H)
CURRENT_MINUTE=$(date +%M)
# Calculate next hour reset
NEXT_HOUR=$(( (CURRENT_HOUR + 1) % 24 ))
MINUTES_TO_RESET=$(( 60 - CURRENT_MINUTE ))
# Format global reset time
if [ $MINUTES_TO_RESET -eq 60 ] || [ $MINUTES_TO_RESET -eq 0 ]; then
GLOBAL_RESET="now"
elif [ $MINUTES_TO_RESET -gt 0 ] && [ $MINUTES_TO_RESET -lt 60 ]; then
GLOBAL_RESET="${MINUTES_TO_RESET}m"
else
GLOBAL_RESET="1m" # Fallback for edge cases
fi
# Calculate next reset time
RESET_EPOCH=$(( CURRENT_EPOCH + (MINUTES_TO_RESET * 60) ))
GLOBAL_RESET_TIME=$(date -r $RESET_EPOCH +"%H:%M" 2>/dev/null || date -d "@$RESET_EPOCH" +"%H:%M" 2>/dev/null || echo "??:??")
# Calculate cost per hour if duration is significant
COST_PER_HOUR=""
if [ $DURATION_MIN -gt 0 ]; then
HOURS_DECIMAL=$(echo "scale=2; $DURATION_MIN / 60" | bc -l 2>/dev/null || echo "0")
if (( $(echo "$HOURS_DECIMAL > 0" | bc -l 2>/dev/null || echo "0") )); then
HOURLY_RATE=$(echo "scale=2; $TOTAL_COST / $HOURS_DECIMAL" | bc -l 2>/dev/null || echo "0")
if (( $(echo "$HOURLY_RATE > 0" | bc -l 2>/dev/null || echo "0") )); then
COST_PER_HOUR=" (\$${HOURLY_RATE}/h)"
fi
fi
fi
# Create a simple progress bar for context usage (shows used, not remaining)
create_progress_bar() {
local used_percent=$1
local width=10
local filled=$(( used_percent * width / 100 ))
local empty=$(( width - filled ))
local bar="["
for ((i=0; i<filled; i++)); do
bar="${bar}β–ˆ"
done
for ((i=0; i<empty; i++)); do
bar="${bar}β–‘"
done
bar="${bar}]"
echo "$bar"
}
PROGRESS_BAR=$(create_progress_bar "$CONTEXT_USED_PCT")
# 5-hour rate limit (Claude.ai subscription only; absent for API users)
FIVE_HOUR_PCT=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
FIVE_HOUR_RESETS_AT=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty')
FIVE_HOUR_DISPLAY=""
if [ -n "$FIVE_HOUR_PCT" ]; then
FIVE_HOUR_INT=$(printf "%.0f" "$FIVE_HOUR_PCT")
if [ "$FIVE_HOUR_INT" -ge 90 ]; then
RATE_COLOR="\033[31m" # Red - near limit
elif [ "$FIVE_HOUR_INT" -ge 70 ]; then
RATE_COLOR="\033[33m" # Yellow - getting close
else
RATE_COLOR="\033[32m" # Green - fine
fi
# Show time until reset if available
RESET_SUFFIX=""
if [ -n "$FIVE_HOUR_RESETS_AT" ] && [ "$FIVE_HOUR_RESETS_AT" -gt 0 ] 2>/dev/null; then
NOW=$(date +%s)
SECS_LEFT=$(( FIVE_HOUR_RESETS_AT - NOW ))
if [ $SECS_LEFT -gt 0 ]; then
MINS_LEFT=$(( SECS_LEFT / 60 ))
if [ $MINS_LEFT -ge 60 ]; then
RESET_SUFFIX=" (~$((MINS_LEFT/60))h$((MINS_LEFT%60))m)"
else
RESET_SUFFIX=" (~${MINS_LEFT}m)"
fi
fi
fi
FIVE_HOUR_DISPLAY=" | ${RATE_COLOR}5h: ${FIVE_HOUR_INT}%${RESET_COLOR}${RESET_SUFFIX}"
fi
# 7-day rate limit (Claude.ai subscription only; absent for API users)
SEVEN_DAY_PCT=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
SEVEN_DAY_RESETS_AT=$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at // empty')
SEVEN_DAY_DISPLAY=""
if [ -n "$SEVEN_DAY_PCT" ]; then
SEVEN_DAY_INT=$(printf "%.0f" "$SEVEN_DAY_PCT")
if [ "$SEVEN_DAY_INT" -ge 90 ]; then
WEEK_COLOR="\033[31m"
elif [ "$SEVEN_DAY_INT" -ge 70 ]; then
WEEK_COLOR="\033[33m"
else
WEEK_COLOR="\033[32m"
fi
WEEK_RESET_SUFFIX=""
if [ -n "$SEVEN_DAY_RESETS_AT" ] && [ "$SEVEN_DAY_RESETS_AT" -gt 0 ] 2>/dev/null; then
NOW=$(date +%s)
SECS_LEFT=$(( SEVEN_DAY_RESETS_AT - NOW ))
if [ $SECS_LEFT -gt 0 ]; then
DAYS_LEFT=$(( SECS_LEFT / 86400 ))
HOURS_LEFT=$(( (SECS_LEFT % 86400) / 3600 ))
MINS_LEFT=$(( (SECS_LEFT % 3600) / 60 ))
WEEK_RESET_PARTS=""
[ $DAYS_LEFT -gt 0 ] && WEEK_RESET_PARTS="${DAYS_LEFT}d"
if [ $HOURS_LEFT -gt 0 ]; then
[ -n "$WEEK_RESET_PARTS" ] && WEEK_RESET_PARTS="${WEEK_RESET_PARTS},"
WEEK_RESET_PARTS="${WEEK_RESET_PARTS}${HOURS_LEFT}h"
fi
if [ $MINS_LEFT -gt 0 ]; then
[ -n "$WEEK_RESET_PARTS" ] && WEEK_RESET_PARTS="${WEEK_RESET_PARTS},"
WEEK_RESET_PARTS="${WEEK_RESET_PARTS}${MINS_LEFT}m"
fi
[ -n "$WEEK_RESET_PARTS" ] && WEEK_RESET_SUFFIX=" (~${WEEK_RESET_PARTS})"
fi
fi
SEVEN_DAY_DISPLAY=" | ${WEEK_COLOR}7d: ${SEVEN_DAY_INT}%${RESET_COLOR}${WEEK_RESET_SUFFIX}"
fi
# Build two-line status display
# Line 1: Keep original format with project/directory info
echo -e "[$MODEL_DISPLAY | v$CLAUDE_VERSION] 🎯 ${PROJECT_DIR##*/}: πŸ“ ${CURRENT_DIR##*/}${GIT_BRANCH}"
# Line 2: Session duration + Cost + Context progress + 5-hour rate limit
echo -e "⏱️ ${TIME_COLOR}${DURATION_DISPLAY}${RESET_COLOR} | πŸ’° ${COST_COLOR}\$${COST_DISPLAY}${RESET_COLOR} | ${CONTEXT_COLOR}${PROGRESS_BAR} ${CONTEXT_USED_PCT}%${RESET_COLOR} (${CONTEXT_STATUS})${FIVE_HOUR_DISPLAY}${SEVEN_DAY_DISPLAY}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment