Statusline di Claude Code su VPS: configurazione
Configura statusLine per mostrare host, directory, branch Git e modello sotto il prompt. Evita di eseguire comandi sul server sbagliato durante sessioni SSH.
Cosa mostra una statusline di Claude Code
Una statusline di Claude Code è una riga sotto il prompt che visualizza l’output di uno script scritto dall’utente. Aggiungi un blocco statusLine a settings.json e configuralo in modo che punti a un comando. Claude Code esegue il comando, gli invia lo stato della sessione in formato JSON tramite lo standard input e stampa ciò che il comando scrive sullo standard output.
Questo è l’intero contratto. Lo script legge il JSON dallo standard input e stampa testo sullo standard output. Viene eseguito sul computer locale e nulla di ciò che stampa viene inviato al modello, quindi non consuma token.
Su un laptop con un solo progetto, è un elemento puramente informativo. Su tre server, è una protezione operativa. Ogni sessione di Claude Code ha lo stesso aspetto in ogni terminale; per questo, quattro finestre SSH senza etichette possono causare l’esecuzione di una migrazione sul server sbagliato. Una statusline che inizia con il nome host elimina questo tipo di errore.
Dove si trova l'impostazione statusLine in settings.json
Inseriscila nelle impostazioni utente in ~/.claude/settings.json, che si applicano a tutti i progetti presenti su quel computer. Funzionano anche le impostazioni del progetto in .claude/settings.json all'interno di un repository e hanno la precedenza per quella directory.
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh"
}
}type è sempre "command". Il valore command viene eseguito tramite una shell, quindi può essere il percorso di uno script o un comando semplice. Verifica il funzionamento del collegamento prima di scrivere uno script:
{
"statusLine": {
"type": "command",
"command": "hostname -s"
}
}Avvia Claude Code e invia un messaggio. La barra sotto il prompt ora mostra il nome host breve del server. Se resta vuota, il problema riguarda l'impostazione o la finestra di dialogo relativa all'attendibilità, non lo script. Leggi la sezione "Perché la statusline resta vuota" più avanti.
Ad agosto 2026 sono disponibili tre chiavi facoltative. padding aggiunge spaziatura orizzontale in caratteri e il valore predefinito è 0. refreshInterval riesegue il comando ogni N secondi, oltre ai normali trigger, con un minimo di 1. Usala solo quando la riga mostra un orologio o un altro valore che cambia mentre la sessione resta inattiva. hideVimModeIndicator nasconde il testo -- INSERT -- integrato quando lo script personalizzato visualizza già la modalità vim.
Quali dati riceve lo script della riga di stato?
Non fidarti di un elenco di campi trovato altrove, nemmeno in questa pagina. Acquisisci l’oggetto reale inviato dalla tua versione. Scrivi uno script temporaneo che salvi lo stdin in un file:
cat > ~/.claude/statusline-capture.sh <<'EOF'
#!/bin/bash
cat > /tmp/statusline-input.json
echo "captured"
EOF
chmod +x ~/.claude/statusline-capture.shConfigura statusLine.command in modo che punti a quel file, avvia una sessione e invia un messaggio. La barra legge captured. Ora controlla i dati ricevuti:
jq . /tmp/statusline-input.jsonIn questo modo ottieni la struttura esatta della tua build e puoi ripetere la procedura ogni volta che un aggiornamento modifica qualcosa.
Le parti stabili, secondo la documentazione disponibile ad agosto 2026, sono oggetti annidati e non chiavi piatte. model contiene id e display_name. workspace contiene current_dir e project_dir: current_dir indica la directory di lavoro corrente della sessione, project_dir quella da cui è stata avviata e i due valori diventano diversi quando la directory di lavoro cambia durante la sessione. Il valore di primo livello cwd contiene lo stesso valore di workspace.current_dir. context_window contiene i conteggi dei token e un used_percentage precalcolato. cost contiene total_cost_usd e i contatori della durata. session_id resta stabile per tutta la durata della sessione ed è univoco tra le sessioni, un aspetto importante per il caching descritto più avanti.
Tre regole aiutano a mantenere lo script compatibile con le modifiche allo schema.
Alcune chiavi sono assenti, non null. vim, agent, pr, worktree e effort compaiono soltanto quando la funzionalità corrispondente è attiva. Leggere .vim.mode con jq -r quando la modalità vim è disattivata stampa la stringa letterale null e la barra mostra null all’utente. Aggiungi // empty a ogni selettore, in modo che una chiave assente non stampi nulla.
Alcuni valori sono null all’inizio. context_window.used_percentage e context_window.current_usage sono null prima della prima risposta API e current_usage torna a null dopo /compact, finché la chiamata successiva non lo valorizza di nuovo. Perciò una percentuale del contesto nella barra richiede // 0; in caso contrario, per i primi secondi di ogni sessione viene letto null. Prima di visualizzare questo numero nella barra, è utile capire come si riempie effettivamente la finestra di contesto.
Il branch git non è presente nel JSON. Nessun campo lo riporta. Qualsiasi branch visualizzato nella barra viene ricavato dallo script, che esegue direttamente git.
Una statusline che degrada senza interrompersi
Questa è la versione pronta per il copia e incolla. Stampa hostname, directory di lavoro, branch Git e nome del modello. Ogni campo ha un valore di fallback, quindi anche un oggetto JSON vuoto produce comunque una riga utilizzabile.
#!/bin/bash
# ~/.claude/statusline.sh
input=$(cat)
# Read one field. Prints nothing when the key is missing or null.
field() { printf '%s' "$input" | jq -r "$1 // empty" 2>/dev/null; }
HOST=$(hostname -s 2>/dev/null)
[ -z "$HOST" ] && HOST="host"
DIR=$(field '.workspace.current_dir')
[ -z "$DIR" ] && DIR=$(field '.cwd')
[ -z "$DIR" ] && DIR="$PWD"
MODEL=$(field '.model.display_name')
[ -z "$MODEL" ] && MODEL="claude"
SHORT="$DIR"
if [ -n "$HOME" ]; then
case "$DIR" in
"$HOME") SHORT="~" ;;
"$HOME"/*) SHORT="~/${DIR#"$HOME"/}" ;;
esac
fi
BRANCH=""
if git -C "$DIR" rev-parse --git-dir >/dev/null 2>&1; then
BRANCH=$(git -C "$DIR" branch --show-current 2>/dev/null)
[ -z "$BRANCH" ] && BRANCH="detached"
fi
CYAN=$'\033[36m'
YELLOW=$'\033[33m'
DIM=$'\033[2m'
RESET=$'\033[0m'
LINE="${CYAN}${HOST}${RESET} ${SHORT}"
[ -n "$BRANCH" ] && LINE="${LINE} ${YELLOW}${BRANCH}${RESET}"
LINE="${LINE} ${DIM}${MODEL}${RESET}"
printf '%s\n' "$LINE"Ogni lettura passa da field, che aggiunge // empty. Di conseguenza, se una chiave è stata rinominata o rimossa, viene restituita una stringa vuota e la riga successiva fornisce un valore predefinito. La directory usa come fallback, nell'ordine, workspace.current_dir, cwd e $PWD. Il branch viene ricavato da git -C "$DIR" invece che da un semplice git, quindi corrisponde sempre alla directory visualizzata dalla statusline.
Salvare il file, quindi renderlo eseguibile:
chmod +x ~/.claude/statusline.shIl bit di esecuzione è obbligatorio. Claude Code esegue il comando tramite una shell, quindi uno script senza +x termina con Permission denied, non produce output su stdout e lascia la riga vuota senza mostrare errori.
jq analizza JSON dalla riga di comando e non è installato su un server Ubuntu appena configurato:
sudo apt update && sudo apt install -y jqImpostare quindi la configurazione in modo che punti allo script, usando il primo blocco settings.json riportato sopra.
Testa lo script prima di considerarlo affidabile
Eseguilo manualmente due volte. Prima con un oggetto di sessione normale:
echo '{"model":{"display_name":"Opus"},"workspace":{"current_dir":"/srv/api"},"session_id":"t1"}' | ~/.claude/statusline.shOttieni il nome host, quindi /srv/api, poi Opus. Non compare alcun ramo, perché /srv/api sul tuo sistema probabilmente non è un repository Git.
Secondo, esegui il test di degradazione, che spesso viene saltato:
echo '{}' | ~/.claude/statusline.shUn oggetto vuoto rappresenta il caso peggiore che una modifica allo schema possa fornire. La riga continua a stampare il nome host, la directory corrente ottenuta da $PWD e la parola claude al posto del nome del modello. Non si verifica alcun arresto anomalo e non viene stampato null. Uno script che supera questo test continua a funzionare anche se un campo viene rinominato, perché per lo script un campo rinominato e un campo mancante rappresentano lo stesso evento.
Cosa dovresti vedere
La riga di stato viene visualizzata su una riga propria, sopra i badge del footer integrati, senza sostituirli. In una configurazione funzionante contiene una sola riga: il nome host breve in ciano, quindi la directory di lavoro con la home directory abbreviata in ~, poi il nome del branch in giallo quando la directory è un repository git e infine il nome del modello attenuato. Il risultato è simile a web-01 ~/api main Opus, con questi quattro elementi colorati.
La riga riesegue lo script quando una sessione viene avviata, incluso il ripristino di una sessione, quando arriva un nuovo messaggio dell'assistente, al termine di /compact, quando cambia la modalità delle autorizzazioni, quando viene attivata o disattivata la modalità vim e a ogni intervallo di refreshInterval, se ne hai impostato uno. Gli aggiornamenti vengono raggruppati con un ritardo di 300 ms, quindi una sequenza ravvicinata di modifiche esegue lo script una sola volta. La barra viene nascosta durante il completamento automatico, nel menu della guida e nelle richieste di autorizzazione, quindi viene visualizzata nuovamente.
Perché il nome host viene prima
Quando mantieni agenti in esecuzione su più server, il terminale è l'unico elemento che indica dove ti trovi, ma i terminali possono fornire informazioni errate. Apri una seconda connessione ssh dall'interno di un riquadro tmux e il titolo della finestra spesso mantiene il nome precedente, perché viene impostato da una shell che non si è accorta del cambio di server. Lascia Claude Code in esecuzione in una sessione tmux scollegata su un VPS e ricollegati il giorno dopo: nulla sullo schermo distingue il server di build dal server di produzione.
La statusline è diversa perché viene generata direttamente da Claude Code, per ogni sessione, usando i dati memorizzati dalla sessione stessa. Non può essere ereditata dal riquadro sbagliato né rimanere obsoleta a causa di un prompt della shell mai aggiornato. Indica il server sul quale l'agente sta scrivendo i file.
Assegna a ogni server un colore distinto, così lo riconosci prima ancora di leggere il testo. Inserisci queste due righe sopra l'assegnazione LINE=:
CODE=$(printf '%s' "$HOST" | cksum | cut -d' ' -f1)
HOST_COLOR=$(printf '\033[%dm' "$((31 + CODE % 6))")Usa quindi ${HOST_COLOR} al posto di ${CYAN}. cksum calcola un checksum del nome host, quindi ogni nome viene sempre associato allo stesso colore nell'intervallo da 31 a 36, dal rosso al ciano. Copia lo stesso script su ogni server: ciascuno visualizzerà automaticamente la propria etichetta.
La directory è utile per lo stesso motivo. /srv/api e /srv/api-staging sono adiacenti sulla tastiera in un comando ssh, ma possono produrre conseguenze completamente diverse in un incidente. Il modello e il branch sono gli altri due elementi per cui vale la pena riservare spazio: il modello indica quale sessione hai ripreso, mentre il branch indica se l'agente sta per eseguire un commit su main.
Su uno schermo piccolo tutto questo è ancora più importante, perché non puoi fare affidamento sul titolo della finestra. Se questo è il tuo caso, consulta controllare Claude Code da un telefono.
Mantieni veloce lo script
Lo script viene eseguito per ogni messaggio dell'assistente e Claude Code annulla un'esecuzione in corso quando arriva un nuovo aggiornamento. Uno script lento mostra quindi testo obsoleto oppure non mostra alcun testo.
Ogni chiamata a jq richiede pochi millisecondi. git è la parte che rallenta: git status in un repository di grandi dimensioni con cache fredda richiede centinaia di millisecondi. Lo script precedente evita intenzionalmente git status e usa git branch --show-current, che legge .git/HEAD e restituisce subito il risultato.
Se aggiungi un'operazione più pesante, memorizzane il risultato in un file e aggiornalo ogni pochi secondi. Usa la sessione come chiave del file:
CACHE="/tmp/statusline-$(field '.session_id')"Usa session_id, non $$. $$ è l'ID del processo dello script, che cambia a ogni esecuzione. Una cache indicizzata con questo valore non produce mai un riscontro e il costo completo viene sostenuto ogni volta. session_id rimane stabile per tutta la sessione ed è diverso tra le sessioni, quindi due sessioni di Claude Code in due repository non possono leggere il nome del branch memorizzato nella cache dell'altra sessione. Per progettazione, le sessioni restano isolate; per trasferire il lavoro da una sessione all'altra è quindi necessario un passaggio esplicito. È proprio questo lo scopo di inviare un messaggio da una sessione di Claude Code a un'altra.
È utile conoscere anche un'altra limitazione: tput cols non funziona all'interno di uno script statusline. Claude Code acquisisce l'output invece di collegare lo script al terminale, quindi il rilevamento della larghezza non ha alcun valore da misurare. Nelle versioni v2.1.153 e successive, Claude Code imposta le variabili d'ambiente COLUMNS e LINES prima di eseguire il comando. Leggi $COLUMNS quando devi decidere quanto testo stampare.
Perché la statusline rimane vuota
Non viene visualizzato nulla. Verifica il bit di esecuzione con ls -l ~/.claude/statusline.sh, quindi esegui manualmente lo script usando l'input di esempio precedente. Se stampa una riga nella shell ma non in Claude Code, inizia da claude --debug, che registra il codice di uscita e lo stderr della prima esecuzione della statusline nella sessione.
Il log di debug indica Status line command skipped: workspace trust not accepted. La statusline esegue un comando shell, quindi è soggetta allo stesso controllo di attendibilità dell'area di lavoro degli hook. Finché non accetti la finestra di dialogo relativa all'attendibilità per quella directory, il comando non viene eseguito. Questo è comune su un VPS, dove ogni nuovo clone si trova in una directory che Claude Code non ha ancora rilevato. Riavvia Claude Code in quella directory e accetta la finestra di dialogo.
Tutto è vuoto e disableAllHooks è impostato. "disableAllHooks": true in settings.json disabilita anche la statusline, perché applica lo stesso controllo per l'esecuzione della shell. Rimuovilo oppure impostalo su false.
La riga stampa null. Un selettore jq ha raggiunto una chiave mancante o null e jq -r stampa null come i quattro caratteri null. Aggiungi // empty per il testo e // 0 per i numeri.
La riga diventa vuota subito dopo aver modificato lo script. Un comando che termina con un codice diverso da zero o che non stampa nulla rende vuota la riga. La causa più comune è una riga finale come [ -n "$BRANCH" ] && LINE="...", che restituisce 1 quando il ramo è vuoto e trasferisce il relativo codice di uscita all'intero script. Mantieni printf come ultima istruzione oppure aggiungi exit 0.
I codici di escape vengono visualizzati come testo letterale, ad esempio \e]8;; nella barra. Usa printf '%b' invece di echo -e. Anche i link OSC 8 cliccabili richiedono un terminale che li supporti, mentre tmux o SSH possono rimuovere queste sequenze; per questo, su un host remoto, il semplice colore è la scelta più sicura.
La parte destra della riga viene tagliata. Le notifiche di sistema e il contatore dettagliato dei token in modalità verbose condividono quella riga partendo da destra, e un terminale stretto non riesce a gestire la sovrapposizione. Mantieni breve l'output. Per un conteggio effettivo dell'utilizzo, invece di un numero visualizzato su una barra, consulta come Claude Code conta i token.
FAQ
Dove si trova l'impostazione della statusline di Claude Code?
Si trova in settings.json, in un blocco statusLine con type impostato su "command" e command impostato sul percorso di uno script o su un comando shell. Le impostazioni utente si trovano in ~/.claude/settings.json e si applicano a ogni progetto della macchina. Le impostazioni del progetto si trovano in .claude/settings.json all'interno del repository e hanno la precedenza per quella directory. Le impostazioni vengono ricaricate automaticamente, ma una modifica diventa visibile solo al successivo trigger di aggiornamento, ad esempio al messaggio successivo.
Perché la statusline di Claude Code è vuota?
Quattro cause spiegano quasi tutti i casi. Allo script manca il bit di esecuzione, quindi la shell restituisce Permission denied e non invia nulla a stdout. La finestra di dialogo relativa all'attendibilità dell'area di lavoro non è mai stata accettata e claude --debug registra Status line command skipped: workspace trust not accepted. disableAllHooks è true, quindi la statusline viene disabilitata dallo stesso controllo. In alternativa, lo script termina con un codice diverso da zero e la riga resta vuota. Esegui prima un test manuale: echo '{}' | ~/.claude/statusline.sh deve produrre un output.
Il JSON della statusline include il branch git?
No. Il JSON contiene lo stato della sessione, ad esempio il modello, le directory dell'area di lavoro, i valori della finestra di contesto e il costo. Non contiene informazioni su git. Il branch visualizzato nella barra viene ottenuto dallo script, che esegue git branch --show-current. Passa la directory dal JSON usando git -C "$DIR", così il branch corrisponde sempre alla directory visualizzata dalla barra.
La statusline consuma token o rallenta la sessione?
Non consuma token, perché lo script viene eseguito localmente e il suo output non viene mai inviato al modello. La velocità dipende dalla tua implementazione. Il comando viene eseguito a ogni messaggio dell'assistente con un debounce di 300 ms e Claude Code annulla un'esecuzione in corso quando arriva un nuovo aggiornamento. Di conseguenza, uno script che impiega un secondo intero visualizza testo non aggiornato. Evita git status nei repository di grandi dimensioni e memorizza nella cache i dati lenti in un file indicizzato con session_id.
Come posso visualizzare una statusline diversa su ogni server?
Usa uno script unico e lascia che rilevi la macchina. Lo script precedente stampa $HOSTNAME usando hostname -s come valore di fallback. Lo stesso file, copiato su ogni server, identifica quindi correttamente ciascuno di essi; inoltre, il metodo basato sul colore del checksum assegna a ogni hostname un colore distinto. Se un server richiede un layout diverso, inserisci un blocco statusLine nelle impostazioni del progetto del repository su cui lavori in quel server, perché le impostazioni del progetto hanno la precedenza su quelle utente per quella directory.