====== Status line pro Claude Code ======
//Vytvořeno: **** | Aktualizováno: **~~LASTMOD~~**//
[[ai:platformy:claude-code:start|Claude Code]] umí vykreslovat vlastní status line spuštěný jako externí příkaz. Tohle je moje varianta, která drží stabilní pořadí polí a na jeden pohled ukazuje pracovní adresář, model, session ID, využití kontextu, 5h a 7d limity i absolutní spotřebu tokenů context window se zvýrazněním nad hranicí 200k.
===== Co z toho získám =====
* Aktuální pracovní adresář projektu (root, kde byl Claude Code spuštěn) zkrácený relativně k ''$HOME'', takže místo celé cesty vidím jen ''~'' nebo ''~/...''. Adresář se v průběhu session nemění, i když shell přejde do podadresáře.
* Použitý model a session ID přímo ve status line.
* Využití context window v procentech, čtené přímo z předpočítaného pole ''used_percentage''.
* 5hodinový a 7denní limit, včetně času resetu, pokud je Claude Code pošle v JSONu.
* Absolutní spotřebu tokenů context window ve formátu ''XYZk/TOTALk''. Hodnota celkového okna se čte dynamicky, takže funguje i pro 1M context window. Červeně se rozsvítí při překročení 200k tokenů.
* Barevné zvýraznění podle vytížení: zelená pod 70 %, žlutá od 70 %, červená od 90 %.
===== Zapojení do konfigurace =====
V ''~/.claude/settings.json'' mám status line zapojený takto:
"statusLine": {
"type": "command",
"command": "bash /home/ubuntu/.claude/statusline-command.sh"
}
Skript čte JSON ze standardního vstupu, parsuje ho přes ''jq'' a složí z něj jednu barevnou řádku.
===== Jak vypadá výstup =====
Když Claude Code neposílá data o ''rate_limits'', výstup vypadá zhruba takto:
~/scratch │ Sonnet 4.6 | sid: │ ctx:23% │ 92k/400k
Když jsou limity v JSONu k dispozici, řádka se rozšíří o 5h a 7d přehled:
~/project-procesniaudit-website │ Sonnet 4.6 │ ctx:55% │ 5h:4% ↺ 00:50 │ 7d:45% ↺ Po 08:00 │ 220k/400k
Barvy jsou rozdělené takto:
* cwd → cyan + bold
* model → magenta
* sid → dim
* ''ctx'', ''5h'' a ''7d'' → zelená pod 70 %, žlutá od 70 %, červená od 90 %
* token counter ''XYZk/TOTALk'' → červeně a tučně při překročení 200k, jinak dim
===== Celý skript =====
#!/usr/bin/env bash
# Claude Code status line
# Order: cwd | model | context used | 5h limit | 7d limit
input=$(cat)
# ── helpers ────────────────────────────────────────────────────────────────────
RESET='\033[0m'
BOLD='\033[1m'
DIM='\033[2m'
RED='\033[31m'
YELLOW='\033[33m'
GREEN='\033[32m'
CYAN='\033[36m'
MAGENTA='\033[35m'
WHITE='\033[37m'
# ── 1) cwd ─────────────────────────────────────────────────────────────────────
cwd=$(echo "$input" | jq -r '.workspace.project_dir // .workspace.current_dir // .cwd // ""')
# Show path relative to home dir
home_dir="$HOME"
if [[ "$cwd" == "$home_dir" ]]; then
short_cwd="~"
elif [[ "$cwd" == "$home_dir/"* ]]; then
short_cwd="~/${cwd#$home_dir/}"
else
short_cwd="$cwd"
fi
[ "$short_cwd" = "/" ] && short_cwd="/"
# ── 2) model ───────────────────────────────────────────────────────────────────
model_name=$(echo "$input" | jq -r '.model.display_name // .model.id // ""')
session_id=$(echo "$input" | jq -r '.session_id // .conversation_id // empty')
# ── rate limit helpers ─────────────────────────────────────────────────────────
five_pct=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
five_rst=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty')
week_pct=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
week_rst=$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at // empty')
fmt_reset_short() {
local v="$1"
[ -z "$v" ] && return
# Try as epoch first, then as ISO-8601 string
if [[ "$v" =~ ^[0-9]+$ ]]; then
date -d "@$v" +%H:%M 2>/dev/null || date -r "$v" +%H:%M 2>/dev/null || echo "?"
else
date -d "$v" +%H:%M 2>/dev/null || echo "?"
fi
}
fmt_reset_long() {
local v="$1"
[ -z "$v" ] && return
if [[ "$v" =~ ^[0-9]+$ ]]; then
date -d "@$v" +"%a %H:%M" 2>/dev/null || date -r "$v" +"%a %H:%M" 2>/dev/null || echo "?"
else
date -d "$v" +"%a %H:%M" 2>/dev/null || echo "?"
fi
}
# Choose colour based on used %
pct_color_used() {
local used="$1"
[ -z "$used" ] && echo "$WHITE" && return
local u
u=$(printf "%.0f" "$used")
if [ "$u" -ge 90 ]; then echo "$RED"
elif [ "$u" -ge 70 ]; then echo "$YELLOW"
else echo "$GREEN"
fi
}
# ── 3) context used ────────────────────────────────────────────────────────────
ctx_used_tokens=$(echo "$input" | jq -r '.context_window.total_input_tokens // empty')
ctx_window_size=$(echo "$input" | jq -r '.context_window.context_window_size // empty')
ctx_pct=$(echo "$input" | jq -r '.context_window.used_percentage // empty')
ctx_str=""
if [ -n "$ctx_pct" ]; then
ctx_int=$(printf "%.0f" "$ctx_pct")
if [ "$ctx_int" -ge 90 ]; then
ctx_str="$(printf "${RED}${BOLD}ctx:%s%%!${RESET}" "$ctx_int")"
elif [ "$ctx_int" -ge 70 ]; then
ctx_str="$(printf "${YELLOW}ctx:%s%%${RESET}" "$ctx_int")"
else
ctx_str="$(printf "${GREEN}ctx:%s%%${RESET}" "$ctx_int")"
fi
fi
# ── assemble line ──────────────────────────────────────────────────────────────
parts=()
# 1) cwd
parts+=("$(printf "${CYAN}${BOLD}%s${RESET}" "$short_cwd")")
# 2) model + session id
if [ -n "$model_name" ] || [ -n "$session_id" ]; then
parts+=("$(printf "${MAGENTA}%s${RESET}" "$model_name")${session_id:+ $(printf "${DIM}| sid:%s${RESET}" "$session_id")}")
fi
# 3) context used (always shown when data available)
[ -n "$ctx_str" ] && parts+=("$ctx_str")
# 4) 5h rate limit (only when data is available)
if [ -n "$five_pct" ]; then
five_int=$(printf "%.0f" "$five_pct")
col=$(pct_color_used "$five_pct")
rst=$(fmt_reset_short "$five_rst")
parts+=("$(printf "${col}5h:%s%%%s${RESET}" "$five_int" "${rst:+ ↺ $rst}")")
fi
# 5) 7d rate limit (only when data is available)
if [ -n "$week_pct" ]; then
week_int=$(printf "%.0f" "$week_pct")
col=$(pct_color_used "$week_pct")
rst=$(fmt_reset_long "$week_rst")
parts+=("$(printf "${col}7d:%s%%%s${RESET}" "$week_int" "${rst:+ ↺ $rst}")")
fi
# 6) token counter — červeně od 200k
if [ -n "$ctx_used_tokens" ] && [ -n "$ctx_window_size" ] && [ "$ctx_window_size" -gt 0 ]; then
ctx_used_k=$(python3 -c "print(round($ctx_used_tokens / 1000))")
ctx_total_k=$(python3 -c "print(round($ctx_window_size / 1000))")
if [ "$ctx_used_tokens" -gt 200000 ]; then
parts+=("$(printf "${RED}${BOLD}%sk/%sk${RESET}" "$ctx_used_k" "$ctx_total_k")")
else
parts+=("$(printf "${DIM}%sk/%sk${RESET}" "$ctx_used_k" "$ctx_total_k")")
fi
fi
# ── print ──────────────────────────────────────────────────────────────────────
# Join with separator " │ "
sep="$(printf "${DIM} │ ${RESET}")"
out=""
for p in "${parts[@]}"; do
[ -z "$out" ] && out="$p" || out="${out}${sep}${p}"
done
printf "%b\n" "$out"
===== Poznámky k chování =====
* Pole ''5h'' a ''7d'' se zobrazí jen když Claude Code skutečně pošle ''rate_limits''.
* Funkce ''fmt_reset_short()'' a ''fmt_reset_long()'' zvládnou jak unix epoch, tak ISO-8601 string.
* Pro cwd se primárně čte ''.workspace.project_dir'' — pole, které Claude Code nastavuje na root projektu (kde byl spuštěn) a nemění se v průběhu session, i když shell přejde do podadresáře. Pole ''.workspace.current_dir'' a ''.cwd'' jsou jen fallback.
* Procento využití context window se čte přímo z ''context_window.used_percentage'' — předpočítané pole, které Claude Code posílá od verze 2.1.132. Pokrývá vstupní tokeny včetně cache: ''used_percentage'' = (''input_tokens'' + ''cache_creation_input_tokens'' + ''cache_read_input_tokens'') / ''context_window_size''. Výstupní tokeny do procenta nezahrnuje, ale ani do ''XYZk'' v token counteru (tam se čte ''total_input_tokens'', které je součtem stejných tří složek).
* ''total_input_tokens'' zahrnuje všechny vstupní tokeny včetně cache a od v2.1.132 reprezentuje aktuální stav context window, nikoli kumulativní součet přes celou session.
* Skript záměrně nepoužívá příznak ''exceeds_200k_tokens'' — ten vychází z tokenů aktuálního API volání (input + output + cache) a má pevnou hranici 200k bez ohledu na skutečnou velikost okna. Místo toho skript ukazuje aktuální stav v segmentu ''XYZk/TOTALk''.
* Když některé pole v JSONu chybí, skript se nerozbije a prostě ho přeskočí.
* Pořadí polí je pevné: ''cwd'' → ''model + sid'' → ''ctx'' → ''5h'' → ''7d'' → ''XYZk/TOTALk''.
===== Zdroje =====
* [[https://code.claude.com/docs/en/statusline|Claude Code – Customize your status line (oficiální dokumentace)]]