← blog

Pasek stanu Claude Code: widzę, kiedy mogę cisnąć limity

Pasek stanu Claude Code, który pokazuje limity 5h i 7d na tle upływu czasu, stan cache i kontekst. Skrypt do skopiowania, 15 minut roboty.

#claude @Claude Code #productivity #tutorial
P
▸ // spis treści

Limit 5h w Claude Code nie mówi ci, czy pracujesz za szybko. Mówi tylko, ile już zużyłeś. Dołożyłem do paska stanu jedną kreskę, która pokazuje, ile czasu z okna minęło, i od razu widzę, czy mogę przycisnąć, czy lepiej zwolnić.

Zajęło mi to 15 minut, a pasek mam przed oczami przy każdej wiadomości.

Z tego artykułu dowiesz się:


Problem

Goła liczba „32% limitu 5h" nic nie znaczy. Po 4 godzinach okna to świetny wynik. Po 30 minutach - sygnał, że za godzinę staniesz.

Patrzysz na procent i nie pamiętasz, kiedy okno się zaczęło. A Claude Code ma te dane. Przekazuje do paska stanu procent zużycia i dokładny czas resetu obu okien. Wystarczy je zestawić.

Co pokazuje pasek

Sześć przykładów paska stanu Claude Code: limity, cache, kontekst i zmiany w git

Ten sam pasek w formie tekstowej, w sześciu sytuacjach:

Wszystko zielone - możesz cisnąć
_Brain_  Opus 5.5 high │ ◷ 48m │ ⛁ 18% · 5h ━───┃─────── 12% 3h0m · 7d ━━───┃────── 20% 3d12h

5h na czerwono - zużycie wyprzedza czas
_Brain_  Opus 5.5 high │ ◷ 35m │ ⛁ 41% · 5h ━━━━┃━━━──── 70% 3h0m · 7d ━━━━┃─────── 30% 4d4h

Równo z czasem - trzymaj tempo
_Brain_  Opus 5.5 high │ ◷ 22m │ ⛁ 27% · 5h ━━━━┃─────── 38% 3h0m · 7d ━━━━━┃────── 52% 3d12h

Cache kończy się za 7 minut
_Brain_  Opus 5.5 high │ ◷ 7m │ ⛁ 33% · 5h ━━━────┃──── 25% 2h0m · 7d ━━━━─┃────── 35% 3d18h

Cache zimny
_Brain_  Opus 5.5 high │ ☠☠ │ ⛁ 22% · 5h ━━┃───────── 18% 4h0m · 7d ━━━━━─┃───── 40% 2d22h

Pełny kontekst i duży commit do zrobienia
_Brain_  Opus 5.5 high │ ◷ 41m │ ⛁ 72% · 5h ━━━━─┃────── 30% 2h30m · 7d ━━━━━─┃───── 45% 3d8h │ +1.2k -340
ElementCo znaczyKolory
Opus 5.5 highmodel i poziom rozumowania, zmienia się po /effort-
◷ 48mile minut zostało do wygaśnięcia cachezielony powyżej 30, żółty 11-30, czerwony 10 i mniej
☠☠cache zimnyczerwony
⛁ 18%ile kontekstu jest zajętezielony do 30%, żółty do 60%, czerwony powyżej
5h ━━┃──gruba linia to zużycie, kreska to czas, który minął z oknazielony, gdy jesteś ponad 5 punktów przed kreską, żółty w granicach 5 punktów, czerwony, gdy wyprzedzasz kreskę o więcej niż 5
+1.2k -340linie dodane i usunięte od ostatniego commitazielony i czerwony

Kreska rozwiązuje cały problem. Okno 5h, do resetu zostały 3 godziny, więc minęło 40% czasu. Zużyłeś 70%? Pasek robi się czerwony i wiesz, że tniesz za szybko. Zużyłeś 12%? Zielono, możesz odpalić cięższe zadanie.

Cache działa podobnie. Gdy wygaśnie, Claude przelicza całą rozmowę od nowa, a to mocniej zjada limit. Czerwone ◷ 7m to sygnał: pisz teraz albo zrób przerwę świadomie.

Instalacja krok po kroku

  1. Zainstaluj jq, którym skrypt czyta dane z Claude Code: brew install jq na macOS.
  2. Zapisz skrypt poniżej jako ~/.claude/statusline.sh.
  3. Dopisz do ~/.claude/settings.json:
"statusLine": {
  "type": "command",
  "command": "bash ~/.claude/statusline.sh",
  "refreshInterval": 60
}

refreshInterval odświeża pasek co 60 sekund, więc kreska i minuty cache przesuwają się też wtedy, gdy nic nie piszesz. Skrypt działa lokalnie i nie zużywa tokenów - tak podaje dokumentacja Claude Code.

