statuslin.es

Overage Watcher

bash

Watches plan limits and extra-usage spending in dollars, next to model, branch with diff stats, context and cost. Env vars switch it between one and two lines.

MIT licensed · original source

Preview

Clean repo
Opus 4.8 | app@main | ctx 44k/200k (22%) | cost $0.41
New session
Opus 4.8 | app@main | ctx 0/200k (0%) | cost $0.00
Dirty branch
Sonnet 4.6 | app@feat/auth (+1 -0) | ctx 96k/200k (48%) | cost $0.41
Near-full
Opus 4.8 | app@main | ctx 182k/200k (91%) | cost $4.12
1M context
Fable 5 | app@main | ctx 640k/1.0m (64%) | cost $0.41
Post-compact
Haiku 4.5 | app@main | ctx 0/200k (0%) | cost $0.41
Worktree
Opus 4.8 | feature[wt:feature]@worktree-feature | ctx 74k/200k (37%) | cost $0.41
Non-git
Opus 4.8 | scratch | ctx 44k/200k (22%) | cost $0.41

Source

#!/usr/bin/env bash
# claude-code-statusline — Enhanced status line for Claude Code
# https://github.com/aleksander-dytko/claude-code-statusline
# MIT License — Aleksander Dytko 2026
#
# Displays: model | git repo@branch | ctx | cost | 5h limit | 7d limit | extra usage

set -f  # disable globbing
export LC_NUMERIC=C  # ensure '.' is decimal separator regardless of locale
unset LC_ALL          # LC_ALL overrides LC_NUMERIC; unset it while preserving other locale vars

# Detect stat variant once (GNU vs BSD) to avoid repeated fallback forks
if stat -c %Y /dev/null >/dev/null 2>&1; then
    _stat_mtime() { stat -c %Y "$1" 2>/dev/null; }
else
    _stat_mtime() { stat -f %m "$1" 2>/dev/null; }
fi

# ─── Configuration (override via environment variables) ─────────────────────
STATUSLINE_SHOW_GIT="${STATUSLINE_SHOW_GIT:-true}"
STATUSLINE_SHOW_CONTEXT="${STATUSLINE_SHOW_CONTEXT:-true}"
STATUSLINE_SHOW_SESSION="${STATUSLINE_SHOW_SESSION:-true}"
STATUSLINE_SHOW_WEEKLY="${STATUSLINE_SHOW_WEEKLY:-true}"
STATUSLINE_SHOW_EXTRA="${STATUSLINE_SHOW_EXTRA:-true}"
STATUSLINE_SHOW_SESSION_COST="${STATUSLINE_SHOW_SESSION_COST:-true}"
STATUSLINE_SPLIT_LINES="${STATUSLINE_SPLIT_LINES:-false}"
STATUSLINE_CACHE_TTL="${STATUSLINE_CACHE_TTL:-60}"           # seconds between API fetches
STATUSLINE_CACHE_DIR="${STATUSLINE_CACHE_DIR:-/tmp/claude}"  # cache directory
STATUSLINE_CURRENCY_SYMBOL="${STATUSLINE_CURRENCY_SYMBOL:-$}"  # set to € for Europe
# ────────────────────────────────────────────────────────────────────────────

input=$(cat)

if [ -z "$input" ]; then
    printf "Claude"
    exit 0
fi

# Hard dependency check
if ! command -v jq >/dev/null 2>&1; then
    printf "Claude (install jq for full statusline — brew install jq)"
    exit 0
fi

# ─── ANSI colors ────────────────────────────────────────────────────────────
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;46;149;153m'
red='\033[38;2;255;85;85m'
yellow='\033[38;2;230;200;0m'
white='\033[38;2;220;220;220m'
dim='\033[2m'
reset='\033[0m'

# ─── Helper functions ────────────────────────────────────────────────────────

# ─── Color threshold reference ────────────────────────────────────────────────
# Context window:  green < 50% | yellow 50–75% | red ≥ 75%
# 5h session:      green < 70% | yellow 70–90% | red ≥ 90%
# 7d weekly:       green < 70% | yellow 70–90% | red ≥ 90%
# Extra usage:     green < 50% | yellow 50–80% | red ≥ 80%
# Session cost:    white (informational, no threshold coloring)
# Balance:         white (not available via OAuth API — field not returned)
# ⚡ on 5h/7d:     utilization ≥ 100 (plan limit hit, routing to extra billing)
# ⚡ on extra:     EITHER five_hour OR seven_day utilization ≥ 100
# ─────────────────────────────────────────────────────────────────────────────

# Format token counts: 50000 → "50k", 1200000 → "1.2m"
format_tokens() {
    local num=$1
    if [ "$num" -ge 1000000 ]; then
        awk "BEGIN {printf \"%.1fm\", $num / 1000000}"
    elif [ "$num" -ge 1000 ]; then
        awk "BEGIN {printf \"%.0fk\", $num / 1000}"
    else
        printf "%d" "$num"
    fi
}

# Color for plan limits (session / weekly): green < 70%, yellow 70-90%, red ≥ 90%
plan_color() {
    local pct=$1
    if   [ "$pct" -ge 90 ]; then echo "$red"
    elif [ "$pct" -ge 70 ]; then echo "$yellow"
    else echo "$green"
    fi
}

# Color for context window: green < 50%, yellow 50-75%, red ≥ 75%
context_color() {
    local pct=$1
    if   [ "$pct" -ge 75 ]; then echo "$red"
    elif [ "$pct" -ge 50 ]; then echo "$yellow"
    else echo "$green"
    fi
}

# Color for extra usage spend: green < 50%, yellow 50-80%, red ≥ 80%
extra_color() {
    local pct=$1
    if   [ "$pct" -ge 80 ]; then echo "$red"
    elif [ "$pct" -ge 50 ]; then echo "$yellow"
    else echo "$green"
    fi
}

# Resolve OAuth token — tries 4 sources in order
get_oauth_token() {
    # 1. Explicit env var override
    if [ -n "$CLAUDE_CODE_OAUTH_TOKEN" ]; then
        echo "$CLAUDE_CODE_OAUTH_TOKEN"
        return 0
    fi

    # 2. macOS Keychain
    if command -v security >/dev/null 2>&1; then
        local blob
        blob=$(security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null)
        if [ -n "$blob" ]; then
            local token
            token=$(echo "$blob" | jq -r '.claudeAiOauth.accessToken // empty' 2>/dev/null)
            if [ -n "$token" ] && [ "$token" != "null" ]; then
                echo "$token"; return 0
            fi
        fi
    fi

    # 3. Linux credentials file
    local creds_file="${HOME}/.claude/.credentials.json"
    if [ -f "$creds_file" ]; then
        local token
        token=$(jq -r '.claudeAiOauth.accessToken // empty' "$creds_file" 2>/dev/null)
        if [ -n "$token" ] && [ "$token" != "null" ]; then
            echo "$token"; return 0
        fi
    fi

    # 4. GNOME Keyring via secret-tool
    if command -v secret-tool >/dev/null 2>&1; then
        local blob
        blob=$(timeout 2 secret-tool lookup service "Claude Code-credentials" 2>/dev/null)
        if [ -n "$blob" ]; then
            local token
            token=$(echo "$blob" | jq -r '.claudeAiOauth.accessToken // empty' 2>/dev/null)
            if [ -n "$token" ] && [ "$token" != "null" ]; then
                echo "$token"; return 0
            fi
        fi
    fi

    echo ""
}

