Status line pro Claude Code
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 informaci, jestli session nepřelezla hranici 200k tokenů.
Co z toho získám
- Aktuální pracovní adresář zkrácený relativně k
$HOME, takže místo celé cesty vidím jen~nebo~/…. - Použitý model a session ID přímo ve status line.
- Využití context window v procentech.
- 5hodinový a 7denní limit, včetně času resetu, pokud je Claude Code pošle v JSONu.
- Rychlý signál, jestli session už překročila hranici 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:<id> │ ctx:23% │ <200k
Když jsou limity v JSONu k dispozici, řádka se rozšíří o 5h a 7d přehled:
~/project-dokuwiki │ Sonnet 4.6 | sid:<id> │ ctx:23% │ 5h:41% ↺ 01:15 │ 7d:68% ↺ Ne 10:00 │ <200k
Barvy jsou rozdělené takto:
- cwd → cyan + bold
- model → magenta
- sid → dim
ctx,5ha7d→ zelená pod 70 %, žlutá od 70 %, červená od 90 %>200k→ červeně a tučně<200k→ 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.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 } # ── exceeds_200k ─────────────────────────────────────────────────────────────── exceeds=$(echo "$input" | jq -r '.exceeds_200k_tokens // false') # ── 3) context used ──────────────────────────────────────────────────────────── ctx_used_pct=$(echo "$input" | jq -r '.context_window.used_percentage // empty') ctx_str="" if [ -n "$ctx_used_pct" ]; then ctx_int=$(printf "%.0f" "$ctx_used_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) exceeds_200k signal if [ "$exceeds" = "true" ]; then parts+=("$(printf "${RED}${BOLD}>200k${RESET}")") else parts+=("$(printf "${DIM}<200k${RESET}")") 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
5ha7dse zobrazí jen když Claude Code skutečně pošlerate_limits. - Funkce
fmt_reset_short()afmt_reset_long()zvládnou jak unix epoch, tak ISO-8601 string. - 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→>200k/<200k.