SSD Nodes Learn 🎉 VPS desde $4.99/mês
Guias Matt ConnorPor Matt Connor · Atualizado 2026-08-07

Como configurar uma statusline do Claude Code em VPS

Use statusLine para mostrar hostname, diretório, branch Git e modelo sob o prompt. Veja o script, o JSON de entrada e a configuração correta no VPS.

O que a statusline do Claude Code mostra

Uma statusline do Claude Code é uma linha sob o prompt que apresenta a saída de um script escrito por si. Adicione um bloco statusLine a settings.json e indique um comando. O Claude Code executa esse comando, envia-lhe o estado da sessão em JSON pela entrada padrão e apresenta tudo o que o comando escrever na saída padrão.

Esse é todo o contrato. O script lê JSON da entrada padrão e escreve texto na saída padrão. É executado na sua máquina e nada do que escreve é enviado para o modelo, pelo que não consome tokens.

Num laptop com um único projeto, isto é apenas decoração. Em três servidores, funciona como uma barreira de segurança. Todas as sessões do Claude Code têm o mesmo aspeto em todos os terminais, por isso quatro janelas SSH sem etiquetas podem fazer uma migração ser executada no servidor errado. Uma statusline que começa pelo hostname elimina esse tipo de erro.

Onde fica a configuração statusLine em settings.json

Coloque-a nas configurações do utilizador em ~/.claude/settings.json. Esta localização aplica-se a todos os projetos nessa máquina. As configurações do projeto em .claude/settings.json, dentro de um repositório, também funcionam e têm precedência para esse diretório.

{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.sh"
  }
}

type é sempre "command". O valor command é executado através de uma shell. Por isso, pode ser um caminho para um script ou um comando simples. Confirme primeiro que a ligação funciona, antes de escrever qualquer script:

{
  "statusLine": {
    "type": "command",
    "command": "hostname -s"
  }
}

Inicie o Claude Code e envie uma mensagem. A barra sob o pedido passa a mostrar o hostname curto do servidor. Se continuar vazia, o problema está na configuração ou na caixa de diálogo de confiança, não no seu script. Consulte a secção "Porque é que a statusline continua vazia" abaixo.

A partir de agosto de 2026, existem três chaves opcionais. padding adiciona espaçamento horizontal em caracteres e tem o valor predefinido 0. refreshInterval volta a executar o comando a cada N segundos, além dos acionadores normais, com um mínimo de 1. Use esta opção apenas quando a linha mostrar um relógio ou outro valor que mude enquanto a sessão permanece inativa. hideVimModeIndicator suprime o texto incorporado -- INSERT -- quando o seu próprio script já apresenta o modo vim.

Que dados o script do statusline recebe?

Não confie numa lista de campos que leia em qualquer lugar, incluindo nesta página. Capture o objeto real enviado pela sua versão. Escreva um script temporário que guarde o stdin num ficheiro:

cat > ~/.claude/statusline-capture.sh <<'EOF'
#!/bin/bash
cat > /tmp/statusline-input.json
echo "captured"
EOF
chmod +x ~/.claude/statusline-capture.sh

Aponte statusLine.command para esse ficheiro, inicie uma sessão e envie uma mensagem. A barra lê captured. Agora veja o que chegou:

jq . /tmp/statusline-input.json

Assim, tem a estrutura exata da sua compilação e pode repetir o procedimento sempre que uma atualização alterar alguma coisa.

As partes estáveis, conforme documentado em agosto de 2026, são objetos aninhados, não chaves simples. model contém id e display_name. workspace contém current_dir e project_dir: current_dir indica onde a sessão está agora, project_dir indica de onde foi iniciada, e os dois valores diferem quando o diretório de trabalho muda durante a sessão. O cwd de nível superior contém o mesmo valor que workspace.current_dir. context_window contém as contagens de tokens e um used_percentage pré-calculado. cost contém total_cost_usd e contadores de duração. session_id permanece estável durante toda a sessão e é exclusivo entre sessões, o que é importante para a cache mais tarde.

Três regras mantêm um script funcional durante alterações do esquema.

