Passa al contenuto principale

Personalizzare la statusline

Intermedio
What you'll learn
  • Capire il contratto: Claude Code invia l'intera sessione come JSON a uno script e mostra ciò che lo script stampa
  • Configurarla in entrambi i modi: chiedere a /statusline in linguaggio naturale, oppure scrivere da sé il blocco statusLine
  • Scegliere i pochi campi che meritano davvero un posto, tra la sessantina disponibili
  • Conoscere gli otto eventi che rilanciano lo script, il debounce di 300 ms e quando serve refreshInterval
  • Costruire tre ricette: una barra del contesto, una riga con PR e limiti di frequenza, e un indicatore di salute della prompt cache
  • Evitare le quattro trappole: tput cols non funziona, campi null prima della prima chiamata API, cancellazione dell'esecuzione in corso e perdita dei suggerimenti da tastiera

La statusline è una striscia in fondo a Claude Code che esegue qualsiasi script di shell tu configuri. Claude Code le invia l'intero stato della sessione come JSON su stdin; il tuo script stampa qualcosa; Claude Code lo mostra. Gira in locale e non consuma token API.

Questo contratto è l'intera funzione. Tutto ciò che segue riguarda cosa c'è dentro il JSON e quando lo script viene eseguito.

Viene mostrata in una riga propria sopra i badge predefiniti del piè di pagina, senza sostituirli — ma configurarne una fa sì che Claude Code smetta di mostrare la maggior parte dei suggerimenti da tastiera del piè di pagina, tra cui esc to interrupt, il ripiego ? for shortcuts e il suggerimento di dettatura hold space to speak. Vale la pena saperlo prima di consegnare questa configurazione a un collega che ne fa uso.

Configurarla​

Due strade. La più veloce è descrivere ciò che vuoi:

Lascia che Claude Code scriva lo script per te

/statusline show model name and context percentage with a progress bar

Genera uno script in ~/.claude/, aggiorna le impostazioni e chiede il permesso per le modifiche ai file. Eseguire /statusline delete (oppure clear, o "remove it") la rimuove.

La strada manuale è un blocco statusLine in ~/.claude/settings.json o nelle impostazioni di progetto:

{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh",
"padding": 2,
"refreshInterval": 10
}
}

Quattro campi, tre dei quali facoltativi:

CampoSignificato
type"command"
commandIl percorso di uno script o un comando di shell inline: viene eseguito in una shell, quindi funziona anche una riga sola
paddingSpaziatura orizzontale extra in caratteri, predefinita 0. Rientro relativo, non distanza assoluta dal bordo del terminale
refreshIntervalRiesegue ogni N secondi in aggiunta ai trigger a eventi. Minimo 1. Lascialo non impostato per eseguire solo su eventi
hideVimModeIndicatorImposta true quando il tuo script mostra vim.mode da sé, così la modalità non compare due volte

Poiché command viene eseguito in una shell, la statusline utile più piccola possibile non richiede alcun file di script: basta jq:

{
"statusLine": {
"type": "command",
"command": "jq -r '\"[\\(.model.display_name)] \\(.context_window.used_percentage // 0)% context\"'"
}
}

Cosa c'è nel JSON​

L'input è ampio: modello, workspace, costo, finestra di contesto, limiti di frequenza, stato della PR, worktree, modalità vim, prompt cache. La tentazione è mostrare tutto. Resisti: una statusline che smetti di leggere è peggio di nessuna.

Questi sono i campi che per la maggior parte delle persone meritano un posto, raggruppati per la sorpresa che evitano:

