Nerd Font Duo

GitTokensCostLimitsMulti-LineBashNetwork AccessReads Token

Two Nerd Font lines: model, a 16-segment context bar, cost and quotas on top; directory, git counts, Python venv and vim mode below.

MIT licensed · original source

0 copies

Using the Claude desktop app? Add your status line with statusline-anywhere.

Preview

Clean repo
󰚩 Opus 4.8 │ 󰍛 ▰▰▰▰▱▱▱▱▱▱▱▱▱▱▱▱ 22% │ 󰄉 $0.41 󰝰 app │ 󰘬 main
New session
󰚩 Opus 4.8 │ 󰍛 ▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱ 0% │ 󰄉 $0.00 󰝰 app │ 󰘬 main
Dirty branch
󰚩 Sonnet 4.6 │ 󰍛 ▰▰▰▰▰▰▰▰▱▱▱▱▱▱▱▱ 48% │ 󰄉 $0.41 󰝰 app │ 󰘬 feat/auth ~1 ?1 │ 󰕷 INSERT
Near-full
CTX 91% 󰚩 Opus 4.8 │ ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▱ │ 󰄉 $4.12 󰝰 app │ 󰘬 main │ 󰕷 VISUAL
1M context
󰚩 Fable 5 │ 󰍛 ▰▰▰▰▰▰▰▰▰▰▱▱▱▱▱▱ 64% │ 󰄉 $0.41 󰝰 app │ 󰘬 main
Post-compact
󰚩 Haiku 4.5 │ 󰍛 ▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱ 0% │ 󰄉 $0.41 󰝰 app │ 󰘬 main │ 󰕷 NORMAL
Worktree
󰚩 Opus 4.8 │ 󰍛 ▰▰▰▰▰▰▱▱▱▱▱▱▱▱▱▱ 37% │ 󰄉 $0.41 󰝰 feature │ 󰘬 worktree-feature │ 󰕷 VISUAL LINE
Non-git
󰚩 Opus 4.8 │ 󰍛 ▰▰▰▰▱▱▱▱▱▱▱▱▱▱▱▱ 22% │ 󰄉 $0.41 󰝰 scratch

Source

#!/bin/bash

# Claude Code Status Line — Two-line layout with Nerd Font icons (MD range)
# Line 1: Model │ Context Bar (16 segs) │ Cost │ 5h usage │ 7d usage
# Line 2: Directory │ Git Branch & Status │ Venv │ Vim

input=$(< /dev/stdin)
now=$(date +%s)

# --- Extract all values in a single jq call ---
eval "$(jq -r '
    @sh "model=\(.model.display_name // "?")",
    @sh "cwd=\(.workspace.current_dir // ".")",
    @sh "used_pct=\(.context_window.used_percentage // 0)",
    @sh "cost=\(.cost.total_cost_usd // 0)",
    @sh "vim_mode=\(.vim.mode // "")"
' <<< "$input")"

dir_name="${cwd##*/}"

# --- Theme detection ---
# Override with STATUSLINE_THEME=dark|light|auto (default: auto)
detect_theme() {
    local theme="${STATUSLINE_THEME:-auto}"
    if [ "$theme" != "auto" ]; then echo "$theme"; return; fi

    # macOS system appearance
    if defaults read -g AppleInterfaceStyle &>/dev/null; then
        echo "dark"; return
    fi

    # COLORFGBG env var (e.g. "15;0" → bg=0 is dark)
    if [ -n "$COLORFGBG" ]; then
        local bg="${COLORFGBG##*;}"
        if [ "$bg" -lt 8 ] 2>/dev/null; then
            echo "dark"
        else
            echo "light"
        fi
        return
    fi

    echo "dark"
}

THEME=$(detect_theme)

# --- Colors ---
RST=$'\033[0m'
BOLD=$'\033[1m'

if [ "$THEME" = "light" ]; then
    DIM=$'\033[90m'              # bright black (gray) — visible on light bg
    CYAN=$'\033[36m'
    GREEN=$'\033[32m'
    YELLOW=$'\033[33m'
    RED=$'\033[31m'
    MAGENTA=$'\033[35m'
    BLUE=$'\033[34m'
    BG_RED=$'\033[41m'
    WHITE_BOLD=$'\033[1;30m'     # bold black — for alert badge text on light bg