Pełny skrypt:

#!/usr/bin/env bash
# Skrypt linii statusu dla Claude Code
# Format: <project>  <model_short> <effort> │ ◷ <min> │ ⛁ <pct>% · 5h <pasek> <pct>% <reset> · 7d <pasek> <pct>% <reset> │ +<dodane> -<usunięte>
# Pasek 5h/7d: gruba linia = zużycie, ┃ = ile czasu z okna minęło.
# Kolor 5h/7d: zielony > 5 pkt przed kreską, żółty ±5 pkt, czerwony > 5 pkt za kreską.

input=$(cat)

# Kolory ANSI
DIM="\033[2m"
GRAY="\033[90m"
WHITE="\033[97m"
CYAN="\033[96m"
GREEN="\033[32m"
YELLOW="\033[33m"
RED="\033[31m"
RESET="\033[0m"

BAR_WIDTH=12

# Kolor limitu bez czasu resetu, na podstawie procentu (liczba całkowita)
pct_color() {
    local pct=$1
    if [ "$pct" -lt 50 ]; then
        printf "%s" "$GREEN"
    elif [ "$pct" -le 80 ]; then
        printf "%s" "$YELLOW"
    else
        printf "%s" "$RED"
    fi
}

# Kolor kontekstu: do 30% zielony, do 60% żółty, powyżej czerwony
ctx_color() {
    local pct=$1
    if [ "$pct" -le 30 ]; then
        printf "%s" "$GREEN"
    elif [ "$pct" -le 60 ]; then
        printf "%s" "$YELLOW"
    else
        printf "%s" "$RED"
    fi
}

# Kolor limitu: zużycie względem upływu czasu (punkty procentowe)
pace_color() {
    local used=$1 elapsed=$2
    local diff=$(( used - elapsed ))
    if [ "$diff" -lt -5 ]; then
        printf "%s" "$GREEN"
    elif [ "$diff" -le 5 ]; then
        printf "%s" "$YELLOW"
    else
        printf "%s" "$RED"
    fi
}

# Rysuje pasek: bar <used_pct> <marker_pct albo -1> <kolor>
bar() {
    local used=$1 marker=$2 color=$3
    local filled=$(( (used * BAR_WIDTH + 50) / 100 ))
    [ "$filled" -gt "$BAR_WIDTH" ] && filled=$BAR_WIDTH
    local mark=-1
    if [ "$marker" -ge 0 ]; then
        mark=$(( marker * BAR_WIDTH / 100 ))
        [ "$mark" -ge "$BAR_WIDTH" ] && mark=$(( BAR_WIDTH - 1 ))
    fi
    local out="" i
    for (( i = 0; i < BAR_WIDTH; i++ )); do
        if [ "$i" -eq "$mark" ]; then
            out="${out}${WHITE}┃"
        elif [ "$i" -lt "$filled" ]; then
            out="${out}${color}━"
        else
            out="${out}${GRAY}─"
        fi
    done
    printf "%s" "${out}${RESET}"
}

# Formatuje sekundy jako "Xd Yh" lub "XhYm" lub "Xm"
format_remaining() {
    local secs=$1
    if [ "$secs" -le 0 ]; then
        echo "now"
        return
    fi
    local days=$(( secs / 86400 ))
    local hours=$(( (secs % 86400) / 3600 ))
    local mins=$(( (secs % 3600) / 60 ))
    if [ "$days" -ge 1 ]; then
        echo "${days}d${hours}h"
    elif [ "$hours" -ge 1 ]; then
        echo "${hours}h${mins}m"
    else
        echo "${mins}m"
    fi
}

# Nazwa projektu (ostatni element ścieżki katalogu roboczego)
dir=$(echo "$input" | jq -r '.workspace.current_dir // empty')
project=""
if [ -n "$dir" ]; then
    project=$(basename "$dir")
fi

# Skrócona nazwa modelu: "Claude X.Y Sonnet" → "Sonnet X.Y", "Haiku" → "Haiku", itd.
model_full=$(echo "$input" | jq -r '.model.display_name // empty')
model_short=""
if [ -n "$model_full" ]; then
    # Wyciągnij numer wersji (np. "3.5", "4.6", "3")
    version=$(echo "$model_full" | grep -oE '[0-9]+\.[0-9]+|[0-9]+' | head -1)
    if echo "$model_full" | grep -qi "sonnet"; then
        model_short="Sonnet"
    elif echo "$model_full" | grep -qi "haiku"; then
        model_short="Haiku"
    elif echo "$model_full" | grep -qi "opus"; then
        model_short="Opus"
    else
        model_short="$model_full"
    fi
    [ -n "$version" ] && model_short="$model_short $version"