CampoEvita
model.display_nameBruciare Opus su un compito banale
context_window.used_percentageEsaurire il contesto a metà compito: il tuo segnale per /compact
workspace.current_dir, workspace.git_worktreeModificare il checkout sbagliato quando hai più worktree aperti
rate_limits.five_hour.used_percentageSbattere contro un muro senza alcun avviso
cost.total_cost_usdUna sessione che diventa costosa senza che te ne accorga (stima lato client a prezzo di listino, non la tua fattura)
effort.level, fast_modeDimenticare di aver lasciato l'effort su max
pr.number, pr.review_statePassare al browser per controllare se la revisione è arrivata
prompt_cache.hit_ratio, prompt_cache.warmLa perdita di costi più silenziosa che esista: vedi la terza ricetta

Tre note strutturali sullo schema che fanno risparmiare vero tempo di debug:

  • cwd e workspace.current_dir hanno lo stesso valore. Preferisci workspace.current_dir, per coerenza con workspace.project_dir, che è dove Claude Code è stato avviato e può differire quando la directory di lavoro cambia a metà sessione.
  • workspace.git_worktree e worktree.* non sono la stessa cosa. workspace.git_worktree è valorizzato per qualsiasi worktree collegato creato con git worktree add, ed è assente nell'albero principale. L'oggetto worktree.* esiste solo mentre la sessione è in una sessione worktree di Claude Code.
  • used_percentage considera solo l'input. È calcolato da input_tokens + cache_creation_input_tokens + cache_read_input_tokens ed esclude i token di output. Se calcoli da te una percentuale a partire da current_usage, usa la stessa formula solo-input, altrimenti il tuo numero non coinciderà con quello di Claude Code.
Premi Invio o Spazio per girare la carta. Usa le frecce sinistra e destra per spostarti tra le carte.Termine mostrato.
1 / 12

Quando viene eseguito lo script​

Una volta all'avvio della sessione, anche alla ripresa. Poi, a ciascuno di questi eventi:

Guided walkthrough1 of 4
  1. Il caso comune, ed è il motivo per cui la percentuale di contesto resta più o meno aggiornata senza alcun timer.

Da questo elenco derivano tre comportamenti:

  • Gli aggiornamenti hanno un debounce di 300 ms, quindi modifiche rapide si raggruppano in un'unica esecuzione. Modificare lo stesso command salta il debounce ed esegue subito.
  • Un nuovo trigger annulla uno script in corso. Mantienilo veloce. Una statusline che invoca una lenta chiamata di rete verrà regolarmente uccisa prima di stampare.
  • I trigger a eventi tacciono quando la sessione principale è inattiva: il caso classico è un coordinatore in attesa di subagenti in background che cambiano lo stato git sotto i tuoi occhi. Questo, più un orologio o qualsiasi segmento di origine esterna, è lo scopo di refreshInterval.

