Zum Inhalt springen
cd ..

Meine Claude Code Status Line

Datum
Lesezeit
5 min

Kontext-Auslastung, Kosten, Git-Status – das sind Dinge, die man beim Arbeiten mit Claude Code immer mal wieder wissen will, ohne extra nachfragen zu müssen. Die Statuszeile zeigt das permanent am unteren Terminalrand. Nach jeder Antwort führt Claude Code ein Shell-Script aus, das JSON-Sitzungsdaten via stdin bekommt und ausgibt was man sehen will.

So sieht meine Statuszeile aus:

[Claude Sonnet 4.6]  my-project |main ~2 | +41 -7
▓▓▓░░░░░░░ 31% ctx | $0.042 | ⧗ 3m 12s | 5h: 37% 7d: 23% | in:12k out:3.2k | cache w:8k r:21k

Das Script liegt unter ~/.claude/statusline.sh, eingetragen in ~/.claude/settings.json:

{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.sh"
  }
}

##Zeile 1 – Modell, Verzeichnis, Git

[Claude Sonnet 4.6]  my-project |main ~2 | +41 -7
  • [Claude Sonnet 4.6] – aktives Modell, damit sofort klar ist womit man gerade arbeitet
  • my-project – nur der letzte Teil des aktuellen Verzeichnispfads, kein volles /home/...
  • ⑂ main ~2 – Git-Branch; +N für gestagete, ~N für modifizierte Dateien
  • +41 -7 – Lines added/removed der gesamten Sitzung, nicht nur des letzten Commits

Git-Daten werden 10 Sekunden gecacht (/tmp/claude-statusline-git-cache). Claude Code führt das Script nach jeder Antwort aus – ohne Cache würde jedes git-Kommando spürbare Verzögerung erzeugen.

##Zeile 2 – Kontext, Kosten, Token

▓▓▓░░░░░░░ 31% ctx | $0.042 | ⧗ 3m 12s | 5h: 37% 7d: 23% | in:12k out:3.2k | cache w:8k r:21k
  • ▓▓▓░░░░░░░ 31% ctx – Kontextbalken (10 Zeichen) mit Prozentzahl; grün unter 50 %, gelb bis 75 %, rot darüber
  • $0.042 – bisherige Kosten der Sitzung in USD
  • ⧗ 3m 12s – Gesamtlaufzeit der Sitzung
  • 5h: 37% 7d: 23% – Auslastung der Rate Limits über 5 Stunden und 7 Tage; nur bei Claude.ai Pro/Max verfügbar
  • in:12k out:3.2k – Input- und Output-Token des aktuellen Requests, kompakt formatiert (z. B. 1200 → 1.2k)
  • cache w:8k r:21k – geschriebene und gelesene Cache-Token; hohe Cache-Reads sind gut, weil gecachte Token deutlich weniger kosten

##Das vollständige Script

#!/bin/bash

input=$(cat)

