Created
February 9, 2026 18:54
-
-
Save mrf/bf166c6c2db4b98ed3c8e972c88733b5 to your computer and use it in GitHub Desktop.
Claude Code multi-line statusline with context, rate limits, model, git branch, thinking mode, and cost
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Claude Code Statusline - Multi-line, column-aligned status display | |
| # Lines share a 3-column grid so pipes line up: | |
| # [Col A: 31 chars] | [Col B: 31 chars] | [Col C: variable] | |
| # Line 1: model | context bar | dir branch [wt] | |
| # Line 2: current bar | weekly bar | extra bar | |
| # Line 3: resets time | resets datetime | resets date | |
| # Line 4: think ●●● | $cost | |
| # Receives JSON via stdin from Claude Code | |
| input=$(cat) | |
| # ── Extract data ── | |
| CURRENT_DIR=$(echo "$input" | jq -r '.workspace.current_dir // ""') | |
| PROJECT_DIR=$(echo "$input" | jq -r '.workspace.project_dir // ""') | |
| COST=$(echo "$input" | jq -r '.cost.total_cost_usd // 0') | |
| TRANSCRIPT_PATH=$(echo "$input" | jq -r '.transcript_path // ""') | |
| # Get the ACTUAL model from the transcript (last assistant message), | |
| # since the statusline JSON model field reflects the global preference, | |
| # not the per-session model. | |
| MODEL="?" | |
| if [ -n "$TRANSCRIPT_PATH" ] && [ -f "$TRANSCRIPT_PATH" ]; then | |
| ACTUAL_MODEL=$(tail -50 "$TRANSCRIPT_PATH" 2>/dev/null \ | |
| | jq -r 'select(.type == "assistant") | .message.model // empty' 2>/dev/null \ | |
| | tail -1) | |
| if [ -n "$ACTUAL_MODEL" ] && [ "$ACTUAL_MODEL" != "null" ]; then | |
| case "$ACTUAL_MODEL" in | |
| *opus-4-6*) MODEL="Opus 4.6" ;; | |
| *opus-4-5*) MODEL="Opus 4.5" ;; | |
| *opus*) MODEL="Opus" ;; | |
| *sonnet-4-5*) MODEL="Sonnet 4.5" ;; | |
| *sonnet*) MODEL="Sonnet" ;; | |
| *haiku-4-5*) MODEL="Haiku 4.5" ;; | |
| *haiku*) MODEL="Haiku" ;; | |
| *) MODEL="$ACTUAL_MODEL" ;; | |
| esac | |
| fi | |
| fi | |
| # Context window data | |
| CONTEXT_MAX=$(echo "$input" | jq -r '.context_window.context_window_size // 0') | |
| INPUT_TOKENS=$(echo "$input" | jq -r '.context_window.current_usage.input_tokens // 0') | |
| OUTPUT_TOKENS=$(echo "$input" | jq -r '.context_window.current_usage.output_tokens // 0') | |
| CACHE_READ=$(echo "$input" | jq -r '.context_window.current_usage.cache_read_input_tokens // 0') | |
| CACHE_CREATION=$(echo "$input" | jq -r '.context_window.current_usage.cache_creation_input_tokens // 0') | |
| USED_PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0') | |
| CONTENT_TOKENS=$((CACHE_READ + INPUT_TOKENS + CACHE_CREATION + OUTPUT_TOKENS)) | |
| # Format cost | |
| if [ "$COST" != "0" ] && [ "$COST" != "null" ]; then | |
| COST_FMT=$(printf "%.2f" "$COST" 2>/dev/null || echo "$COST") | |
| else | |
| COST_FMT="0.00" | |
| fi | |
| # Shorten directory | |
| if [ -n "$PROJECT_DIR" ] && [ "$CURRENT_DIR" != "$PROJECT_DIR" ]; then | |
| DIR_DISPLAY="${CURRENT_DIR#"$PROJECT_DIR"/}" | |
| else | |
| DIR_DISPLAY="${CURRENT_DIR##*/}" | |
| fi | |
| # Git branch + worktree detection | |
| GIT_BRANCH="" | |
| IS_WORKTREE=false | |
| if [ -n "$CURRENT_DIR" ] && [ -d "$CURRENT_DIR/.git" ] || git -C "$CURRENT_DIR" rev-parse --git-dir &>/dev/null 2>&1; then | |
| BRANCH=$(git -C "$CURRENT_DIR" branch --show-current 2>/dev/null) | |
| [ -n "$BRANCH" ] && GIT_BRANCH=" $BRANCH" | |
| # In a worktree, --git-dir and --git-common-dir differ | |
| GIT_DIR=$(git -C "$CURRENT_DIR" rev-parse --git-dir 2>/dev/null) | |
| GIT_COMMON=$(git -C "$CURRENT_DIR" rev-parse --git-common-dir 2>/dev/null) | |
| [ -n "$GIT_DIR" ] && [ -n "$GIT_COMMON" ] && [ "$GIT_DIR" != "$GIT_COMMON" ] && IS_WORKTREE=true | |
| fi | |
| # ── True-color ANSI codes ── | |
| RST="\033[0m" | |
| BOLD="\033[1m" | |
| DIM="\033[2m" | |
| BLUE="\033[38;2;0;153;255m" | |
| ORANGE="\033[38;2;255;176;85m" | |
| GREEN="\033[38;2;0;160;0m" | |
| CYAN="\033[38;2;100;200;200m" | |
| RED="\033[38;2;255;85;85m" | |
| YELLOW="\033[38;2;230;200;0m" | |
| WHITE="\033[38;2;220;220;220m" | |
| GRAY="\033[38;2;180;180;180m" | |
| MAGENTA="\033[35m" | |
| # ── Layout constants ── | |
| COL_W=31 # Fixed column width for cols A and B | |
| BAR_WIDTH=15 # Progress bar dot count | |
| SEP=" ${DIM}|${RST} " | |
| # ── Helpers ── | |
| # Print spaces to pad from current visible width to COL_W | |
| pad() { | |
| local gap=$(( COL_W - $1 )) | |
| [ "$gap" -gt 0 ] && printf "%*s" "$gap" "" | |
| } | |
| build_bar() { | |
| local pct=$1 width=$2 | |
| [ "$pct" -lt 0 ] 2>/dev/null && pct=0 | |
| [ "$pct" -gt 100 ] 2>/dev/null && pct=100 | |
| local filled=$(( pct * width / 100 )) | |
| local empty=$(( width - filled )) | |
| local bar_color | |
| if [ "$pct" -ge 90 ]; then bar_color="$RED" | |
| elif [ "$pct" -ge 70 ]; then bar_color="$YELLOW" | |
| elif [ "$pct" -ge 50 ]; then bar_color="$ORANGE" | |
| else bar_color="$GREEN" | |
| fi | |
| local filled_str="" empty_str="" | |
| for ((i=0; i<filled; i++)); do filled_str+="●"; done | |
| for ((i=0; i<empty; i++)); do empty_str+="○"; done | |
| printf "%b%s%b%b%s%b" "$bar_color" "$filled_str" "$RST" "$DIM" "$empty_str" "$RST" | |
| } | |
| format_tokens() { | |
| local n=$1 | |
| if [ "$n" -ge 1000000 ] 2>/dev/null; then | |
| printf "%s" "$(echo "scale=1; $n / 1000000" | bc)m" | |
| elif [ "$n" -ge 1000 ] 2>/dev/null; then | |
| printf "%s" "$(( n / 1000 ))k" | |
| else | |
| printf "%s" "$n" | |
| fi | |
| } | |
| format_reset_time() { | |
| local iso="$1" style="$2" | |
| [ -z "$iso" ] && return | |
| local epoch | |
| epoch=$(date -d "$iso" +%s 2>/dev/null) | |
| [ -z "$epoch" ] && return | |
| if [ "$style" = "time" ]; then | |
| date -d "@$epoch" "+%-I:%M%P" 2>/dev/null | |
| else | |
| date -d "@$epoch" "+%b %-d, %-I:%M%P" 2>/dev/null | |
| fi | |
| } | |
| cached_fetch() { | |
| local cache_file="$1" max_age="$2" | |
| shift 2 | |
| if [ -f "$cache_file" ]; then | |
| local mtime now age | |
| mtime=$(stat -c %Y "$cache_file" 2>/dev/null || stat -f %m "$cache_file" 2>/dev/null || echo 0) | |
| now=$(date +%s) | |
| age=$(( now - mtime )) | |
| if [ "$age" -lt "$max_age" ]; then | |
| cat "$cache_file" 2>/dev/null | |
| return | |
| fi | |
| fi | |
| local resp | |
| resp=$(curl -s --max-time 3 "$@" 2>/dev/null) | |
| if [ -n "$resp" ] && [ "$resp" != "null" ]; then | |
| echo "$resp" > "$cache_file" 2>/dev/null | |
| echo "$resp" | |
| elif [ -f "$cache_file" ]; then | |
| cat "$cache_file" 2>/dev/null | |
| fi | |
| } | |
| # ── Read settings ── | |
| THINKING="off" | |
| EFFORT="" | |
| SETTINGS_FILE="$HOME/.claude/settings.json" | |
| if [ -f "$SETTINGS_FILE" ]; then | |
| THINK_VAL=$(jq -r '.alwaysThinkingEnabled // false' "$SETTINGS_FILE" 2>/dev/null) | |
| [ "$THINK_VAL" = "true" ] && THINKING="on" | |
| EFFORT=$(jq -r '.effortLevel // ""' "$SETTINGS_FILE" 2>/dev/null) | |
| fi | |
| # ── Context color ── | |
| if [ "$USED_PCT" -lt 50 ]; then CTX_COLOR="$GREEN" | |
| elif [ "$USED_PCT" -lt 75 ]; then CTX_COLOR="$YELLOW" | |
| else CTX_COLOR="$RED" | |
| fi | |
| # ── Pre-compute display strings ── | |
| TOKENS_USED_STR=$(format_tokens $CONTENT_TOKENS) | |
| TOKENS_MAX_STR=$(format_tokens $CONTEXT_MAX) | |
| # ═══════════════════════════════════════════════════════════ | |
| # LINE 1: model | context bar | dir branch [wt] | |
| # ═══════════════════════════════════════════════════════════ | |
| # Col A: model | |
| printf "%b%b%s%b" "$BOLD" "$BLUE" "$MODEL" "$RST" | |
| pad ${#MODEL} | |
| printf "%b" "$SEP" | |
| # Col B: context bar | |
| build_bar "$USED_PCT" $BAR_WIDTH | |
| USED_STR="${USED_PCT}%" | |
| TOK_STR="${TOKENS_USED_STR}/${TOKENS_MAX_STR}" | |
| printf " %b%s%b %b%s%b" "$CTX_COLOR" "$USED_STR" "$RST" "$DIM" "$TOK_STR" "$RST" | |
| pad $(( BAR_WIDTH + 1 + ${#USED_STR} + 1 + ${#TOK_STR} )) | |
| printf "%b" "$SEP" | |
| # Col C: dir branch [wt] (free to grow) | |
| printf "%b%s%b" "$MAGENTA" "$DIR_DISPLAY" "$RST" | |
| [ -n "$GIT_BRANCH" ] && printf "%b%b%s%b" "$DIM" "$GREEN" "$GIT_BRANCH" "$RST" | |
| $IS_WORKTREE && printf " %b%bwt%b" "$BOLD" "$ORANGE" "$RST" | |
| echo | |
| # ═══════════════════════════════════════════════════════════ | |
| # LINE 2: current bar | weekly bar | extra bar | |
| # LINE 3: resets | resets | resets | |
| # LINE 4: think ●●● | $cost | |
| # ═══════════════════════════════════════════════════════════ | |
| CREDS_FILE="$HOME/.claude/.credentials.json" | |
| USAGE_DATA="" | |
| if [ -f "$CREDS_FILE" ]; then | |
| TOKEN=$(jq -r '.claudeAiOauth.accessToken // ""' "$CREDS_FILE" 2>/dev/null) | |
| if [ -n "$TOKEN" ]; then | |
| RESP=$(cached_fetch "/tmp/claude-statusline-usage-cache.json" 60 \ | |
| -H "Accept: application/json" \ | |
| -H "Authorization: Bearer $TOKEN" \ | |
| -H "anthropic-beta: oauth-2025-04-20" \ | |
| "https://api.anthropic.com/api/oauth/usage") | |
| if [ -n "$RESP" ] && echo "$RESP" | jq -e '.five_hour' &>/dev/null; then | |
| USAGE_DATA="$RESP" | |
| fi | |
| fi | |
| fi | |
| EXTRA_ENABLED=false | |
| if [ -n "$USAGE_DATA" ]; then | |
| FIVE_PCT=$(echo "$USAGE_DATA" | jq -r '.five_hour.utilization // 0' | xargs printf "%.0f" 2>/dev/null) | |
| FIVE_RESET_ISO=$(echo "$USAGE_DATA" | jq -r '.five_hour.resets_at // ""') | |
| FIVE_RESET=$(format_reset_time "$FIVE_RESET_ISO" "time") | |
| SEVEN_PCT=$(echo "$USAGE_DATA" | jq -r '.seven_day.utilization // 0' | xargs printf "%.0f" 2>/dev/null) | |
| SEVEN_RESET_ISO=$(echo "$USAGE_DATA" | jq -r '.seven_day.resets_at // ""') | |
| SEVEN_RESET=$(format_reset_time "$SEVEN_RESET_ISO" "datetime") | |
| EXTRA_ENABLED=$(echo "$USAGE_DATA" | jq -r '.extra_usage.is_enabled // false') | |
| if [ "$EXTRA_ENABLED" = "true" ]; then | |
| EXTRA_PCT=$(echo "$USAGE_DATA" | jq -r '.extra_usage.utilization // 0' | xargs printf "%.0f" 2>/dev/null) | |
| EXTRA_USED=$(echo "$USAGE_DATA" | jq -r '.extra_usage.used_credits // 0') | |
| EXTRA_LIMIT=$(echo "$USAGE_DATA" | jq -r '.extra_usage.monthly_limit // 0') | |
| EXTRA_USED_D=$(echo "scale=2; $EXTRA_USED / 100" | bc 2>/dev/null || echo "0") | |
| EXTRA_LIMIT_D=$(echo "scale=2; $EXTRA_LIMIT / 100" | bc 2>/dev/null || echo "0") | |
| EXTRA_RESET=$(date -d "$(date +%Y-%m-01) +1 month" "+%b %-d" 2>/dev/null) | |
| fi | |
| fi | |
| # ── LINE 2: rate limit bars ── | |
| if [ -n "$USAGE_DATA" ]; then | |
| # Col A: current (5h) bar | |
| printf "%bcurrent:%b " "$WHITE" "$RST" | |
| build_bar "$FIVE_PCT" $BAR_WIDTH | |
| PCT_STR="${FIVE_PCT}%" | |
| printf " %b%s%b" "$CYAN" "$PCT_STR" "$RST" | |
| pad $(( 9 + BAR_WIDTH + 1 + ${#PCT_STR} )) | |
| printf "%b" "$SEP" | |
| # Col B: weekly (7d) bar | |
| printf "%bweekly:%b " "$WHITE" "$RST" | |
| build_bar "$SEVEN_PCT" $BAR_WIDTH | |
| PCT_STR="${SEVEN_PCT}%" | |
| printf " %b%s%b" "$CYAN" "$PCT_STR" "$RST" | |
| pad $(( 9 + BAR_WIDTH + 1 + ${#PCT_STR} )) | |
| printf "%b" "$SEP" | |
| # Col C: extra bar (if enabled) | |
| if [ "$EXTRA_ENABLED" = "true" ]; then | |
| printf "%bextra:%b " "$WHITE" "$RST" | |
| build_bar "$EXTRA_PCT" $BAR_WIDTH | |
| printf " %b\$%s/\$%s%b" "$CYAN" "$EXTRA_USED_D" "$EXTRA_LIMIT_D" "$RST" | |
| fi | |
| fi | |
| echo | |
| # ── LINE 3: all resets (only if usage data) ── | |
| if [ -n "$USAGE_DATA" ]; then | |
| # Col A: 5h reset (under current bar) | |
| RESET_A="resets ${FIVE_RESET}" | |
| printf "%b%s%b" "$GRAY" "$RESET_A" "$RST" | |
| pad ${#RESET_A} | |
| printf "%b" "$SEP" | |
| # Col B: 7d reset (under weekly bar) | |
| RESET_B="resets ${SEVEN_RESET}" | |
| printf "%b%s%b" "$GRAY" "$RESET_B" "$RST" | |
| pad ${#RESET_B} | |
| printf "%b" "$SEP" | |
| # Col C: extra reset (under extra bar) | |
| if [ "$EXTRA_ENABLED" = "true" ]; then | |
| printf "%bresets %s%b" "$GRAY" "$EXTRA_RESET" "$RST" | |
| fi | |
| echo | |
| fi | |
| # ── LINE 4: think | $cost ── | |
| # Col A: think effort | |
| if [ "$THINKING" = "on" ]; then | |
| case "$EFFORT" in | |
| high) printf "%bthink %b●●●%b" "$WHITE" "$GREEN" "$RST"; TVLEN=9 ;; | |
| medium) printf "%bthink %b●●%b%b○%b" "$WHITE" "$YELLOW" "$RST" "$DIM" "$RST"; TVLEN=9 ;; | |
| low) printf "%bthink %b●%b%b○○%b" "$WHITE" "$RED" "$RST" "$DIM" "$RST"; TVLEN=9 ;; | |
| *) printf "%bthink %b●●●%b" "$WHITE" "$GREEN" "$RST"; TVLEN=9 ;; | |
| esac | |
| else | |
| printf "%bthink %b○○○%b" "$WHITE" "$DIM" "$RST"; TVLEN=9 | |
| fi | |
| pad $TVLEN | |
| printf "%b" "$SEP" | |
| # Col B: $cost | |
| COST_STR="\$${COST_FMT}" | |
| printf "%b%s%b" "$DIM" "$COST_STR" "$RST" | |
| echo |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment