ai:platformy:claude-code:statusline

Toto je starší verze dokumentu!


Status line pro Claude Code

Vytvořeno: 11.04.2026 | Aktualizováno: 04.08.2026 14:30

Claude Code umí podle oficiální dokumentace vykreslovat vlastní status line přes externí příkaz. Tohle je moje aktuální konfigurace: hlavní statusLine ukazuje stav top-level session a samostatná subagentStatusLine přidává přehled běžících subagentů v agent panelu.

  • Hlavní status line ukazuje pracovní adresář, model, session ID, využití context window, 5h a 7d limity a absolutní spotřebu tokenů.
  • Subagent status line ukazuje každého subagenta jako vlastní řádek: agent, model, krátký popis, stav, zaplnění jeho context window, tokeny, trend tokenů, rychlost tokenů za sekundu, běh od startu a případně pracovní adresář.
  • Model subagenta se bere z pole model, které Claude Code předává do subagentStatusLine. Název subagent_type v datech samostatně není; pro přehled se proto zapisuje do description.
  • Popisky subagentů jsou čitelné i při paralelním běhu více agentů.

V ~/.claude/settings.json jsou zapojené dva skripty:

"statusLine": {
  "type": "command",
  "command": "bash ~/.claude/statusline-command.sh"
},
"subagentStatusLine": {
  "type": "command",
  "command": "bash ~/.claude/subagent-statusline.sh"
}

Skripty čtou JSON ze standardního vstupu, parsují ho přes jq a vrací barevný výstup přes ANSI sekvence.

Hlavní statusLine je vázaná na top-level Claude Code session. Nepřepíná se podle aktivního subagenta a nedostává data o tom, který subagent zrovna běží. K tomu slouží samostatná subagentStatusLine.

Výstup hlavní status line vypadá zhruba takto:

~/project │ Sonnet 4.6 | sid:<id> │ 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
#!/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"

subagentStatusLine dostává pole tasks a pro každý task musí vypsat jeden JSON řádek ve tvaru:

{"id":"<task id>","content":"<řádek s ANSI>"}

V reálných datech task obsahuje zejména pole cwd, description, id, label, startTime, status, tokenCount, tokenSamples, type, model a contextWindowSize. Pole type je jen obecná hodnota typu local_agent, nikoli název použitého subagenta. Pole model obsahuje skutečně použitý model, například claude-haiku-4-5-20251001.

Pro název subagenta se používá konvence v description:

<subagent_type> · <short description>

Příklad:

elite-prompt-architect · rešerše pricing

Skript model přečte z model a popisek rozparsuje. Výsledek vypadá například takto:

elite-prompt-architect │ haiku │ rešerše pricing │ running │ ctx:2% │ tok:8.1k ▁▄█ 579/s │ 14s

Aby byl panel čitelný i v dalších session, je potřeba dát do globálního CLAUDE.md pravidlo pro pojmenování dispatchů v Claude Code. description přenáší identitu subagenta, protože subagent_type není samostatnou součástí dat pro panel. Model se do description nepíše: Claude Code předává autoritativní hodnotu v poli model.

## `description` naming convention — Claude Code only
 
In **Claude Code**, format every dispatch `description` as:
 
```
<subagent_type> · <short description>
```
 
Example: `elite-prompt-architect · rešerše pricing`
 
Why this exact shape: the task data behind the subagent status-line panel exposes
`model`, `status`, `tokenCount` and timings on its own, but it does **not** expose
`subagent_type` — `type` is just the coarse category `local_agent`. So the agent's
identity reaches the panel only through `description`. That visibility matters most
exactly when several subagents run in parallel and you need to tell them apart at a
glance.
 
- Separator is a spaced middot ` · ` — the status line splits the label on it.
- **Never write the model into `description`.** Claude Code sends the real model in
  the task's `model` field and the status line renders it as a colored chip itself.
  Writing it by hand is redundant, and when the `model` param is omitted there is
  nothing truthful to write — placeholders like `session` or `inherit` used to leak
  into the visible label.
- Keep `<short description>` genuinely short — the panel truncates to terminal width.
 
Legacy `<subagent_type> · <model> · <description>` labels still render correctly:
the status line detects a model-shaped middle segment and drops it in favour of the
real `model` field. No need to rewrite old agent definitions, but write new
dispatches in the two-part form.
 