# --- model & session ---
MODEL=$(echo "$input"       | jq -r '.model.display_name // "Claude"')
DIR=$(echo "$input"         | jq -r '.workspace.current_dir // ""')
DIR_NAME="${DIR##*/}"
COST=$(echo "$input"        | jq -r '.cost.total_cost_usd // 0')
DURATION_MS=$(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')

# --- context window ---
PCT_RAW=$(echo "$input"     | jq -r '.context_window.used_percentage // 0')
PCT=$(echo "$PCT_RAW"       | cut -d. -f1)
IN_TOKENS=$(echo "$input"   | jq -r '.context_window.current_usage.input_tokens // empty')
OUT_TOKENS=$(echo "$input"  | jq -r '.context_window.current_usage.output_tokens // empty')
CACHE_W=$(echo "$input"     | jq -r '.context_window.current_usage.cache_creation_input_tokens // empty')
CACHE_R=$(echo "$input"     | jq -r '.context_window.current_usage.cache_read_input_tokens // empty')

# --- rate limits ---
FIVE_H=$(echo "$input"      | jq -r '.rate_limits.five_hour.used_percentage // empty')
SEVEN_D=$(echo "$input"     | jq -r '.rate_limits.seven_day.used_percentage // empty')

# --- colors ---
GREEN='\033[32m'  YELLOW='\033[33m'  RED='\033[31m'
CYAN='\033[36m'   BOLD='\033[1m'     DIM='\033[2m'
RESET='\033[0m'

# compact token format: 1234 -> 1.2k, 12345 -> 12k
fmt_tok() {
    local n="$1"
    [ -z "$n" ] || [ "$n" = "0" ] && { echo "0"; return; }
    if [ "$n" -ge 1000 ]; then
        local k=$(( n / 1000 )) r=$(( (n % 1000) / 100 ))
        [ "$r" -gt 0 ] && [ "$k" -lt 10 ] && echo "${k}.${r}k" || echo "${k}k"
    else
        echo "$n"
    fi
}

# --- git (cached 10s) ---
CACHE_FILE="/tmp/claude-statusline-git-cache"

if [ ! -f "$CACHE_FILE" ] || \
   [ $(( $(date +%s) - $(stat -c %Y "$CACHE_FILE" 2>/dev/null || echo 0) )) -gt 10 ]; then
    if git -C "${DIR:-.}" rev-parse --git-dir > /dev/null 2>&1; then
        BRANCH=$(git -C "${DIR:-.}" branch --show-current 2>/dev/null)
        STAGED=$(git -C "${DIR:-.}" diff --cached --numstat 2>/dev/null | wc -l | tr -d ' ')
        MODIFIED=$(git -C "${DIR:-.}" diff --numstat 2>/dev/null | wc -l | tr -d ' ')
        printf '%s|%s|%s' "$BRANCH" "$STAGED" "$MODIFIED" > "$CACHE_FILE"
    else
        printf '||' > "$CACHE_FILE"
    fi
fi
IFS='|' read -r BRANCH STAGED MODIFIED < "$CACHE_FILE"

# --- line 1: model · dir · git · lines ---
LINE1="${BOLD}${CYAN}[${MODEL}]${RESET} ${DIM}${RESET} ${DIR_NAME}"

if [ -n "$BRANCH" ]; then
    GIT_PART="${DIM}|${RESET}${GREEN}${BRANCH}${RESET}"
    [ "${STAGED:-0}"   -gt 0 ] && GIT_PART="${GIT_PART} ${GREEN}+${STAGED}${RESET}"
    [ "${MODIFIED:-0}" -gt 0 ] && GIT_PART="${GIT_PART} ${YELLOW}~${MODIFIED}${RESET}"
    LINE1="${LINE1} ${GIT_PART}"
fi

if [ "${LINES_ADDED:-0}" -gt 0 ] || [ "${LINES_REMOVED:-0}" -gt 0 ]; then
    LINE1="${LINE1} ${DIM}|${RESET} ${GREEN}+${LINES_ADDED}${RESET} ${RED}-${LINES_REMOVED}${RESET}"
fi

# --- line 2: ctx bar · cost · time · tokens ---
if   [ "${PCT:-0}" -ge 75 ]; then BAR_COLOR="$RED"
elif [ "${PCT:-0}" -ge 50 ]; 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=""
for ((i=0; i<FILLED; i++)); do BAR="${BAR}▓"; done
for ((i=0; i<EMPTY;  i++)); do BAR="${BAR}░"; done

COST_FMT=$(LC_NUMERIC=C printf '$%.3f' "$COST")
MINS=$(( DURATION_MS / 60000 ))
SECS=$(( (DURATION_MS % 60000) / 1000 ))

LINE2="${BAR_COLOR}${BAR}${RESET} ${PCT}% ctx ${DIM}|${RESET} ${YELLOW}${COST_FMT}${RESET} ${DIM}|${RESET}${MINS}m ${SECS}s"

if [ -n "$FIVE_H" ] || [ -n "$SEVEN_D" ]; then
    RATE="${DIM}|${RESET}"
    [ -n "$FIVE_H"  ] && RATE="${RATE} 5h: $(LC_NUMERIC=C printf '%.0f' "$FIVE_H")%"
    [ -n "$SEVEN_D" ] && RATE="${RATE} 7d: $(LC_NUMERIC=C printf '%.0f' "$SEVEN_D")%"
    LINE2="${LINE2} ${RATE}"
fi

if [ -n "$IN_TOKENS" ]; then
    TOKEN_PART="${DIM}|${RESET} in:$(fmt_tok "$IN_TOKENS") out:${CYAN}$(fmt_tok "$OUT_TOKENS")${RESET}"
    TOKEN_PART="${TOKEN_PART} ${DIM}| cache${RESET} w:$(fmt_tok "$CACHE_W") r:${GREEN}$(fmt_tok "$CACHE_R")${RESET}"
    LINE2="${LINE2} ${TOKEN_PART}"
fi

printf '%b\n%b\n' "$LINE1" "$LINE2"

##Fazit

Das Script ist ein Ausgangspunkt. Was hier gezeigt ist funktioniert für mich – wer andere Felder braucht, andere Farben will oder einfach weniger Informationen möchte, passt es an. Die verfügbaren JSON-Felder sind im Script dokumentiert, der Rest ist Shell.