# Convert ISO 8601 to Unix epoch (cross-platform: GNU date + BSD date)
iso_to_epoch() {
    local iso_str="$1"

    # GNU date (Linux)
    local epoch
    epoch=$(date -d "${iso_str}" +%s 2>/dev/null)
    [ -n "$epoch" ] && echo "$epoch" && return 0

    # BSD date (macOS)
    local stripped="${iso_str%%.*}"
    stripped="${stripped%%Z}"
    stripped="${stripped%%+*}"
    stripped="${stripped%%-[0-9][0-9]:[0-9][0-9]}"

    if [[ "$iso_str" == *"Z"* ]] || [[ "$iso_str" == *"+00:00"* ]] || [[ "$iso_str" == *"-00:00"* ]]; then
        epoch=$(env TZ=UTC date -j -f "%Y-%m-%dT%H:%M:%S" "$stripped" +%s 2>/dev/null)
    else
        epoch=$(date -j -f "%Y-%m-%dT%H:%M:%S" "$stripped" +%s 2>/dev/null)
    fi

    [ -n "$epoch" ] && echo "$epoch" && return 0
    return 1
}

# Format ISO reset timestamp to compact local time
# Styles: time (4:30pm) | datetime (Mar 6, 4:30pm) | date (Mar 6)
format_reset_time() {
    local iso_str="$1"
    local style="$2"
    [ -z "$iso_str" ] || [ "$iso_str" = "null" ] && return

    local epoch
    epoch=$(iso_to_epoch "$iso_str") || return

    case "$style" in
        time)
            date -j -r "$epoch" +"%l:%M%p" 2>/dev/null | sed 's/^ //' | tr '[:upper:]' '[:lower:]' || \
            date -d "@$epoch" +"%l:%M%P" 2>/dev/null | sed 's/^ //'
            ;;
        datetime)
            date -j -r "$epoch" +"%b %-d, %l:%M%p" 2>/dev/null | sed 's/  / /g; s/^ //' | tr '[:upper:]' '[:lower:]' || \
            date -d "@$epoch" +"%b %-d, %l:%M%P" 2>/dev/null | sed 's/  / /g; s/^ //'
            ;;
        *)
            date -j -r "$epoch" +"%b %-d" 2>/dev/null | tr '[:upper:]' '[:lower:]' || \
            date -d "@$epoch" +"%b %-d" 2>/dev/null
            ;;
    esac
}

# Format time remaining until reset: epoch → "in 2h 24min", "in 47min", "soon"
format_countdown() {
    local iso_str="$1"
    [ -z "$iso_str" ] || [ "$iso_str" = "null" ] && return

    local epoch
    epoch=$(iso_to_epoch "$iso_str") || return

    local now diff hours mins
    now=$(date +%s)
    diff=$(( epoch - now ))

    [ "$diff" -le 0 ] && echo "soon" && return

    hours=$(( diff / 3600 ))
    mins=$(( (diff % 3600) / 60 ))

    if   [ "$hours" -ge 24 ]; then echo "resets in $(( hours / 24 ))d"
    elif [ "$hours" -ge 1 ];  then echo "resets in ${hours}h ${mins}min"
    else echo "resets in ${mins}min"
    fi
}

# ─── Parse stdin JSON ────────────────────────────────────────────────────────
model_name=$(echo "$input" | jq -r '.model.display_name // "Claude"')
cwd=$(echo "$input" | jq -r '.cwd // empty')

size=$(echo "$input" | jq -r '.context_window.context_window_size // 200000')
[ "$size" -eq 0 ] 2>/dev/null && size=200000

input_tokens=$(echo "$input" | jq -r '.context_window.current_usage.input_tokens // 0')
cache_create=$(echo "$input" | jq -r '.context_window.current_usage.cache_creation_input_tokens // 0')
cache_read=$(echo "$input"   | jq -r '.context_window.current_usage.cache_read_input_tokens // 0')
current=$(( input_tokens + cache_create + cache_read ))

used_tokens=$(format_tokens "$current")
total_tokens=$(format_tokens "$size")

# Prefer stdin pre-calculated percentage; fall back to manual integer division
pct_used_stdin=$(echo "$input" | jq -r '.context_window.used_percentage // empty')
if [ -n "$pct_used_stdin" ] && [ "$pct_used_stdin" != "null" ]; then
    pct_used=$(printf "%.0f" "$pct_used_stdin" 2>/dev/null || echo 0)