This is purely a Claude Code convenience: it relies on the `subagentStatusLine`
setting parsing the ` · ` format. **OpenCode** has no such status line, so use a
plain, natural `description` there — do **not** force this format.
#!/usr/bin/env bash
# Claude Code subagent status line
# Renders one custom row per active subagent in the agent panel.
# Row: <type> │ <status> │ tok:<n> <sparkline> <rate> │ <elapsed> │ [cwd] │ <label|desc>
# Input (stdin): { cwd, columns, tasks:[ ... ] }
# Output (stdout): one JSON line per task -> {"id":"<id>","content":"<row w/ ANSI>"}
 
input=$(cat)
 
# ── DEBUG (volitelne): SUBAGENT_SL_DEBUG_DIR=/nejaka/slozka -> dump stdin ──────
if [ -n "$SUBAGENT_SL_DEBUG_DIR" ] && [ -d "$SUBAGENT_SL_DEBUG_DIR" ]; then
  printf '%s\n' "$input" >> "$SUBAGENT_SL_DEBUG_DIR/raw.jsonl" 2>/dev/null
fi
 
# ── ANSI ────────────────────────────────────────────────────────────────────────
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'; BLUE='\033[34m'
 
now=$(date +%s)
main_cwd=$(echo "$input" | jq -r '.cwd // .workspace.current_dir // empty')
columns=$(echo "$input" | jq -r '.columns // 0')
US=$'\x1f'   # interní oddělovač pro rozklad "agent · model · popis"
 
status_color() {
  case "$1" in
    running|in_progress|active) echo "$CYAN" ;;
    completed|done|success)     echo "$GREEN" ;;
    failed|error)               echo "$RED" ;;
    pending|queued|waiting)     echo "$YELLOW" ;;
    *)                          echo "$WHITE" ;;
  esac
}
 
# Rozpozná model v prefixu popisku (konvence "model · popis" / "model | popis").
# Vrací barvu, nebo prázdno když prefix není známý model.
model_color() {
  case "$(echo "$1" | tr '[:upper:]' '[:lower:]')" in
    haiku*)  echo "$GREEN"   ;;
    sonnet*) echo "$CYAN"    ;;
    opus*)   echo "$MAGENTA" ;;
    fable*)  echo "$BLUE"    ;;
    *)       echo ""         ;;
  esac
}
 
# Model z pole `.model` (např. "claude-haiku-4-5-20251001") -> rodina "haiku".
# Toto je autoritativní zdroj; konvence v description je jen fallback.
model_family() {
  case "$(echo "$1" | tr '[:upper:]' '[:lower:]')" in
    *haiku*)  echo "haiku"  ;;
    *sonnet*) echo "sonnet" ;;
    *opus*)   echo "opus"   ;;
    *fable*)  echo "fable"  ;;
    *)        echo ""       ;;
  esac
}
 
# Segment v description, který jen duplikuje/zastupuje model → zahodit,
# ať neteče do popisu ("session", "inherit", "dedeno" = model param vynechán).
is_model_slot() {
  [ -n "$(model_color "$1")" ] && return 0
  case "$(echo "$1" | tr '[:upper:]' '[:lower:]')" in
    session|inherit|dedeno|zdeděno|zdedeno|default) return 0 ;;
    *) return 1 ;;
  esac
}
 
# elapsed seconds from startTime (epoch-s, epoch-ms, or ISO-8601) -> "2m10s"
elapsed_str() {
  local v="$1" start=""
  { [ -z "$v" ] || [ "$v" = "null" ]; } && return
  if [[ "$v" =~ ^[0-9]+$ ]]; then
    if [ "${#v}" -ge 13 ]; then start=$(( v / 1000 )); else start="$v"; fi
  else
    start=$(date -d "$v" +%s 2>/dev/null) || return
  fi
  local d=$(( now - start )); [ "$d" -lt 0 ] && d=0
  if   [ "$d" -ge 3600 ]; then printf "%dh%dm" $(( d/3600 )) $(( (d%3600)/60 ))
  elif [ "$d" -ge 60 ];   then printf "%dm%02ds" $(( d/60 )) $(( d%60 ))
  else printf "%ds" "$d"; fi
  return
}
elapsed_secs() {
  local v="$1" start=""
  { [ -z "$v" ] || [ "$v" = "null" ]; } && { echo 0; return; }
  if [[ "$v" =~ ^[0-9]+$ ]]; then
    if [ "${#v}" -ge 13 ]; then start=$(( v / 1000 )); else start="$v"; fi
  else
    start=$(date -d "$v" +%s 2>/dev/null) || { echo 0; return; }
  fi
  local d=$(( now - start )); [ "$d" -lt 0 ] && d=0; echo "$d"
}
 