Algumas chaves estão ausentes, não são nulas. vim, agent, pr, worktree e effort só aparecem quando a funcionalidade correspondente está ativa. Ler .vim.mode com jq -r quando o modo vim está desativado imprime a cadeia literal null, e a barra mostra null ao utilizador. Acrescente // empty a cada seletor para que uma chave ausente não imprima nada.

Alguns valores são nulos inicialmente. context_window.used_percentage e context_window.current_usage são nulos antes da primeira resposta da API, e current_usage volta a ser nulo depois de /compact, até que a chamada seguinte o preencha novamente. Por isso, uma percentagem de contexto na barra precisa de // 0; caso contrário, mostra null durante os primeiros segundos de cada sessão. Antes de colocar esse número numa barra, é útil saber como a janela de contexto é efetivamente preenchida.

A branch do git não está no JSON. Nenhum campo a informa. Qualquer branch apresentada na barra vem do próprio script, que executa git.

Um script de statusline que degrada em vez de falhar

Esta é a versão pronta para copiar e colar. Mostra o hostname, o diretório de trabalho, o branch do git e o nome do modelo. Cada campo tem um fallback, por isso até um objeto JSON vazio produz uma linha utilizável.

#!/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"

Todas as leituras passam por field, que acrescenta // empty. Assim, uma chave renomeada ou removida produz uma string vazia, e a linha seguinte fornece um valor predefinido. O diretório usa como fallback workspace.current_dir, depois cwd e, por fim, $PWD. O branch vem de git -C "$DIR", e não de um git isolado. Desta forma, o branch corresponde sempre ao diretório mostrado pela barra.

Guarde o ficheiro e torne-o executável:

chmod +x ~/.claude/statusline.sh

O bit de execução é obrigatório. O Claude Code executa o comando através de uma shell. Por isso, um script sem +x falha com Permission denied, não produz stdout e deixa a linha em branco sem apresentar um erro visível.

jq analisa JSON na linha de comandos e não está instalado num servidor Ubuntu recém-instalado:

sudo apt update && sudo apt install -y jq

Depois, aponte a definição para o script, usando o primeiro bloco settings.json acima.

Teste o script antes de confiar nele

Execute-o manualmente duas vezes. Primeiro, com um objeto de sessão normal:

echo '{"model":{"display_name":"Opus"},"workspace":{"current_dir":"/srv/api"},"session_id":"t1"}' | ~/.claude/statusline.sh

É apresentado o nome do host, depois /srv/api e, em seguida, Opus. Não aparece nenhuma branch, porque /srv/api na sua máquina provavelmente não é um repositório Git.

Em seguida, faça o teste de degradação, que é o que as pessoas costumam ignorar:

echo '{}' | ~/.claude/statusline.sh

Um objeto vazio é o pior caso que uma alteração de esquema pode fornecer. A linha continua a apresentar o nome do host, o diretório atual obtido de $PWD e a palavra claude no lugar do nome do modelo. Nada falha e nada apresenta null. Um script que passa neste teste continua a funcionar quando um campo é renomeado, porque, para o script, um campo renomeado e um campo ausente são o mesmo evento.

O que deve aparecer

A linha de estado é apresentada na sua própria linha, acima dos indicadores do rodapé incorporados, e não os substitui. Numa configuração funcional, existe uma linha com quatro elementos: o nome curto do host a ciano, seguido do diretório de trabalho, com o diretório pessoal reduzido a ~, depois o nome do branch a amarelo quando o diretório é um repositório git e, por fim, o nome do modelo com menor intensidade. O resultado deve ser semelhante a web-01 ~/api main Opus, com essas quatro partes coloridas.

A linha executa novamente o seu script quando uma sessão começa, incluindo ao retomar uma sessão, quando chega uma nova mensagem do assistente, depois de /compact terminar, quando o modo de permissões muda, quando o modo vim é ativado ou desativado e a cada intervalo de refreshInterval, se tiver definido um. As atualizações são agrupadas durante 300 ms, por isso uma sequência rápida de alterações executa o script uma vez. A barra fica oculta durante o preenchimento automático, o menu de ajuda e os pedidos de permissão. Depois, volta a aparecer.

Por que o hostname vem primeiro

Quando mantém agentes em execução em mais de um servidor, o terminal é a única coisa que indica onde está, e os terminais enganam. Abra uma segunda ligação ssh a partir de um painel do tmux e o título da janela muitas vezes mantém o nome antigo, porque o título é definido por uma shell que nunca percebeu que mudou de servidor. Deixe o Claude Code em execução numa sessão tmux desanexada num VPS e volte a ligar-se um dia depois. Nada no ecrã distingue o servidor de build do servidor de produção.

A linha de estado é diferente porque é renderizada pelo próprio Claude Code, por sessão, com base nos dados dessa sessão. Não pode ser herdada do painel errado nem ficar desatualizada por causa de um prompt da shell que nunca foi atualizado. O que ela mostra é o servidor no qual o agente está a escrever ficheiros.

Atribua uma cor própria a cada servidor para o reconhecer antes de ler o texto. São necessárias duas linhas, inseridas acima da atribuição LINE=:

CODE=$(printf '%s' "$HOST" | cksum | cut -d' ' -f1)
HOST_COLOR=$(printf '\033[%dm' "$((31 + CODE % 6))")

Depois, use ${HOST_COLOR} no lugar de ${CYAN}. cksum calcula uma soma de verificação do hostname. Assim, um determinado nome corresponde sempre à mesma cor no intervalo de 31 a 36, que vai de vermelho a ciano. Copie o mesmo script para todos os servidores e cada um identifica-se automaticamente.

O diretório também merece estar na linha de estado pelo mesmo motivo. /srv/api e /srv/api-staging ficam separados por uma tecla num comando ssh, mas a diferença pode corresponder a um incidente inteiro. O modelo e o branch são os outros dois elementos que justificam o espaço: o modelo indica que sessão retomou, e o branch indica se o agente está prestes a fazer commit em main.

Um ecrã pequeno torna tudo isto ainda mais importante, porque não há título de janela ao qual recorrer. Se esse for o seu caso, consulte controlar o Claude Code a partir de um telemóvel.

Mantenha o script rápido

O script é executado em cada mensagem do assistente, e o Claude Code cancela uma execução em curso quando chega uma nova atualização. Por isso, um script lento pode mostrar texto desatualizado ou não mostrar texto algum.

Cada chamada a jq custa alguns milissegundos. git é a parte que fica lenta: git status num repositório grande, com a cache fria, demora centenas de milissegundos. O script anterior evita git status deliberadamente e chama git branch --show-current, que lê .git/HEAD e retorna imediatamente.

Se adicionar algo mais pesado, coloque o resultado em cache num ficheiro e atualize-o a cada poucos segundos. Use a sessão como chave do ficheiro:

CACHE="/tmp/statusline-$(field '.session_id')"

Use session_id, não $$. $$ é o ID do processo do script, que muda em cada execução. Por isso, uma cache baseada nele nunca é reutilizada e o custo total é pago todas as vezes. session_id permanece estável durante toda a sessão e é diferente entre sessões. Assim, duas sessões do Claude Code em dois repositórios não conseguem ler o nome de branch colocado em cache pela outra sessão.

Há mais uma limitação importante: tput cols não funciona dentro de um script de statusline. O Claude Code captura a saída em vez de associar o script ao terminal, portanto não há nada cuja largura possa ser detetada. O Claude Code define as variáveis de ambiente COLUMNS e LINES antes de executar o comando, na versão v2.1.153 e posteriores. Leia $COLUMNS quando precisar de decidir quanto texto imprimir.

Por que a linha de estado fica em branco

Não aparece absolutamente nada. Verifique o bit de execução com ls -l ~/.claude/statusline.sh e execute o script manualmente com a entrada simulada acima. Se ele imprimir uma linha no shell, mas não no Claude Code, comece por claude --debug, que regista o código de saída e o stderr da primeira execução da linha de estado na sessão.

O log de depuração indica Status line command skipped: workspace trust not accepted. A linha de estado executa um comando shell, por isso fica sujeita ao mesmo mecanismo de confiança no workspace que os hooks. Até aceitar a caixa de diálogo de confiança para esse diretório, o comando não é executado. Isto é comum numa VPS, onde cada novo clone fica num diretório que o Claude Code ainda não conhece. Reinicie o Claude Code nesse diretório e aceite a caixa de diálogo.