else
    pct_used=$(( size > 0 ? current * 100 / size : 0 ))
fi

# Session cost from stdin (no API call needed)
session_cost=$(echo "$input" | jq -r '.cost.total_cost_usd // 0')

# Worktree info from stdin (more accurate than git-dir path heuristic)
wt_name=$(echo "$input" | jq -r '.worktree.name // empty')

# ─── Fetch / cache usage API ─────────────────────────────────────────────────
cache_file="${STATUSLINE_CACHE_DIR}/statusline-usage-cache.json"
attempt_stamp="${STATUSLINE_CACHE_DIR}/statusline-fetch-attempt"
ratelimit_stamp="${STATUSLINE_CACHE_DIR}/statusline-ratelimited"
lock_dir="${STATUSLINE_CACHE_DIR}/statusline-fetch.lock"
mkdir -p "${STATUSLINE_CACHE_DIR}"

now=$(date +%s)
usage_data=""

# Always load valid cached data for display (even if stale — shown while refreshing)
if [ -f "$cache_file" ]; then
    cached=$(cat "$cache_file" 2>/dev/null)
    echo "$cached" | jq -e '.five_hour' >/dev/null 2>&1 && usage_data="$cached"
fi

# Exponential backoff for rate limits: 30s → 60s → 120s → 240s → 300s (capped)
# Count of consecutive 429s is stored in the ratelimit_stamp file content.
rl_count=0
ratelimited=false
if [ -f "$ratelimit_stamp" ]; then
    rl_count=$(cat "$ratelimit_stamp" 2>/dev/null | tr -d '[:space:]')
    [[ "$rl_count" =~ ^[0-9]+$ ]] || rl_count=1
    [ "$rl_count" -lt 1 ] && rl_count=1
    rl_mtime=$(_stat_mtime "$ratelimit_stamp" || echo 0)
    rl_backoff=$(( 30 * (1 << (rl_count - 1)) ))   # 30 * 2^(n-1)
    [ "$rl_backoff" -gt 300 ] && rl_backoff=300     # cap at 5 min
    [ $(( now - rl_mtime )) -lt "$rl_backoff" ] && ratelimited=true
fi

# Throttle fetches: only attempt once per TTL period regardless of success/failure
needs_refresh=false
if ! $ratelimited; then
    needs_refresh=true
    if [ -f "$attempt_stamp" ]; then
        stamp_mtime=$(_stat_mtime "$attempt_stamp" || echo 0)
        [ $(( now - stamp_mtime )) -lt "$STATUSLINE_CACHE_TTL" ] && needs_refresh=false
    fi
fi

if $needs_refresh; then
    # Atomic lock: mkdir is POSIX-atomic — only one session fetches at a time
    # If mkdir fails, check for stale lock (crashed holder) and retry once
    got_lock=false
    if mkdir "$lock_dir" 2>/dev/null; then
        got_lock=true
    else
        lock_mtime=$(_stat_mtime "$lock_dir" || echo 0)
        if [ $(( now - lock_mtime )) -gt 30 ]; then
            rmdir "$lock_dir" 2>/dev/null && mkdir "$lock_dir" 2>/dev/null && got_lock=true
        fi
    fi
    if $got_lock; then
        trap 'rmdir "$lock_dir" 2>/dev/null' INT TERM EXIT
        touch "$attempt_stamp"
        token=$(get_oauth_token)
        if [ -n "$token" ] && [ "$token" != "null" ]; then
            response=$(curl -s --max-time 8 \
                -H "Accept: application/json" \
                -H "Content-Type: application/json" \
                -H "Authorization: Bearer $token" \
                -H "anthropic-beta: oauth-2025-04-20" \
                -H "User-Agent: claude-code-statusline/1.0.0" \
                "https://api.anthropic.com/api/oauth/usage" 2>/dev/null)
            if [ -n "$response" ] && echo "$response" | jq -e '.five_hour' >/dev/null 2>&1; then
                usage_data="$response"
                echo "$response" > "$cache_file"
                rm -f "$ratelimit_stamp"  # success — reset backoff
            elif echo "$response" | jq -e '.error.type == "rate_limit_error"' >/dev/null 2>&1; then
                echo $(( rl_count + 1 )) > "$ratelimit_stamp"  # increment backoff counter
            fi
        fi
        rmdir "$lock_dir" 2>/dev/null
        trap - INT TERM EXIT
    fi
    # If mkdir failed, another session holds the lock — silently use cached data
fi

# ─── Build output ────────────────────────────────────────────────────────────
sep=" ${dim}|${reset} "
out1=""  # stdin-based: model, git, ctx, cost  (always available, per-session)
out2=""  # API-based:   5h, 7d, extra          (cached, shared across tabs)

# Append to out2 with auto-separator
append2() { [ -n "$out2" ] && out2+="$sep"; out2+="$1"; }

# Model name
out1+="${blue}${model_name}${reset}"

# Git: project[wt]@branch +adds/-dels
if [ "${STATUSLINE_SHOW_GIT}" = "true" ] && [ -n "$cwd" ]; then
    display_dir="${cwd##*/}"
    git_branch=$(git -C "${cwd}" rev-parse --abbrev-ref HEAD 2>/dev/null)
    out1+="${sep}${cyan}${display_dir}${reset}"
    if [ -n "$git_branch" ]; then
        # Worktree detection: prefer stdin worktree.name (accurate); fallback to git-dir path heuristic
        if [ -n "$wt_name" ]; then
            out1+="${dim}[wt:${wt_name}]${reset}"
        else
            git_dir=$(git -C "${cwd}" rev-parse --git-dir 2>/dev/null)
            [[ "$git_dir" == *"/worktrees/"* ]] && out1+="${dim}[wt]${reset}"
        fi
        out1+="${dim}@${reset}${green}${git_branch}${reset}"
        # Use HEAD diff to include both staged and unstaged changes
        git_stat=$(git -C "${cwd}" diff HEAD --numstat 2>/dev/null | awk '{a+=$1; d+=$2} END {if (a+d>0) printf "+%d -%d", a, d}')
        if [ -n "$git_stat" ]; then
            adds="${git_stat%% *}"
            dels="${git_stat##* }"
            out1+=" ${dim}(${reset}${green}${adds}${reset} ${red}${dels}${reset}${dim})${reset}"
        fi
    fi
fi

# Context window
if [ "${STATUSLINE_SHOW_CONTEXT}" = "true" ]; then
    ctx_color=$(context_color "$pct_used")
    out1+="${sep}${white}ctx${reset} ${orange}${used_tokens}/${total_tokens}${reset} ${dim}(${reset}${ctx_color}${pct_used}%${reset}${dim})${reset}"
fi

# Session cost (from stdin, no API call)
if [ "${STATUSLINE_SHOW_SESSION_COST}" = "true" ]; then
    cost_fmt=$(printf "%.2f" "$session_cost" 2>/dev/null || echo "0.00")
    sym="${STATUSLINE_CURRENCY_SYMBOL}"
    out1+="${sep}${white}cost ${sym}${cost_fmt}${reset}"
fi

# Usage limits from API
if [ -n "$usage_data" ]; then

    five_pct=$(echo "$usage_data" | jq -r '.five_hour.utilization // 0' | awk '{printf "%.0f", $1}')
    five_reset_iso=$(echo "$usage_data" | jq -r '.five_hour.resets_at // empty')
    seven_pct=$(echo "$usage_data" | jq -r '.seven_day.utilization // 0' | awk '{printf "%.0f", $1}')
    seven_reset_iso=$(echo "$usage_data" | jq -r '.seven_day.resets_at // empty')

    # ⚡ fires on whichever limit is currently causing overflow (real-time signal)
    five_on_extra=false
    seven_on_extra=false
    [ "$five_pct" -ge 100 ] && five_on_extra=true
    [ "$seven_pct" -ge 100 ] && seven_on_extra=true

    # 5-hour session limit
    if [ "${STATUSLINE_SHOW_SESSION}" = "true" ]; then
        five_color=$(plan_color "$five_pct")
        five_label="5h"
        $five_on_extra && five_label="⚡ 5h"

        seg="${white}${five_label}${reset} ${five_color}${five_pct}%${reset}"
        if $five_on_extra; then
            five_countdown=$(format_countdown "$five_reset_iso")
            [ -n "$five_countdown" ] && seg+=" ${dim}${five_countdown}${reset}"
        else
            five_reset=$(format_reset_time "$five_reset_iso" "time")
            [ -n "$five_reset" ] && seg+=" ${dim}@${five_reset}${reset}"
        fi
        append2 "$seg"
    fi

    # 7-day weekly limit
    if [ "${STATUSLINE_SHOW_WEEKLY}" = "true" ]; then
        seven_color=$(plan_color "$seven_pct")
        seven_label="7d"
        $seven_on_extra && seven_label="⚡ 7d"

        seg="${white}${seven_label}${reset} ${seven_color}${seven_pct}%${reset}"
        if $seven_on_extra; then
            seven_countdown=$(format_countdown "$seven_reset_iso")
            [ -n "$seven_countdown" ] && seg+=" ${dim}${seven_countdown}${reset}"
        else
            seven_reset=$(format_reset_time "$seven_reset_iso" "datetime")
            [ -n "$seven_reset" ] && seg+=" ${dim}@${seven_reset}${reset}"
        fi
        append2 "$seg"
    fi

    # Extra usage — monthly billing summary (shown when extra is enabled)
    if [ "${STATUSLINE_SHOW_EXTRA}" = "true" ]; then
        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' | awk '{printf "%.0f", $1}')
            extra_used=$(echo "$usage_data" | jq -r '.extra_usage.used_credits // 0' | awk '{printf "%.2f", $1/100}')
            extra_limit=$(echo "$usage_data" | jq -r '.extra_usage.monthly_limit // 0' | awk '{printf "%.2f", $1/100}')
            extra_clr=$(extra_color "$extra_pct")

            sym="${STATUSLINE_CURRENCY_SYMBOL}"
            extra_cap_left=$(echo "$usage_data" | jq -r '((.extra_usage.monthly_limit // 0) - (.extra_usage.used_credits // 0)) / 100' | awk '{printf "%.2f", $1}')

            extra_label="extra"
            { $five_on_extra || $seven_on_extra; } && extra_label="extra ⚡"
            seg="${white}${extra_label}${reset} ${extra_clr}${sym}${extra_used}/${sym}${extra_limit}${reset}"
            seg+=" ${dim}(${reset}${white}${sym}${extra_cap_left} left${reset}${dim})${reset}"
            append2 "$seg"
        fi
    fi
fi

# When rate-limited with no cached data, show a dim indicator instead of silence
# Only if at least one API section is enabled (otherwise out2 is empty by design)
if [ -z "$out2" ] && $ratelimited; then
    if [ "${STATUSLINE_SHOW_SESSION}" = "true" ] || [ "${STATUSLINE_SHOW_WEEKLY}" = "true" ] || [ "${STATUSLINE_SHOW_EXTRA}" = "true" ]; then
        append2 "${dim}limits unavailable (rate limited)${reset}"
    fi
fi

# ─── Render ──────────────────────────────────────────────────────────────────
if [ "${STATUSLINE_SPLIT_LINES}" = "true" ] && [ -n "$out2" ]; then
    printf "%b\n%b" "$out1" "$out2"
else
    [ -n "$out2" ] && out1+="${sep}${out2}"
    printf "%b" "$out1"