fi

# Poziom rozumowania (brak, gdy model go nie obsługuje)
effort=$(echo "$input" | jq -r '.effort.level // empty')

# Kontekst
used_pct=$(echo "$input" | jq -r '.context_window.used_percentage // empty')
ctx=""
if [ -n "$used_pct" ]; then
    pct_int=$(printf '%.0f' "$used_pct")
    c=$(ctx_color "$pct_int")
    ctx="${c}⛁ ${pct_int}%${RESET}"
fi

now=$(date +%s)

# Segment limitu: limit_segment <etykieta> <used_pct> <resets_at> <okno_w_sekundach>
limit_segment() {
    local label=$1 pct=$2 reset=$3 window=$4
    [ -z "$pct" ] && return
    local used
    used=$(printf '%.0f' "$pct")
    local elapsed=-1 timer=""
    if [ -n "$reset" ] && [ "$reset" != "null" ]; then
        local left=$(( reset - now ))
        elapsed=$(( (window - left) * 100 / window ))
        [ "$elapsed" -lt 0 ] && elapsed=0
        [ "$elapsed" -gt 100 ] && elapsed=100
        timer=" ${DIM}$(format_remaining "$left")${RESET}"
    fi
    local c
    if [ "$elapsed" -ge 0 ]; then
        c=$(pace_color "$used" "$elapsed")
    else
        c=$(pct_color "$used")
    fi
    printf "%s" "${c}${label}${RESET} $(bar "$used" "$elapsed" "$c") ${c}${used}%${RESET}${timer}"
}

five=$(limit_segment "5h" \
    "$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')" \
    "$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty')" \
    18000)
week=$(limit_segment "7d" \
    "$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')" \
    "$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at // empty')" \
    604800)

# Cache promptu: ◷ i minuty do wygaśnięcia albo ☠☠ gdy zimny
cache=""
cache_warm=$(echo "$input" | jq -r 'if .prompt_cache.warm == null then empty else .prompt_cache.warm end')
cache_exp=$(echo "$input" | jq -r '.prompt_cache.expires_at // empty')
if [ -n "$cache_warm" ]; then
    if [ "$cache_warm" = "true" ] && [ -n "$cache_exp" ] && [ "$cache_exp" -gt "$now" ]; then
        mins=$(( (cache_exp - now) / 60 ))
        if [ "$mins" -le 10 ]; then cc=$RED
        elif [ "$mins" -le 30 ]; then cc=$YELLOW
        else cc=$GREEN; fi
        cache="${cc}◷ ${mins}m${RESET}"
    else
        cache="${RED}☠☠${RESET}"
    fi
fi

# Skraca liczbę: 1234 → 1.2k, 102208 → 102k
short_num() {
    local n=$1
    if [ "$n" -ge 10000 ]; then
        echo "$(( n / 1000 ))k"
    elif [ "$n" -ge 1000 ]; then
        echo "$(( n / 1000 )).$(( n % 1000 / 100 ))k"
    else
        echo "$n"
    fi
}

# Niezacommitowane linie w repo: +dodane -usunięte
git_diff=""
if [ -n "$dir" ] && git -C "$dir" rev-parse --git-dir >/dev/null 2>&1; then
    stat=$(git -C "$dir" diff HEAD --shortstat 2>/dev/null)
    ins=$(echo "$stat" | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+')
    del=$(echo "$stat" | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+')
    [ -n "$ins" ] && git_diff="${GREEN}+$(short_num "$ins")${RESET}"
    [ -n "$del" ] && git_diff="${git_diff:+$git_diff }${RED}-$(short_num "$del")${RESET}"
fi

# Buduj output
SEP=" ${DIM}·${RESET} "
out=""

[ -n "$project" ] && out="${DIM}${project}${RESET}"
[ -n "$model_short" ] && out="$out  ${CYAN}${model_short}${RESET}"
[ -n "$effort" ] && out="$out ${DIM}${effort}${RESET}"
[ -n "$cache" ] && out="$out ${DIM}│${RESET} $cache"
[ -n "$ctx" ] && out="$out ${DIM}│${RESET} $ctx"
[ -n "$five" ] && out="$out${SEP}$five"
[ -n "$week" ] && out="$out${SEP}$week"
[ -n "$git_diff" ] && out="$out ${DIM}│${RESET} $git_diff"

printf "%b\n" "$out"

Typowe pułapki

Podsumowanie

P.S. Poprzednia wersja mojego paska pokazywała same liczby i osobno dwa czasy resetu, bez podpisu, który jest od czego. Przebudowa zajęła mniej czasu niż zgadywanie, co znaczy „2d14h”.


Damian Ślimak. Twój Nawigator w chaosie AI.