else
    DIM=$'\033[2m'
    CYAN=$'\033[36m'
    GREEN=$'\033[32m'
    YELLOW=$'\033[33m'
    RED=$'\033[31m'
    MAGENTA=$'\033[35m'
    BLUE=$'\033[34m'
    BG_RED=$'\033[41m'
    WHITE_BOLD=$'\033[1;37m'
fi

# --- Nerd Font Icons (all MD range, U+F0000+) ---
ICON_MODEL="󰚩"     # nf-md-robot
ICON_CTX="󰍛"       # nf-md-memory
ICON_DIR="󰝰"       # nf-md-folder_outline
ICON_GIT="󰘬"       # nf-md-source_branch
ICON_COST="󰄉"      # nf-md-cash
ICON_WARN=""       # nf-fa-warning
ICON_VIM="󰕷"       # nf-md-vim
ICON_VENV="󰌠"      # nf-md-language_python

SEP="${DIM} │ ${RST}"
BAR_SEGMENTS=16

# --- Color helper for utilization percentage ---
# Thresholds: green < 50, yellow 50-79, red >= 80
pct_color() {
    local pct=$1
    if [ "$pct" -lt 50 ]; then echo "$GREEN"
    elif [ "$pct" -lt 80 ]; then echo "$YELLOW"
    else echo "$RED"
    fi
}

# --- Context percentage ---
pct_int=${used_pct%.*}
pct_int=${pct_int:-0}
CTX_COLOR=$(pct_color "$pct_int")

# --- Progress bar ---
filled=$(( (pct_int * BAR_SEGMENTS + 50) / 100 ))
[ "$filled" -gt "$BAR_SEGMENTS" ] && filled=$BAR_SEGMENTS
empty=$((BAR_SEGMENTS - filled))
bar=""
for ((i = 0; i < filled; i++)); do bar="${bar}▰"; done
for ((i = 0; i < empty; i++)); do bar="${bar}▱"; done

# --- Cost ---
printf -v cost_str '$%.2f' "$cost"

# --- Git info (single git status --porcelain call) ---
git_info=""
if git -C "$cwd" rev-parse --git-dir > /dev/null 2>&1; then
    branch=$(git -C "$cwd" branch --show-current 2>/dev/null)
    [ -z "$branch" ] && branch="detached"

    staged=0 unstaged=0 untracked=0
    while IFS= read -r line; do
        x=${line:0:1}
        y=${line:1:1}
        if [ "$x$y" = "??" ]; then
            ((untracked++))
        else
            [ "$x" != " " ] && [ "$x" != "?" ] && ((staged++))
            [ "$y" != " " ] && ((unstaged++))
        fi
    done < <(git -C "$cwd" status --porcelain 2>/dev/null)

    status=""
    [ "$staged" -gt 0 ] && status="${status} ${GREEN}+${staged}${RST}"
    [ "$unstaged" -gt 0 ] && status="${status} ${YELLOW}~${unstaged}${RST}"
    [ "$untracked" -gt 0 ] && status="${status} ${DIM}?${untracked}${RST}"

    git_info="${SEP}${MAGENTA}${ICON_GIT} ${branch}${RST}${status}"
fi

# --- Python venv detection ---
venv_str=""
venv_name="" py_ver=""
if [ -n "$VIRTUAL_ENV" ]; then
    venv_name="${VIRTUAL_ENV##*/}"
else
    for venv_dir in "$cwd/.venv" "$cwd/venv" "$cwd/.env"; do
        if [ -f "${venv_dir}/bin/python" ]; then
            venv_name="${venv_dir##*/}"
            py_ver=$("${venv_dir}/bin/python" --version 2>/dev/null | awk '{print $2}' | cut -d. -f1-2)
            break
        fi
    done
fi
if [ -n "$venv_name" ]; then
    venv_str="${SEP}${YELLOW}${ICON_VENV} ${venv_name}${py_ver:+ ($py_ver)}${RST}"
fi

# --- Vim mode ---
vim_str=""
if [ -n "$vim_mode" ]; then
    [[ "$vim_mode" == "NORMAL" ]] && vim_color=$BLUE || vim_color=$GREEN
    vim_str="${SEP}${vim_color}${BOLD}${ICON_VIM} ${vim_mode}${RST}"
fi

# --- Anthropic OAuth usage API (cached, background refresh) ---
CACHE_DIR="$HOME/.claude/statusline-cache"
USAGE_CACHE="$CACHE_DIR/usage.dat"
LOCK_FILE="$CACHE_DIR/usage-update.lock"
CACHE_TTL=60

