Skip to content

Instantly share code, notes, and snippets.

@ekinertac
Created June 11, 2026 02:56
Show Gist options
  • Select an option

  • Save ekinertac/bc186ed0b69287c62dc259effd67ab08 to your computer and use it in GitHub Desktop.

Select an option

Save ekinertac/bc186ed0b69287c62dc259effd67ab08 to your computer and use it in GitHub Desktop.
Two-line Claude Code statusline: model/dir/branch + context bar, cost, timer, rate limits. From: ekinertac.com/blog/i-turned-claude-codes-statusline-into-a-cockpit/
#!/bin/bash
# ~/.claude/statusline.sh
# Two-line Claude Code statusline.
#
# Role in system:
# Invoked by Claude Code after each assistant message / on permission-mode or
# vim-mode changes (debounced 300ms). Receives JSON session data on stdin
# and prints two lines of formatted output. Coexists with the built-in
# right-side notification area (MCP errors, context-low warnings, etc.) —
# those are NOT rendered by this script, they share the row by design.
#
# Wired up from: ~/.claude/settings.json -> "statusLine.command"
# Related docs: https://code.claude.com/docs/en/statusline
#
# Layout:
# line 1: [Model] dir | branch
# line 2: <context-bar> N% | $cost | mm:ss | 5h:N% 7d:N%
#
# Design notes:
# - No git status / dirty-check on purpose (user pref) — only `branch --show-current`.
# - jq is required. If absent the script silently degrades to "[unknown]".
# - Rate limits are absent for non-Pro/Max users; handled with `// empty`.
input=$(cat)
# Bail to a useful default if jq is missing rather than printing nothing.
if ! command -v jq >/dev/null 2>&1; then
echo "[statusline: install jq]"
exit 0
fi
MODEL=$(echo "$input" | jq -r '.model.display_name // "unknown"')
DIR=$(echo "$input" | jq -r '.workspace.current_dir // .cwd // ""')
PCT=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
COST=$(echo "$input" | jq -r '.cost.total_cost_usd // 0')
DURATION_MS=$(echo "$input" | jq -r '.cost.total_duration_ms // 0')
FIVE_H=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
WEEK=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
CYAN='\033[36m'
GREEN='\033[32m'
YELLOW='\033[33m'
RED='\033[31m'
DIM='\033[2m'
RESET='\033[0m'
# Color the context bar by pressure so high usage is visually loud.
if [ "$PCT" -ge 90 ]; then
BAR_COLOR="$RED"
elif [ "$PCT" -ge 70 ]; then
BAR_COLOR="$YELLOW"
else
BAR_COLOR="$GREEN"
fi
BAR_WIDTH=10
FILLED=$((PCT * BAR_WIDTH / 100))
[ "$FILLED" -gt "$BAR_WIDTH" ] && FILLED=$BAR_WIDTH
EMPTY=$((BAR_WIDTH - FILLED))
BAR=""
[ "$FILLED" -gt 0 ] && printf -v FILL "%${FILLED}s" && BAR="${FILL// /█}"
[ "$EMPTY" -gt 0 ] && printf -v PAD "%${EMPTY}s" && BAR="${BAR}${PAD// /░}"
MINS=$((DURATION_MS / 60000))
SECS=$(((DURATION_MS % 60000) / 1000))
DUR_FMT=$(printf '%dm %02ds' "$MINS" "$SECS")
COST_FMT=$(printf '$%.2f' "$COST")
# Branch is cheap — no caching needed. Silent fail outside a repo.
BRANCH=""
if git rev-parse --git-dir >/dev/null 2>&1; then
B=$(git branch --show-current 2>/dev/null)
[ -n "$B" ] && BRANCH=" | 🌿 $B"
fi
# Rate-limits segment is omitted entirely for non-subscribers.
LIMITS=""
if [ -n "$FIVE_H" ]; then
LIMITS=$(printf '5h:%.0f%%' "$FIVE_H")
fi
if [ -n "$WEEK" ]; then
W=$(printf '7d:%.0f%%' "$WEEK")
LIMITS="${LIMITS:+$LIMITS }$W"
fi
# Collapse $HOME to ~ for readability without losing path context.
DIR_DISPLAY="$DIR"
case "$DIR" in
"$HOME") DIR_DISPLAY="~" ;;
"$HOME"/*) DIR_DISPLAY="~${DIR#$HOME}" ;;
esac
# Line 1: identity + location
printf '%b\n' "${CYAN}[$MODEL]${RESET} 📁 ${DIR_DISPLAY}${BRANCH}"
# Line 2: pressure + economics
LINE2="${BAR_COLOR}${BAR}${RESET} ${PCT}% | ${YELLOW}${COST_FMT}${RESET} | ${DIM}⏱ ${DUR_FMT}${RESET}"
[ -n "$LIMITS" ] && LINE2="${LINE2} | ${DIM}${LIMITS}${RESET}"
printf '%b\n' "$LINE2"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment