ai:platformy:claude-code:statusline

Rozdíly

Zde můžete vidět rozdíly mezi vybranou verzí a aktuální verzí dané stránky.

Odkaz na výstup diff

Obě strany předchozí revize Předchozí verze
Následující verze
Předchozí verze
ai:platformy:claude-code:statusline [07.07.2026 18:08] – Aktualizace článku o Claude Code status line a subagentStatusLine Petr Nosekai:platformy:claude-code:statusline [09.08.2026 23:18] (aktuální) – Aktualizace subagent status line pro aktuální chování label Petr Nosek
Řádek 1: Řádek 1:
 ====== Status line pro Claude Code ====== ====== Status line pro Claude Code ======
  
-//Vytvořeno: **** | Aktualizováno: **~~LASTMOD~~**//+//Vytvořeno: **11.04.2026** | Aktualizováno: **~~LASTMOD~~**//
  
 [[ai:platformy:claude-code:start|Claude Code]] umí podle [[https://code.claude.com/docs/en/statusline|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. [[ai:platformy:claude-code:start|Claude Code]] umí podle [[https://code.claude.com/docs/en/statusline|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.
Řádek 8: Řádek 8:
  
   * Hlavní status line ukazuje pracovní adresář, model, session ID, využití context window, 5h a 7d limity a absolutní spotřebu tokenů.   * 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, tokeny, trend tokenů, rychlost tokenů za sekundu, běh od startu a případně pracovní adresář. +  * Subagent status line ukazuje každého subagenta jako vlastní řádek: agent, model, krátký popis dispatche, živou činnost, 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 do panelu dostává přes konvenci v ''description'', protože Claude Code ho ve vstupních datech pro ''subagentStatusLine'' neposílá jako samostatné pole.+  * Model subagenta se bere z pole ''model'', které Claude Code předává do ''subagentStatusLine''. Název ''subagent_type''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ů.   * Popisky subagentů jsou čitelné i při paralelním běhu více agentů.
  
Řádek 199: Řádek 199:
 </code> </code>
  
-V reálných datech se ukázalo, že task obsahuje zejména pole ''cwd'', ''description'', ''id'', ''label'', ''startTime'', ''status'', ''tokenCount'', ''tokenSamples'' ''type''. Pole ''type'' je jen obecná hodnota typu ''local_agent'', nikoli název použitého subagenta. Samostatné pole pro model ani název subagenta v datech není.+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''.
  
-Proto se používá konvence v ''description'':+Pro název subagenta se používá konvence v ''description'':
  
 <code> <code>
-<subagent_type> · <model> · <short description>+<subagent_type> · <short description>
 </code> </code>
  
Řádek 210: Řádek 210:
  
 <code> <code>
-elite-prompt-architect · haiku · rešerše pricing+elite-prompt-architect · rešerše pricing
 </code> </code>
  
-Skript tento popisek rozparsuje a zobrazí ho jako:+Skript model přečte z ''model''popisek rozparsuje. Výsledek vypadá například takto:
  
 <code> <code>
-elite-prompt-architect │ haiku │ rešerše pricing │ running │ tok:8.1k ▁▄█ 579/s │ 14s+elite-prompt-architect │ haiku │ rešerše pricing │ Reading subagent-statusline.sh │ running │ ctx:2% │ tok:8.1k ▁▄█ 579/s │ 14s
 </code> </code>
  
-==== Pravidlo do globálního ''CLAUDE.md'' ====+==== Pravidlo ve skillu ''calling-subagents'' ====
  
-Aby skript fungoval dobře i dalších session, je potřeba dát do globálního ''CLAUDE.md'' pravidlo pro pojmenování dispatchů v Claude CodeBez toho se sice subagent zobrazí, ale nebude zřejmé, který agent a model běží.+Pro pojmenování dispatchů Claude Code je tato konvence uložená ve skillu ''calling-subagents''. ''description'' přenáší identitu subagenta, protože ''subagent_type'' není samostatnou součástí dat pro panelModel se do ''description'' nepíše: Claude Code předává autoritativní hodnotu v poli ''model''.
  
 <code markdown> <code markdown>
Řádek 229: Řádek 229:
  
 ``` ```
-<subagent_type> · <model> · <short description>+<subagent_type> · <short description>
 ``` ```
  
-Example: `elite-prompt-architect · haiku · rešerše pricing`+Example: `elite-prompt-architect · rešerše pricing`
  
-Why this exact shape: the `description` is the **only** human-readable string that +Why this exact shape: the task data behind the subagent status-line panel exposes 
-reaches the Claude Code subagent status-line panel — the task data exposes no +`model``status`, `tokenCount` and timings on its own, but it does **not** expose 
-`nameor `modelfield, and `subagent_type` isn't surfaced there either. Encoding +`subagent_type` — `type` is just the coarse category `local_agent`. So the agent's 
-them into `description` is the only way the panel can show *which agent, on which +identity reaches the panel only through `description`. That visibility matters most 
-model, doing what*. That visibility matters most exactly when several subagents run +exactly when several subagents run in parallel and you need to tell them apart at a 
-in parallel and you need to tell them apart at a glance.+glance.
  
 - Separator is a spaced middot ` · ` — the status line splits the label on it. - Separator is a spaced middot ` · ` — the status line splits the label on it.
-- `<model>= whatever you pass in the `modelparam (`haiku`/`sonnet`/`opus`/`fable`); +The panel'`labelfield is **not** the dispatch label. Claude Code computes it as 
-  the status line renders it as a colored chip.+  `progress.summary || description`, and for `local_agentit fills `progress.summary` 
 +  every 30 s with an LLM-generated activity line ("Reading runAgent.ts"). A status-line 
 +  script must therefore read identity from `descriptionand treat `labelas live 
 +  activity only — never the other way round. 
 +- **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. - 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` This is purely a Claude Code convenience: it relies on the `subagentStatusLine`
Řádek 262: Řádek 275:
  
 input=$(cat) 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 ──────────────────────────────────────────────────────────────────────── # ── ANSI ────────────────────────────────────────────────────────────────────────
Řádek 291: Řádek 309:
     fable*)  echo "$BLUE"    ;;     fable*)  echo "$BLUE"    ;;
     *)       echo ""         ;;     *)       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   esac
 } }