Il tuo script può stampare più di una semplice riga: ogni echo è una riga, i codici di escape ANSI danno il colore (\033[32m verde, \033[0m reset) e le sequenze OSC 8 rendono il testo cliccabile in iTerm2, Kitty o WezTerm.

Tre ricette​

Ricetta 1: barra del contesto​

La riga di maggior valore, e quella che vale la pena avere anche se non aggiungi nient'altro. Nota i valori di ripiego // 0: current_usage è null prima della prima chiamata API e di nuovo subito dopo /compact, quindi un'espressione jq non protetta stampa null proprio nei momenti in cui è più probabile che tu stia guardando.

#!/usr/bin/env bash
input=$(cat)

model=$(echo "$input" | jq -r '.model.display_name // "claude"')
dir=$(echo "$input" | jq -r '.workspace.current_dir // "."')
pct=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)

# 20-cell bar: fill proportional to pct
filled=$(( pct / 5 ))
bar=""
for ((i = 0; i < 20; i++)); do
if (( i < filled )); then bar+="▓"; else bar+="░"; fi
done

# green under 60%, yellow under 85%, red above
if (( pct < 60 )); then color="\033[32m"
elif (( pct < 85 )); then color="\033[33m"
else color="\033[31m"
fi

printf "%s · %s · ${color}%s %s%%\033[0m" "$model" "$(basename "$dir")" "$bar" "$pct"

Ricetta 2: branch, stato della PR e margine sui limiti di frequenza​

pr.* rispecchia il badge della PR nel piè di pagina — e in un repository GitLab viene invece popolato dalla merge request aperta del branch, con pr.kind impostato a mr e pr.number che è il numero della MR. I campi dei limiti di frequenza sono quelli che le persone vorrebbero aver avuto col senno di poi.

#!/usr/bin/env bash
input=$(cat)

branch=$(git branch --show-current 2>/dev/null)
wt=$(echo "$input" | jq -r '.workspace.git_worktree // empty')
pr=$(echo "$input" | jq -r '.pr.number // empty')
state=$(echo "$input" | jq -r '.pr.review_state // empty')
limit=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')

line="${branch:-no-git}"
[ -n "$wt" ] && line+=" ⎇ $wt"
[ -n "$pr" ] && line+=" · #$pr${state:+ ($state)}"
[ -n "$limit" ] && line+=" · 5h ${limit%.*}%"

printf "%s" "$line"

Ricetta 3: salute della cache, la perdita che non vedi​

È la ricetta che nessuno scrive, ed è quella con il ritorno più alto nelle sessioni agentiche lunghe. La prompt caching è ciò che rende sostenibile una sessione da 100 turni — e un singolo byte che cambia vicino alla cima del prompt la distrugge in silenzio, rielaborando l'intero prefisso a ogni turno a prezzo pieno. Nulla nell'interfaccia predefinita ti dice che sta accadendo.

prompt_cache te lo dice. Due campi portano la maggior parte del segnale: warm (il prefisso è ancora entro il suo TTL) e hit_ratio (letture dalla cache sul totale dei token di input, 0–1) — e last_miss_cause.causes nomina il colpevole: tools_changed, system_prompt_changed, ttl_expired_5m o likely_server_side.

#!/usr/bin/env bash
input=$(cat)

warm=$(echo "$input" | jq -r '.prompt_cache.warm // empty')
ratio=$(echo "$input" | jq -r '.prompt_cache.hit_ratio // empty')
cause=$(echo "$input" | jq -r '.prompt_cache.last_miss_cause.causes[0] // empty')
misses=$(echo "$input" | jq -r '.prompt_cache.misses // 0')

# prompt_cache is absent until the main conversation's first API response
[ -z "$warm" ] && { printf "cache: —"; exit 0; }

pct=$(awk "BEGIN{printf \"%d\", ${ratio:-0} * 100}")
if [ "$warm" = "true" ]; then icon="\033[32m●\033[0m"; else icon="\033[31m○\033[0m"; fi

printf "cache: ${icon} %s%% hit" "$pct"
(( misses > 0 )) && printf " · %s miss%s%s" "$misses" "$([ "$misses" -eq 1 ] || echo es)" "${cause:+ ($cause)}"

Una causa system_prompt_changed che compare a ogni turno significa che qualcosa nel prefisso del prompt non è deterministico: un timestamp in un CLAUDE.md, un hook che inietta output mutevole. tools_changed a ogni turno di solito significa che un server MCP registra gli strumenti in modo incoerente. Entrambi si possono correggere una volta che li vedi. Claude Code mostra le stesse statistiche sulla riga Prompt cache (main) di /usage, se preferisci controllare a richiesta.

Nota che queste statistiche riguardano solo la conversazione principale: le richieste dei subagenti non vengono conteggiate.

Quattro trappole​

  1. tput cols non funziona. Claude Code cattura l'output del tuo script anziché collegarlo al terminale, quindi tput cols e il rilevamento della larghezza a livello di linguaggio non vedono le dimensioni del terminale. Leggi invece le variabili d'ambiente COLUMNS e LINES: Claude Code imposta entrambe alle dimensioni correnti prima di ogni esecuzione.
  2. Proteggi ogni campo. current_usage è null prima della prima chiamata API e di nuovo subito dopo /compact; prompt_cache e rate_limits.spend_limit sono assenti fino alla prima risposta API; pr.review_state può mancare anche quando pr è presente; effort.level è assente sui modelli senza quel parametro. Usa // empty o // 0 su tutto.
  3. Gli script lenti vengono annullati, non messi in coda. Un nuovo trigger uccide l'esecuzione in corso. Se vuoi dati esterni, mettili in cache su file da un processo separato e fai leggere il file alla statusline.
  4. Gli importi in dollari del limite di spesa sono in ritardo. Dietro un gateway delle app Claude, used_percentage arriva con ogni risposta, ma used_usd, limit_usd e period vengono recuperati separatamente circa ogni cinque minuti — quindi possono discordare brevemente dalla percentuale. Trattali come facoltativi anche quando spend_limit è presente.

Non vuoi scriverla?​

Strumenti della comunità come ccstatusline offrono statusline già pronte e configurabili da inserire. Sono un punto di partenza ragionevole — e come ogni script di terze parti che gira a ogni messaggio dell'assistente con i tuoi privilegi, leggilo prima di fidarti. Vedi Verificare il codice di terze parti.

Verifica la tua comprensione

0/5
  1. La tua statusline mostra un orologio e un indicatore di git sporco. Mentre una sessione coordinatrice attende subagenti in background, entrambi si bloccano. Perché, e cosa lo risolve?
  2. Subito dopo aver eseguito /compact, la tua percentuale di contesto stampa "null". Cos'è successo?
  3. Vuoi che la tua statusline si tronchi in modo pulito su un terminale stretto, quindi chiami tput cols. Non restituisce nulla di utile. Perché?
  4. prompt_cache.last_miss_cause.causes riporta system_prompt_changed quasi a ogni turno. Cosa ti dice?
  5. Calcoli da te la percentuale di contesto a partire da current_usage e ottieni un numero diverso da used_percentage. Motivo più probabile?
Key takeaways
  • La statusline è solo uno script: Claude Code invia l'intera sessione come JSON su stdin e mostra ciò che lo script stampa su stdout. Gira in locale e non costa token.
  • /statusline con una descrizione in linguaggio naturale scrive lo script e configura le impostazioni per te. La forma manuale è un blocco statusLine con type, command e i facoltativi padding, refreshInterval e hideVimModeIndicator.
  • Tra la sessantina di campi, pochi meritano un posto: model.display_name, context_window.used_percentage, la directory o il worktree, rate_limits.five_hour.used_percentage e — nelle sessioni lunghe — prompt_cache.
  • Guidata da eventi con debounce di 300 ms. Una sessione principale inattiva non genera eventi, quindi i segmenti basati sul tempo o di origine esterna richiedono refreshInterval. Un nuovo trigger ANNULLA uno script in corso, quindi mantienilo veloce.
  • Proteggi ogni campo con // empty o // 0: current_usage è null prima della prima chiamata API e subito dopo /compact, e prompt_cache e spend_limit sono assenti fino alla prima risposta API.
  • used_percentage considera solo l'input (input nuovo + scritture in cache + letture dalla cache). Usa quella formula se lo calcoli da te.
  • tput cols non vede il terminale dall'interno dello script: leggi COLUMNS e LINES, che Claude Code imposta prima di ogni esecuzione.
  • Un segmento prompt_cache è l'aggiunta insolita a più alto impatto: warm più hit_ratio dicono se il tuo prefisso viene messo in cache, e last_miss_cause.causes indica cosa lo ha rotto.

Prossimi passi​

  • Gestione del contesto — cosa significa davvero la percentuale che hai appena messo a schermo e come agire di conseguenza
  • Prompt Caching — perché vale la pena osservare hit_ratio e cosa distrugge un prefisso in cache
  • settings.json — dove vive il blocco statusLine e quale livello prevale
  • Git Worktrees — la funzione descritta da workspace.git_worktree e worktree.*