num_fmt() { # 39731 -> 39.7k
  local t="$1"
  [ "$t" -ge 1000 ] 2>/dev/null && python3 -c "print(f'{$t/1000:.1f}k')" 2>/dev/null || echo "$t"
}
 
# sparkline + rate from tokenSamples (defensive: čísla i objekty)
# stdout: "<sparkline>\t<rate_per_s or empty>"
spark_and_rate() {
  python3 - "$1" 2>/dev/null <<'PY'
import sys, json
raw = sys.argv[1] if len(sys.argv) > 1 else "[]"
try:
    d = json.loads(raw)
except Exception:
    print("\t"); sys.exit(0)
vals, times = [], []
def num(x):
    if isinstance(x,(int,float)): return float(x)
    if isinstance(x,dict):
        for k in ('tokens','tokenCount','count','value','v','y'):
            if isinstance(x.get(k),(int,float)): return float(x[k])
    return None
def tim(x):
    if isinstance(x,dict):
        for k in ('t','time','ts','timestamp','at'):
            if isinstance(x.get(k),(int,float)): return float(x[k])
    return None
if isinstance(d, list):
    for x in d:
        v = num(x)
        if v is not None:
            vals.append(v); times.append(tim(x))
spark = ""
if len(vals) >= 2:
    blocks = "▁▂▃▄▅▆▇█"
    w = vals[-14:]
    lo, hi = min(w), max(w); rng = (hi - lo) or 1
    spark = "".join(blocks[min(7, int(round((v-lo)/rng*7)))] for v in w)
rate = ""
if len(vals) >= 2 and all(t is not None for t in times) and (times[-1]-times[0]) > 0:
    dt = times[-1]-times[0]
    if dt > 10_000_000_000: dt = dt/1000.0   # ms guard
    r = (vals[-1]-vals[0])/dt
    if r > 0:
        rate = f"{r/1000:.1f}k/s" if r >= 1000 else f"{r:.0f}/s"
print(f"{spark}\t{rate}")
PY
}
 
short_dir() {
  local d="$1"
  { [ -z "$d" ] || [ "$d" = "null" ]; } && return
  if [ "$d" = "$HOME" ]; then echo "~";
  elif [[ "$d" == "$HOME/"* ]]; then echo "~/${d#$HOME/}";
  else echo "$d"; fi
}
 