Tudo fica em branco e disableAllHooks está definido. "disableAllHooks": true em settings.json também desativa a linha de estado, porque utiliza o mesmo mecanismo de execução de shell. Remova-o ou defina-o como false.

A linha imprime null. Um seletor jq chegou a uma chave inexistente ou nula, e jq -r imprime null como os quatro caracteres null. Adicione // empty para texto e // 0 para números.

A linha fica em branco logo depois de editar o script. Um comando que termina com um código diferente de zero ou que não imprime nada deixa a linha em branco. A causa habitual é uma linha final como [ -n "$BRANCH" ] && LINE="...", que termina com 1 quando o ramo está vazio e transmite o código de saída ao script inteiro. Mantenha printf como última linha ou adicione exit 0.

Os códigos de escape aparecem como texto literal, como \e]8;; na barra. Use printf '%b' em vez de echo -e. As ligações OSC 8 clicáveis também precisam de um terminal que as suporte, e o tmux ou o SSH podem remover essas sequências. Por isso, numa máquina remota, a cor simples é a opção mais segura.

O lado direito da linha fica cortado. As notificações do sistema e o contador de tokens do modo detalhado partilham essa linha a partir da direita, e um terminal estreito não tem espaço suficiente para ambos. Mantenha a saída curta. Para obter uma contabilização real da utilização, em vez de um número numa barra, consulte como o Claude Code contabiliza tokens.

FAQ

Onde fica a configuração da linha de estado do Claude Code?

Em settings.json, num bloco statusLine com type definido como "command" e command definido como um caminho de script ou um comando de shell. As configurações do utilizador ficam em ~/.claude/settings.json e aplicam-se a todos os projetos nessa máquina. As configurações do projeto ficam em .claude/settings.json dentro do repositório e têm precedência nesse diretório. As configurações são recarregadas automaticamente, mas uma alteração só fica visível no próximo evento de atualização, como a sua próxima mensagem.

Por que a minha linha de estado do Claude Code está em branco?

Quatro causas abrangem quase todos os casos. O script não tem o bit de execução, por isso a shell devolve Permission denied e nada chega a stdout. O diálogo de confiança do workspace nunca foi aceite, e claude --debug regista Status line command skipped: workspace trust not accepted. disableAllHooks é true, o que desativa a linha de estado sob a mesma condição. Ou o script termina com um código diferente de zero, o que deixa a linha em branco. Teste-o manualmente primeiro: echo '{}' | ~/.claude/statusline.sh tem de imprimir alguma coisa.

O JSON da linha de estado inclui o branch do git?

Não. O JSON contém o estado da sessão, como o modelo, os diretórios do workspace, os valores da janela de contexto e o custo. Não inclui qualquer informação sobre o git. Um branch na sua barra vem do seu próprio script, que chama git branch --show-current. Passe o diretório do JSON com git -C "$DIR", para que o branch corresponda sempre ao diretório mostrado pela barra.

A linha de estado consome tokens ou torna a sessão mais lenta?

Não consome tokens, porque o script é executado localmente e a sua saída nunca é enviada para o modelo. A velocidade depende de si. O comando é executado a cada mensagem do assistente, com um debounce de 300 ms, e o Claude Code cancela uma execução em curso quando chega uma nova atualização. Por isso, um script que demora um segundo inteiro mostra texto desatualizado. Evite git status em repositórios grandes e coloque em cache num ficheiro qualquer operação lenta, usando session_id como chave.

Como mostro uma linha de estado diferente em cada servidor?

Mantenha um único script e faça-o ler a máquina. O script acima imprime $HOSTNAME, usando hostname -s como fallback. Assim, o mesmo ficheiro copiado para cada servidor identifica corretamente cada um, e o truque da cor baseada no checksum atribui uma cor própria a cada hostname. Se um servidor precisar de um layout diferente, coloque um bloco statusLine nas configurações do projeto do repositório em que trabalha nesse servidor, porque as configurações do projeto têm precedência sobre as configurações do utilizador nesse diretório.