Řádek 380: Řádek 420:
 echo "$input" | jq -c '.tasks[]?' | while read -r task; do echo "$input" | jq -c '.tasks[]?' | while read -r task; do
   id=$(echo "$task" | jq -r '.id // empty'); [ -z "$id" ] && continue   id=$(echo "$task" | jq -r '.id // empty'); [ -z "$id" ] && continue
-  # Primární štítek = label|description (subagent_type ve schématu NENÍ). +  # Identita agenta se čte VÝHRADNĚ z `description(konvence 
-  primary=$(echo "$task" | jq -r '(.label // ""as $l | (.description // ""as $d | (.name // ""as $n +  # "<subagent_type> · <popis>"); `subagent_typeve schématu není. 
-    if ($l|length)>0 then $l elif ($d|length)>then $d elif ($n|length)>0 then $n else "agent" end')+  # POZOR: `label` NENÍ štítek dispatche. Claude Code ho počítá jako 
 +  # `progress.summary || description` a pro `type == "local_agent"` do 
 +  # `progress.summary` průběžně (à 30 szapisuje LLM-generované shrnutí 
 +  # aktuální činnosti ("Reading runAgent.ts"). Jakmile se první shrnutí 
 +  # objeví, `label` přepíše description a jméno agenta by z něj zmizelo. 
 +  # Proto: description = identita, label = živá činnost. Nikdy naopak. 
 +  descr=$(echo "$task"   | jq -r '.description // ""') 
 +  label=$(echo "$task"   | jq -r '.label // ""') 
 +  name=$(echo "$task"    | jq -r '.name // ""') 
 +  primary="$descr"; [ -z "$primary" ] && primary="$name" 
 +  activity="" 
 +  if [ -n "$label" ] && [ "$label" != "$descr" ] && [ "$label" != "$name" ]; then 
 +    activity="$label" 
 +  fi 
 +  # Typy bez description (local_bash: label = příkaz→ label slouží jako štítek. 
 +  [ -z "$primary" ] && { primary="$activity"; activity="";
 +  [ -z "$primary" ] && primary="agent"
   # `type` je hrubá kategorie ("local_agent"); ukázat jen když nese info.   # `type` je hrubá kategorie ("local_agent"); ukázat jen když nese info.
   type=$(echo "$task"    | jq -r '.type // ""')   type=$(echo "$task"    | jq -r '.type // ""')
Řádek 390: Řádek 446:
   tcwd=$(echo "$task"    | jq -r '.cwd // ""')   tcwd=$(echo "$task"    | jq -r '.cwd // ""')
   samples=$(echo "$task" | jq -c '.tokenSamples // []')   samples=$(echo "$task" | jq -c '.tokenSamples // []')
 +  rawmodel=$(echo "$task" | jq -r '.model // ""')
 +  ctxsize=$(echo "$task" | jq -r '.contextWindowSize // ""')
  
   sc=$(status_color "$status")   sc=$(status_color "$status")
  
-  # Konvence "agent · model · popis" (oddělovač " · " nebo " | "→ 3 barevné části. +  # Model: primárně z pole `.model` (Claude Code ho posílá), teprve pak z konvence. 
-  # Zpětně kompatibilní: 2 díly "model · popis"1 díl jen popis.+  _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=""   agentseg=""; modelseg=""
   _tmp="${primary// · /$US}"; _tmp="${_tmp// | /$US}"   _tmp="${primary// · /$US}"; _tmp="${_tmp// | /$US}"
   IFS="$US" read -ra _segs <<< "$_tmp"   IFS="$US" read -ra _segs <<< "$_tmp"
-  _agent=""; _model=""; _popis=""+  _agent=""; _popis=""
   _n=${#_segs[@]}   _n=${#_segs[@]}
-  if [ "$_n" -ge ]; then +  if [ "$_n" -ge ]; then 
-    _agent="${_segs[0]}"; _model="${_segs[1]}"; _popis="${_segs[2]}" +    _agent="${_segs[0]}"; _start=1 
-    for ((i=3; i<_n; i++)); do _popis="$_popis · ${_segs[$i]}"; done +    # druhý díl je model-slot ("haiku""session", "inherit"…) → přeskoč ho, 
-  elif [ "$_n-eq 2 ]; then +    # ale jen když víme model odjinud nebo je to skutečně platný model 
-    if [ -n "$(model_color "${_segs[1]}")" ]; then _agent="${_segs[0]}"; _model="${_segs[1]}" +    if is_model_slot "${_segs[1]}"; then 
-    elif [ -n "$(model_color "${_segs[0]}")" ]then _model="${_segs[0]}"; _popis="${_segs[1]}+      [ -z "$_model" && _model=$(model_family "${_segs[1]}"
-    else _agent="${_segs[0]}"; _popis="${_segs[1]}"; fi+      _start=2 
 +    fi 
 +    for ((i=_start; i<_n; i++)); do 
 +      _popis="${_popis:+$_popis · }${_segs[$i]}" 
 +    done
   else   else
     _popis="$primary"     _popis="$primary"
   fi   fi
-  # model chip jen když je to známý model; jinak segment vrať do popisu+  # 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   if [ -n "$_model" ]; then
     _mcol=$(model_color "$_model")     _mcol=$(model_color "$_model")
-    if [ -n "$_mcol" ]; then +    [ -n "$_mcol"&& modelseg=$(printf "%b%b%s%b" "$_mcol" "$BOLD" "$_model" "$RESET")
-      modelseg=$(printf "%b%b%s%b" "$_mcol" "$BOLD" "$_model" "$RESET") +
-    else +
-      _popis="${_model}${_popis:+ · $_popis}" +
-    fi+
   fi   fi
   [ -n "$_agent" ] && agentseg=$(printf "%b%s%b" "$BOLD" "$_agent" "$RESET")   [ -n "$_agent" ] && agentseg=$(printf "%b%s%b" "$BOLD" "$_agent" "$RESET")
   primary="$_popis"   primary="$_popis"
  
-  # tokens: count + sparkline + rate+  # 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=""   tokseg=""
   if [ -n "$tokens" ] && [ "$tokens" != "null" ]; then   if [ -n "$tokens" ] && [ "$tokens" != "null" ]; then
     disp=$(num_fmt "$tokens")     disp=$(num_fmt "$tokens")
-    if [ "$tokens" -ge 100000 ] 2>/dev/null; then tcol="${RED}${BOLD}"else tcol="$DIM"; fi+    # 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")     IFS=$'\t' read -r spark rate < <(spark_and_rate "$samples")
     # fallback rate: průměr od startu, když samples nenesou čas     # fallback rate: průměr od startu, když samples nenesou čas
Řádek 446: Řádek 527:
   fi   fi
  
-  # ořez primárního štítku podle columns (heuristika: fixní část ~ 44 sloupců) +  # ořez popisku a živé činnosti podle columns (heuristika: fixní část ~ 55 
-  if [ -n "$primary" ] && [ "$columns" -gt 0 ] 2>/dev/null; then +  # sloupců — status + ctx + tok/sparkline/rate + elapsed). Popis dispatche má 
-    budget=$(( columns - 44 )); [ "$budget" -lt 12 ] && budget=12 +  # přednost (odlišuje paralelní agenty téhož typu), činnost bere zbytek. 
-    if [ "${#primary}" -gt "$budget" ]; then primary="${primary:0:$((budget-1))}…"; fi+  if [ "$columns" -gt 0 ] 2>/dev/null; then 
 +    budget=$(( columns - 55 )); [ "$budget" -lt 12 ] && budget=12 
 +    if [ -n "$activity" ]; then 
 +      pbudget=$(( budget * 2 / 5 )); [ "$pbudget" -lt 10 ] && pbudget=10 
 +    else 
 +      pbudget="$budget" 
 +    fi 
 +    if [ -n "$primary" ] && [ "${#primary}" -gt "$pbudget" ]; then primary="${primary:0:$((pbudget-1))}…"; fi 
 +    if [ -n "$activity" ]; then 
 +      abudget=$(( budget - ${#primary} - 3 )); [ "$abudget" -lt 8 ] && abudget=8 
 +      if [ "${#activity}" -gt "$abudget" ]; then activity="${activity:0:$((abudget-1))}…"; fi 
 +    fi
   fi   fi
 +  actseg=""
 +  [ -n "$activity" ] && actseg=$(printf "%b%s%b" "$WHITE" "$activity" "$RESET")
  
   # type badge jen když není běžná lokální kategorie   # type badge jen když není běžná lokální kategorie
Řádek 468: Řádek 562:
     parts+=("$(printf "%b%b%s%b" "$MAGENTA" "$BOLD" "$primary" "$RESET")")     parts+=("$(printf "%b%b%s%b" "$MAGENTA" "$BOLD" "$primary" "$RESET")")
   fi   fi
 +  [ -n "$actseg" ] && parts+=("$actseg")
   [ -n "$status" ]  && parts+=("$(printf "%b%s%b" "$sc" "$status" "$RESET")")   [ -n "$status" ]  && parts+=("$(printf "%b%s%b" "$sc" "$status" "$RESET")")
 +  [ -n "$ctxseg" ]  && parts+=("$ctxseg")
   [ -n "$tokseg" ]  && parts+=("$tokseg")   [ -n "$tokseg" ]  && parts+=("$tokseg")
   [ -n "$el" ]      && parts+=("$(printf "%b%s%b" "$DIM" "$el" "$RESET")")   [ -n "$el" ]      && parts+=("$(printf "%b%s%b" "$DIM" "$el" "$RESET")")
Řádek 488: Řádek 584:
  
   * Hlavní ''statusLine'' a ''subagentStatusLine'' jsou oddělené. Hlavní řádek zůstává pro top-level session, subagenti se zobrazují v agent panelu.   * Hlavní ''statusLine'' a ''subagentStatusLine'' jsou oddělené. Hlavní řádek zůstává pro top-level session, subagenti se zobrazují v agent panelu.
-  * ''subagentStatusLine'' nedostává samostatně model ani skutečný ''subagent_type''. Proto je nutná konvence v ''description''.+  * ''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>''
 +  * V aktuálním Claude Code je ''label'' pro ''local_agent'' živá činnost, ne identita dispatche: odpovídá ''progress.summary || description''. ''AgentSummary'' přibližně každých 30 sekund zapisuje do ''progress.summary'' krátké LLM-generované shrnutí činnosti. Identita se proto vždy čte z ''description'', zatímco ''label'' se vypisuje jen jako samostatný sloupec s činností. 
 +  * 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''.   * ''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.   * ''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.   * ''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''.   * Skripty vyžadují ''jq'', ''python3'' a běžné unixové ''date''.
  
  • ai/platformy/claude-code/statusline.1783440491.txt.gz
  • Poslední úprava: 07.07.2026 18:08
  • autor: Petr Nosek