# ── build one row per task ───────────────────────────────────────────────────────
echo "$input" | jq -c '.tasks[]?' | while read -r task; do
  id=$(echo "$task" | jq -r '.id // empty'); [ -z "$id" ] && continue
  # Primární štítek = label|description (subagent_type ve schématu NENÍ).
  primary=$(echo "$task" | jq -r '(.label // "") as $l | (.description // "") as $d | (.name // "") as $n
    | if ($l|length)>0 then $l elif ($d|length)>0 then $d elif ($n|length)>0 then $n else "agent" end')
  # `type` je hrubá kategorie ("local_agent"); ukázat jen když nese info.
  type=$(echo "$task"    | jq -r '.type // ""')
  status=$(echo "$task"  | jq -r '.status // ""')
  tokens=$(echo "$task"  | jq -r '.tokenCount // ""')
  start=$(echo "$task"   | jq -r '.startTime // ""')
  tcwd=$(echo "$task"    | jq -r '.cwd // ""')
  samples=$(echo "$task" | jq -c '.tokenSamples // []')
  rawmodel=$(echo "$task" | jq -r '.model // ""')
  ctxsize=$(echo "$task" | jq -r '.contextWindowSize // ""')
 
  sc=$(status_color "$status")
 
  # Model: primárně z pole `.model` (Claude Code ho posílá), teprve pak z konvence.
  _model=$(model_family "$rawmodel")
 
  # Konvence "agent · popis" (historicky i "agent · model · popis"; oddělovač
  # " · " nebo " | "). Model-slot v popisku se zahodí, když model už známe.
  agentseg=""; modelseg=""
  _tmp="${primary// · /$US}"; _tmp="${_tmp// | /$US}"
  IFS="$US" read -ra _segs <<< "$_tmp"
  _agent=""; _popis=""
  _n=${#_segs[@]}
  if [ "$_n" -ge 2 ]; then
    _agent="${_segs[0]}"; _start=1
    # druhý díl je model-slot ("haiku", "session", "inherit"…) → přeskoč ho,
    # ale jen když víme model odjinud nebo je to skutečně platný model
    if is_model_slot "${_segs[1]}"; then
      [ -z "$_model" ] && _model=$(model_family "${_segs[1]}")
      _start=2
    fi
    for ((i=_start; i<_n; i++)); do
      _popis="${_popis:+$_popis · }${_segs[$i]}"
    done
  else
    _popis="$primary"
  fi
  # jednodílný popisek, který je sám o sobě model → ber jako model, ne jako agenta
  if [ "$_n" -eq 1 ] && [ -z "$_model" ] && [ -n "$(model_color "$primary")" ]; then
    _model=$(model_family "$primary"); _popis=""
  fi
  if [ -n "$_model" ]; then
    _mcol=$(model_color "$_model")
    [ -n "$_mcol" ] && modelseg=$(printf "%b%b%s%b" "$_mcol" "$BOLD" "$_model" "$RESET")
  fi
  [ -n "$_agent" ] && agentseg=$(printf "%b%s%b" "$BOLD" "$_agent" "$RESET")
  primary="$_popis"
 
  # tokens: count + zaplneni okna + sparkline + rate
  # ctx: zaplneni kontextoveho okna subagenta. `tokenCount` je aktualni obsazeni
  # okna (ne kumulativni utrata), takze procento je primo pomer k `contextWindowSize`.
  # Format i barvy zamerne shodne s hlavni statusLine (ctx:55% / ctx:93%!).
  ctxseg=""; ctxpct=""
  if [ -n "$tokens" ] && [ "$tokens" != "null" ] \
     && [ -n "$ctxsize" ] && [ "$ctxsize" != "null" ] && [ "$ctxsize" -gt 0 ] 2>/dev/null; then
    ctxpct=$(( tokens * 100 / ctxsize ))
    if   [ "$ctxpct" -ge 90 ]; then ctxseg=$(printf "%b%bctx:%s%%!%b" "$RED" "$BOLD" "$ctxpct" "$RESET")
    elif [ "$ctxpct" -ge 70 ]; then ctxseg=$(printf "%bctx:%s%%%b" "$YELLOW" "$ctxpct" "$RESET")
    else ctxseg=$(printf "%bctx:%s%%%b" "$GREEN" "$ctxpct" "$RESET")
    fi
  fi
 
  tokseg=""
  if [ -n "$tokens" ] && [ "$tokens" != "null" ]; then
    disp=$(num_fmt "$tokens")
    # Varovnou roli nese ctx segment; tok zustava neutralni absolutni cislo.
    # Bez `contextWindowSize` (starsi Claude Code) plati puvodni pevny prah.
    if [ -n "$ctxpct" ]; then tcol="$DIM"
    elif [ "$tokens" -ge 100000 ] 2>/dev/null; then tcol="${RED}${BOLD}"
    else tcol="$DIM"; fi
    IFS=$'\t' read -r spark rate < <(spark_and_rate "$samples")
    # fallback rate: průměr od startu, když samples nenesou čas
    if [ -z "$rate" ]; then
      es=$(elapsed_secs "$start")
      [ "$es" -gt 0 ] 2>/dev/null && rate=$(python3 -c "r=$tokens/$es; print(f'{r/1000:.1f}k/s' if r>=1000 else f'{r:.0f}/s')" 2>/dev/null)
    fi
    tokseg=$(printf "%btok:%s%b" "$tcol" "$disp" "$RESET")
    [ -n "$spark" ] && tokseg="$tokseg $(printf "%b%s%b" "$CYAN" "$spark" "$RESET")"
    [ -n "$rate" ]  && tokseg="$tokseg $(printf "%b%s%b" "$DIM" "$rate" "$RESET")"
  fi
 
  el=$(elapsed_str "$start")
 
  # cwd jen když se liší od hlavní session
  dirseg=""
  if [ -n "$tcwd" ] && [ "$tcwd" != "null" ] && [ "$tcwd" != "$main_cwd" ]; then
    dirseg=$(printf "%b%s%b" "$YELLOW" "$(short_dir "$tcwd")" "$RESET")
  fi
 
  # ořez primárního štítku podle columns (heuristika: fixní část ~ 55 sloupců
  # — status + ctx + tok/sparkline/rate + elapsed)
  if [ -n "$primary" ] && [ "$columns" -gt 0 ] 2>/dev/null; then
    budget=$(( columns - 55 )); [ "$budget" -lt 12 ] && budget=12
    if [ "${#primary}" -gt "$budget" ]; then primary="${primary:0:$((budget-1))}…"; fi
  fi
 
  # type badge jen když není běžná lokální kategorie
  typeseg=""
  case "$type" in
    ""|local_agent|agent) : ;;
    *) typeseg=$(printf "%b%s%b" "$DIM" "$type" "$RESET") ;;
  esac
 
  parts=()
  if [ -n "$agentseg" ]; then
    parts+=("$agentseg")
    [ -n "$modelseg" ] && parts+=("$modelseg")
    [ -n "$primary" ] && parts+=("$(printf "%b%s%b" "$DIM" "$primary" "$RESET")")
  else
    [ -n "$modelseg" ] && parts+=("$modelseg")
    parts+=("$(printf "%b%b%s%b" "$MAGENTA" "$BOLD" "$primary" "$RESET")")
  fi
  [ -n "$status" ]  && parts+=("$(printf "%b%s%b" "$sc" "$status" "$RESET")")
  [ -n "$ctxseg" ]  && parts+=("$ctxseg")
  [ -n "$tokseg" ]  && parts+=("$tokseg")
  [ -n "$el" ]      && parts+=("$(printf "%b%s%b" "$DIM" "$el" "$RESET")")
  [ -n "$dirseg" ]  && parts+=("$dirseg")
  [ -n "$typeseg" ] && parts+=("$typeseg")
 
  sep="$(printf "%b │ %b" "$DIM" "$RESET")"
  content=""
  for p in "${parts[@]}"; do
    [ -z "$content" ] && content="$p" || content="${content}${sep}${p}"
  done
 
  content_bytes=$(printf "%b" "$content")
  jq -cn --arg id "$id" --arg content "$content_bytes" '{id:$id, content:$content}'
done
  • Hlavní statusLine a subagentStatusLine jsou oddělené. Hlavní řádek zůstává pro top-level session, subagenti se zobrazují v agent panelu.
  • subagentStatusLine dostává skutečný model v poli model, ale nedostává subagent_type. Proto description používá dvoudílný tvar <subagent_type> · <short description>.
  • Starší tříčlenné popisky <subagent_type> · <model> · <description> zůstávají podporované. Prostřední modelový segment se ignoruje ve prospěch hodnoty z model; nově se ale zapisuje dvoudílný tvar.
  • contextWindowSize spolu s tokenCount určuje ctx — procento obsazení context window subagenta. Pod 70 % je zelené, od 70 % žluté a od 90 % červené. tokenCount je aktuální obsazení okna, ne kumulativní spotřeba.
  • tokenSamples se používá pro sparkline trendu tokenů. Když vzorky neobsahují čas, rychlost se dopočítá jako průměr od startTime.
  • columns se používá pro ořez popisku, aby se řádky v úzkém terminálu nelámaly.
  • cwd se zobrazí jen tehdy, když se liší od hlavní session.
  • Pro diagnostiku lze nastavit proměnnou prostředí SUBAGENT_SL_DEBUG_DIR na existující adresář. Skript do něj zapíše zachycené JSON vstupy do raw.jsonl.
  • Skripty vyžadují jq, python3 a běžné unixové date.
  • ai/platformy/claude-code/statusline.1785846624.txt.gz
  • Poslední úprava: 04.08.2026 14:30
  • autor: Petr Nosek