refresh_usage_cache() {
    if ! mkdir "$LOCK_FILE" 2>/dev/null; then
        lock_age=$(( now - $(stat -f%m "$LOCK_FILE" 2>/dev/null || echo 0) ))
        [ "$lock_age" -gt 60 ] && rm -r "$LOCK_FILE" 2>/dev/null || return
        mkdir "$LOCK_FILE" 2>/dev/null || return
    fi
    (
        # Try macOS Keychain first, then fall back to credentials file
        token=$(security find-generic-password -s "Claude Code-credentials" -a "$(whoami)" -w 2>/dev/null | jq -r '.claudeAiOauth.accessToken // empty' 2>/dev/null)
        [ -z "$token" ] && token=$(jq -r '.claudeAiOauth.accessToken // empty' "$HOME/.claude/.credentials.json" 2>/dev/null)
        if [ -n "$token" ]; then
            resp=$(curl -s --max-time 5 \
                -H "Authorization: Bearer $token" \
                -H "anthropic-beta: oauth-2025-04-20" \
                https://api.anthropic.com/api/oauth/usage 2>/dev/null)
            if echo "$resp" | jq -e '.five_hour' > /dev/null 2>&1; then
                echo "$resp" | jq -r '
                    def to_epoch: split(".")[0] + "Z" | fromdateiso8601;
                    "\(.five_hour.utilization | floor) \(.five_hour.resets_at | to_epoch) \(.seven_day.utilization | floor) \(.seven_day.resets_at | to_epoch)"
                ' > "$USAGE_CACHE.tmp" 2>/dev/null && mv "$USAGE_CACHE.tmp" "$USAGE_CACHE"
            fi
        fi
        rm -r "$LOCK_FILE" 2>/dev/null
    ) &
    disown 2>/dev/null
}

format_countdown() {
    local diff=$(( $1 - now ))
    [ "$diff" -le 0 ] && echo "soon" && return
    if [ "$diff" -ge 86400 ]; then
        echo "$((diff / 86400))d$((diff % 86400 / 3600))h"
    elif [ "$diff" -ge 3600 ]; then
        echo "$((diff / 3600))h$((diff % 3600 / 60))m"
    else
        echo "$((diff / 60))m"
    fi
}

usage_segment() {
    local label=$1 pct=$2 reset_epoch=$3
    local color reset_str
    color=$(pct_color "$pct")
    reset_str=$(format_countdown "$reset_epoch")
    echo "${SEP}${DIM}${label}${RST} ${color}${pct}%${RST} ${DIM}↺ ${reset_str}${RST}"
}

if [ ! -f "$USAGE_CACHE" ]; then
    [ -d "$CACHE_DIR" ] || mkdir -p "$CACHE_DIR" 2>/dev/null
    refresh_usage_cache
else
    cache_age=$(( now - $(stat -f%m "$USAGE_CACHE" 2>/dev/null || echo 0) ))
    [ "$cache_age" -gt "$CACHE_TTL" ] && refresh_usage_cache
fi

usage_5h="" usage_7d=""
if [ -f "$USAGE_CACHE" ]; then
    read -r pct5h epoch5h pct7d epoch7d < "$USAGE_CACHE" 2>/dev/null
    if [ -n "$pct5h" ] && [ "$pct5h" != "-1" ]; then
        usage_5h=$(usage_segment "5h" "$pct5h" "$epoch5h")
    fi
    if [ -n "$pct7d" ] && [ "$pct7d" != "-1" ]; then
        usage_7d=$(usage_segment "7d" "$pct7d" "$epoch7d")
    fi
fi

# --- Build output ---
line1_tail="${SEP}${DIM}${ICON_COST} ${cost_str}${RST}${usage_5h}${usage_7d}"

if [ "$pct_int" -ge 90 ]; then
    line1="${BG_RED}${WHITE_BOLD} ${ICON_WARN} CTX ${pct_int}% ${RST} ${CYAN}${BOLD}${ICON_MODEL} ${model}${RST}${SEP}${CTX_COLOR}${bar}${RST}${line1_tail}"
else
    line1="${CYAN}${BOLD}${ICON_MODEL} ${model}${RST}${SEP}${DIM}${ICON_CTX}${RST} ${CTX_COLOR}${bar} ${pct_int}%${RST}${line1_tail}"
fi

line2="${BLUE}${ICON_DIR} ${dir_name}${RST}${git_info}${venv_str}${vim_str}"

printf '%s\n%s' "$line1" "$line2"

What it shows

  • Model display name with a robot icon
  • Context window usage as a 16-segment progress bar plus a percentage
  • A red warning badge with the context percentage when usage reaches 90% or more
  • Session cost in US dollars, formatted to two decimal places
  • 5-hour and 7-day usage percentages with a countdown to reset, when cached usage data from Anthropic's OAuth usage API is available
  • Current directory name (last path segment only)
  • Git branch name, or 'detached' when no branch is checked out
  • Counts of staged, unstaged, and untracked files in the git repo
  • Python virtual environment name, with the Python version when detected from a local .venv, venv, or .env folder
  • Vim mode (e.g. NORMAL, INSERT) when Claude Code reports one

Requirements

  • Bash
  • jq for parsing the stdin JSON, credentials, and the usage API response
  • git for branch and working-tree status
  • curl for fetching usage data from api.anthropic.com
  • A Nerd Font to render the Material Design icon glyphs
  • macOS-flavored commands: stat -f%m for cache timestamps, plus defaults (theme detection) and security (Keychain token lookup)
  • Network access to api.anthropic.com for the 5h/7d usage segments
  • A Claude OAuth token, read from the macOS Keychain or from ~/.claude/.credentials.json
  • awk and cut for extracting the Python version

Behavior notes

  • When context usage reaches 90%, a red 'CTX 91%' badge replaces the memory icon and inline percentage, and the bar turns red
  • Bar and percentage color follows thresholds: green below 50%, yellow from 50-79% (64% renders yellow), red at 80% or above
  • When used_percentage is null (new session or just after /compact), the bar renders empty at 0%
  • Git file counts only appear when the working tree is dirty; a clean repo shows just the branch name
  • In a non-git directory the entire git segment disappears, leaving only the directory name on line two
  • The vim segment appears only when a vim mode is reported; NORMAL renders blue, other modes render green
  • The branch name comes from running git in the current directory, not from the input JSON
  • The 5h/7d usage segments come from a cached API response rather than the rate_limits field on stdin, and did not appear in any rendered preview
  • The venv segment did not appear in any preview; it shows only when a virtual environment is active or found in the directory
  • Input fields like effort level, thinking, PR details, session name, agent name, and output style vary across scenarios but are not displayed

More status lines

Activity Feed

51 copies

Opus 4.8 high ✦ │ ctx 22% │ app (main) │ PR #1287 ● │ $0.41 · 10m +128 -34 Session ● ● ● ● ● ● ● ● ○ ○ ○ 74% left Resets in 2h 6m Weekly ● ● ● ● ● ● ● ● ● ● ○ 93% left Resets in 2d 0h Fable ● ● ● ● ● ● ● ● ● ○ ○ 85% left Resets in 2d 0h ◐ Read:index.ts ✓ Read×1 ✓ Bash×1 ✓ Edit×1 ✓ Grep×1 ◐ code-reviewer Review the change for regressions
Opus 4.8 │ ✍️ 22% │ app (main) │ ● high current ●●○○○○○○○○ 26% ⟳ 6:59pm weekly ○○○○○○○○○○ 7% ⟳ aug 1, 5:52pm
🌿 main │ Opus 4.8/hi │ 🟢 Ctx ▓▓░░░░ 22% │ ⏳ 🟢 ▓▓░░░░ 26% ↻ 2h7m │ $0.41 ⏱ 10m
Model: Opus 4.8 | Thinking: high | Context: [▰▰▱▱▱▱▱▱▱▱] 45k/200k (22%) | cwd: ~/app | ⎇ main | (+0,-0) Cost: $0.41 | Block: 2hr 6m | Weekly: 7.0% | Session: 10m | In: 916.7 t/s | Out: 29.2 t/s | Cached: 2k | Session: [▰▱▱▱▱] 26.0% Mem: 0.8G/1.0G | (*゚∀゚*) | Session ID: b8e1c0d2-4a6f-4e2a-9c1b-3f5d7a9e2c10
Opus 4.8 | app@main | ctx 44k/200k (22%) | cost $0.41 | 5h 26% | 7d 7%
✧ ███████████▋ 73% 🗝 Ultima Weapon ✦ app ∙ main ♥ ████████████████████████ 100% 「SAVE POINT」 ✶ Limit Form ◉ 41