fi
exit 0

What it shows

  • Model display name
  • Current directory name (last path component of the working directory)
  • Current git branch
  • Worktree tag [wt:name] when the session runs in a git worktree
  • Uncommitted line changes against HEAD as +added -deleted counts
  • Context window usage as used/total tokens (formatted as k or m) plus a color-coded percentage
  • Session cost from Claude Code, formatted to two decimals with a configurable currency symbol
  • 5-hour plan limit utilization percentage with its reset time, fetched from the Anthropic OAuth usage API
  • 7-day plan limit utilization percentage with its reset date and time, from the same API
  • Extra-usage spending as dollars used / monthly limit and dollars remaining, when extra usage is enabled on the account
  • A ⚡ marker on the 5h, 7d, and extra segments when a plan limit reaches 100%, with a countdown to the reset instead of a clock time
  • A dim 'limits unavailable (rate limited)' notice when the API is rate limited and no cached data exists

Requirements

  • Bash
  • jq is a hard dependency; without it the script prints only a fallback message
  • curl for fetching the Anthropic usage API
  • git for branch, worktree, and diff information
  • Standard Unix tools: awk, date, stat, sed, tr, and mkdir (works with both GNU and BSD stat/date)
  • Network access to api.anthropic.com for the plan limit and extra-usage segments
  • A Claude OAuth token, resolved from the CLAUDE_CODE_OAUTH_TOKEN env var, the macOS Keychain, ~/.claude/.credentials.json, or GNOME Keyring via secret-tool
  • A writable cache directory, /tmp/claude by default
  • A terminal supporting 24-bit ANSI color; no special fonts beyond the ⚡ character

Behavior notes

  • With empty stdin the script prints just 'Claude' and exits
  • In a non-git directory only the directory name is shown, with no branch, as in the scratch-directory scenario
  • The +adds/-dels diff counts appear only when the working tree has uncommitted changes, as in the dirty feature-branch scenario
  • The worktree scenario adds a [wt:feature] tag between the directory name and the branch, taken from the worktree.name field on stdin
  • The context percentage color shifts with usage: green below 50% (22%, 37%, 48%), yellow at 50-75% (64%), red at 75% and above (91%)
  • When current_usage is null, as in the brand-new and post-compact scenarios, context renders as 0/200k (0%)
  • The context total adapts to the model's window size, showing 640k/1.0m in the 1M-context scenario
  • The 5h, 7d, and extra segments come only from the cached OAuth usage API response, not from the rate_limits field on stdin; in all rendered previews these segments are absent because no API data was available
  • The script prefers the pre-calculated used_percentage from stdin and falls back to computing it from token counts
  • API responses are cached (60 seconds by default) and shared across sessions via a lock directory, with exponential backoff after rate-limit errors
  • STATUSLINE_SHOW_* environment variables hide individual segments, and STATUSLINE_SPLIT_LINES=true moves the API-based segments to a second line

More status lines

app · main · Opus-4.8 · effort high · ctx 22% · 5h 26% ↻2h6m · 7d 7% ↻2d0h
Opus 4.8 | main | ██░░░░░░░░ 22.0% | 44k / 200k | 02:07 26% | Wed 7%
Opus 4.8 main app 44k/200k $0.41
app ⏱ 10m +128 -34 ░░░░░░░ 22% $0.41 ◆ Opus
󰚩 Opus 4.8󰍛 ▰▰▰▰▱▱▱▱▱▱▱▱▱▱▱▱ 22%󰄉 $0.41 󰝰 app󰘬 main
Opus 4.8 high ctx 22% app (main) PR #1287 $0.41 · 10m +128 -34 Session 74% left Resets in 2h 7m Weekly 93% left Resets in 2d 1h ◐ Read:index.ts ✓ Read×1 ✓ Bash×1 ✓ Edit×1 ✓ Grep×1 ◐ code-reviewer Review the change for regressions

New to Claude Code status lines? Read the setup guide.