SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor · Actualizado 2026-08-23

Configurar statusLine de Claude Code en un VPS

Aprenda a mostrar hostname, directorio, rama de Git y modelo bajo el prompt con statusLine, leyendo el estado JSON y evitando editar el servidor equivocado.

Qué muestra la línea de estado de Claude Code

Una línea de estado de Claude Code es una fila situada debajo del indicador que muestra la salida de un script que usted escribe. Añada un bloque statusLine a settings.json y configúrelo para que ejecute un comando. Claude Code ejecuta ese comando, le envía el estado de la sesión como JSON mediante la entrada estándar y muestra todo lo que el comando escribe en la salida estándar.

Ese es todo el contrato. El script lee JSON de stdin y muestra texto en stdout. Se ejecuta en su equipo y nada de lo que muestra se envía al modelo, por lo que no consume tokens.

En un portátil con un solo proyecto, esto es decorativo. En tres servidores, es una medida de seguridad. Todas las sesiones de Claude Code tienen el mismo aspecto en todos los terminales, por lo que cuatro ventanas SSH sin etiquetas pueden hacer que una migración se aplique al servidor equivocado. Una línea de estado que comienza con el nombre de host evita este tipo de error.

Dónde se encuentra la configuración statusLine en settings.json

Añádala a la configuración de usuario en ~/.claude/settings.json. Se aplica a todos los proyectos de ese equipo. La configuración del proyecto en .claude/settings.json dentro de un repositorio también funciona y tiene prioridad para ese directorio.

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

type siempre es "command". El valor de command se ejecuta mediante un shell, por lo que puede ser una ruta de script o un comando simple. Compruebe que la conexión funciona antes de escribir ningún script:

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

Inicie Claude Code y envíe un mensaje. La barra situada debajo del indicador muestra ahora el nombre corto del servidor. Si permanece vacía, el problema está en la configuración o en el cuadro de diálogo de confianza, no en el script. Consulte «Por qué statusline permanece vacío» más abajo.

Desde agosto de 2026 existen tres claves opcionales. padding añade espacio horizontal en caracteres y su valor predeterminado es 0. refreshInterval vuelve a ejecutar el comando cada N segundos además de los desencadenadores normales, con un mínimo de 1. Úselo sólo cuando la línea muestre un reloj u otro valor que cambie mientras la sesión permanece inactiva. hideVimModeIndicator oculta el texto integrado -- INSERT -- cuando el script propio ya muestra el modo de vim.

¿Qué datos recibe el script de statusline?

No confíe en una lista de campos que haya leído en cualquier sitio, incluida esta página. Capture el objeto real que envía su versión. Escriba un script temporal que guarde stdin en un archivo:

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

Indique a statusLine.command que use ese archivo, inicie una sesión y envíe un mensaje. La barra lee captured. Ahora revise lo que llegó:

jq . /tmp/statusline-input.json

Así obtiene la estructura exacta de su compilación y puede repetir el proceso cada vez que una actualización cambie algo.

Las partes estables, según la documentación de agosto de 2026, son objetos anidados y no claves planas. model contiene id y display_name. workspace contiene current_dir y project_dir: current_dir indica dónde está la sesión ahora, project_dir indica dónde se inició y ambos valores difieren cuando el directorio de trabajo cambia durante la sesión. El cwd de nivel superior contiene el mismo valor que workspace.current_dir. context_window contiene los recuentos de tokens y un used_percentage precalculado. cost contiene total_cost_usd y los contadores de duración. session_id permanece estable durante toda la sesión y es único entre sesiones, lo que resulta importante para el almacenamiento en caché posterior.

Tres reglas mantienen un script operativo aunque cambie el esquema.

Algunas claves están ausentes, no son null. vim, agent, pr, worktree y effort sólo aparecen cuando la función correspondiente está activa. Leer .vim.mode con jq -r mientras el modo vim está desactivado imprime la cadena literal null, y la barra muestra null al usuario. Añada // empty a cada selector para que una clave ausente no imprima nada.

Algunos valores son null al principio. context_window.used_percentage y context_window.current_usage son null antes de la primera respuesta de la API, y current_usage vuelve a ser null después de /compact hasta que la siguiente llamada lo rellena de nuevo. Por tanto, un porcentaje de contexto en la barra necesita // 0; de lo contrario, muestra null durante los primeros segundos de cada sesión. Antes de mostrar ese número en una barra, conviene saber cómo se llena realmente la ventana de contexto.

La rama de git no está en JSON. No existe ningún campo que la indique. Cualquier rama que aparezca en la barra procede de que el script ejecute git por su cuenta.

Una línea de estado que se degrada en lugar de fallar

Esta es la versión lista para copiar y pegar. Muestra el nombre de host, el directorio de trabajo, la rama de git y el nombre del modelo. Cada campo tiene un valor alternativo, por lo que incluso un objeto JSON vacío genera una línea utilizable.

#!/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 las lecturas pasan por field, que añade // empty. Así, una clave renombrada o eliminada produce una cadena vacía y la línea siguiente proporciona un valor predeterminado. El directorio usa workspace.current_dir, luego cwd y finalmente $PWD como alternativas. La rama se obtiene mediante git -C "$DIR" en lugar de usar un git independiente. De este modo, la rama siempre coincide con el directorio que muestra la barra.

Guárdelo y conviértalo en ejecutable:

chmod +x ~/.claude/statusline.sh

El bit de ejecución es obligatorio. Claude Code ejecuta el comando mediante un shell, por lo que un script sin +x falla con Permission denied, no produce salida estándar y la fila queda vacía sin mostrar ningún error.

jq analiza JSON en la línea de comandos y no está instalado en un servidor Ubuntu recién instalado:

sudo apt update && sudo apt install -y jq

A continuación, configure el ajuste para que apunte al script mediante el primer bloque settings.json anterior.

Pruebe el script antes de confiar en él

Ejecútelo dos veces manualmente. Primero con un objeto de sesión normal:

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

Obtendrá el nombre de host, después /srv/api y luego Opus. No aparece ninguna rama porque /srv/api probablemente no es un repositorio de git en su máquina.

Después, la prueba de degradación, que es la que se suele omitir:

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

Un objeto vacío es el peor caso que puede producir un cambio de esquema. La línea sigue mostrando el nombre de host, el directorio actual de $PWD y la palabra claude donde debería aparecer el nombre del modelo. No se produce ningún error y no se imprime null. Un script que supera esta prueba sigue funcionando aunque se cambie el nombre de un campo, porque para el script un campo renombrado y un campo ausente representan el mismo evento.

Qué debería ver

La línea de estado se muestra en su propia fila, encima de las insignias del pie integradas, y no las sustituye. En una configuración funcional, ocupa una fila: el nombre de host corto en cian, seguido del directorio de trabajo con el directorio personal contraído a ~, después el nombre de la rama en amarillo cuando el directorio es un repositorio git y, por último, el nombre del modelo atenuado. El resultado debe ser parecido a web-01 ~/api main Opus, con esas cuatro partes coloreadas.

La fila vuelve a ejecutar el script cuando se inicia una sesión, incluido un reanudado, cuando llega un mensaje nuevo del asistente, después de que /compact termina, cuando cambia el modo de permisos, cuando se activa o desactiva el modo vim y en cada intervalo de refreshInterval si se configura uno. Las actualizaciones se agrupan durante 300 ms, por lo que una ráfaga de cambios ejecuta el script una sola vez. La barra se oculta durante el autocompletado, el menú de ayuda y las solicitudes de permisos, y después vuelve a mostrarse.

Por qué el nombre de host va primero

Cuando mantiene agentes en más de un servidor, el terminal es lo único que indica dónde está, y los terminales pueden engañar. Abra una segunda conexión ssh desde un panel de tmux y el título de la ventana suele conservar el nombre anterior, porque lo establece un shell que nunca detectó el cambio. Deje Claude Code ejecutándose en una sesión tmux desconectada en un VPS y vuelva a conectarse un día después: nada en pantalla distingue el servidor de compilación del servidor de producción.

La línea de estado es diferente porque Claude Code la genera por sí mismo para cada sesión, a partir de los datos que conserva esa sesión. No puede heredarse del panel equivocado ni quedar obsoleta porque un prompt de shell no se haya actualizado. Muestra el servidor en el que el agente está escribiendo archivos.

Asigne un color propio a cada servidor para reconocerlo antes de leerlo. Añada estas dos líneas encima de la asignación LINE=:

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

Después use ${HOST_COLOR} en lugar de ${CYAN}. cksum genera una suma de comprobación del nombre de host, de modo que un nombre determinado siempre se asigna al mismo color dentro del rango 31 a 36, que va de rojo a cian. Copie el mismo script en cada servidor y cada uno se identificará por sí mismo.

El directorio también es importante por la misma razón. /srv/api y /srv/api-staging están separados por una sola pulsación en un comando ssh, pero sus efectos pueden marcar la diferencia entre una operación normal y un incidente. El modelo y la rama son los otros dos datos que merecen espacio: el modelo indica qué sesión reanudó, y la rama indica si el agente está a punto de confirmar cambios en main.

Una pantalla pequeña hace que todo esto sea más importante, porque no hay un título de ventana al que recurrir. Si ese es su caso, consulte controlar Claude Code desde un teléfono.

Mantenga el script rápido

El script se ejecuta en cada mensaje del asistente y Claude Code cancela una ejecución en curso cuando llega una actualización nueva. Por tanto, un script lento muestra texto obsoleto o no muestra ningún texto.

Cada llamada a jq cuesta unos milisegundos. git es la parte que se vuelve lenta: git status en un repositorio grande con la caché fría tarda cientos de milisegundos. El script anterior evita git status de forma intencionada y llama a git branch --show-current, que lee .git/HEAD y devuelve el resultado de inmediato.

Si añade algo más costoso, guárdelo en un archivo de caché y actualícelo cada pocos segundos. Use la sesión como clave del archivo:

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

Use session_id, no $$. $$ es el ID de proceso de su script y cambia en cada ejecución, por lo que una caché basada en ese valor nunca acierta y debe pagar el coste completo cada vez. session_id es estable durante toda la sesión y diferente entre sesiones, por lo que dos sesiones de Claude Code en dos repositorios no pueden leer el nombre de rama almacenado en la caché de la otra. Las sesiones permanecen aisladas de esa forma por diseño. Para que una sesión entregue trabajo a otra hace falta un paso explícito. Para eso sirve enviar un mensaje de una sesión de Claude Code a otra.

Hay otro límite que conviene conocer: tput cols no funciona dentro de un script de statusline. Claude Code captura la salida en lugar de conectar el script al terminal, por lo que la detección del ancho no tiene nada que medir. Claude Code establece las variables de entorno COLUMNS y LINES antes de ejecutar el comando, en v2.1.153 y posteriores. Lea $COLUMNS cuando necesite decidir cuánto texto mostrar.

Por qué la línea de estado permanece vacía

No aparece nada. Compruebe el bit de ejecución con ls -l ~/.claude/statusline.sh y ejecute después el script manualmente con la entrada de prueba anterior. Si imprime una línea en el shell, pero no en Claude Code, empiece por claude --debug, que registra el código de salida y la salida de error de la primera ejecución de la línea de estado de la sesión.

El registro de depuración indica Status line command skipped: workspace trust not accepted. La línea de estado ejecuta un comando de shell, por lo que está sujeta al mismo control de confianza del espacio de trabajo que los hooks. El comando no se ejecuta hasta que acepte el diálogo de confianza para ese directorio. Esto es habitual en un VPS, donde cada clon nuevo está en un directorio que Claude Code aún no conoce. Reinicie Claude Code en ese directorio y acepte el diálogo.

Todo está vacío y disableAllHooks está definido. "disableAllHooks": true en settings.json también deshabilita la línea de estado, porque utiliza el mismo control de ejecución del shell. Elimínelo o establézcalo en false.

La fila muestra null. Un selector de jq ha llegado a una clave ausente o con valor null, y jq -r imprime null como los cuatro caracteres null. Añada // empty para texto y // 0 para números.

La fila queda vacía justo después de editar el script. Un comando que termina con un código distinto de cero o que no imprime nada deja la fila vacía. La causa habitual es una línea final como [ -n "$BRANCH" ] && LINE="...", que termina con el código 1 cuando la rama está vacía y hace que ese sea el código de salida de todo el script. Mantenga printf como última línea o añada exit 0.

Los códigos de escape aparecen como texto literal, por ejemplo \e]8;; en la barra. Use printf '%b' en lugar de echo -e. Los enlaces OSC 8 interactivos también necesitan un terminal que los admita, y tmux o SSH pueden eliminar estas secuencias, por lo que el color simple es la opción más segura en un sistema remoto.

El lado derecho de la fila aparece cortado. Las notificaciones del sistema y el contador de tokens del modo detallado comparten esa fila desde la derecha, y un terminal estrecho no puede mostrar correctamente el contenido superpuesto. Mantenga la salida breve. Para obtener un cálculo real del uso, en lugar de un número en una barra, consulte cómo cuenta Claude Code los tokens.

FAQ

¿Dónde se encuentra la configuración de la línea de estado de Claude Code?

Se encuentra en settings.json, como un bloque statusLine con type establecido en "command" y command establecido en una ruta de script o un comando de shell. La configuración del usuario está en ~/.claude/settings.json y se aplica a todos los proyectos de esa máquina. La configuración del proyecto está en .claude/settings.json dentro del repositorio y tiene prioridad para ese directorio. La configuración se vuelve a cargar automáticamente, pero un cambio sólo se muestra con el siguiente desencadenador de actualización, como el siguiente mensaje.

¿Por qué está vacía la línea de estado de Claude Code?

Hay cuatro causas que cubren casi todos los casos. Al script le falta el bit de ejecución, por lo que el shell devuelve Permission denied y no llega nada a stdout. Nunca se aceptó el cuadro de diálogo de confianza del espacio de trabajo y claude --debug registra Status line command skipped: workspace trust not accepted. disableAllHooks es true, lo que desactiva la línea de estado con la misma condición. También puede que el script termine con un código distinto de cero, lo que deja vacía la fila. Pruébelo primero manualmente: echo '{}' | ~/.claude/statusline.sh debe mostrar algún resultado.

¿El JSON de la línea de estado incluye la rama de git?

No. El JSON contiene información de la sesión, como el modelo, los directorios del espacio de trabajo, los números de la ventana de contexto y el coste. No contiene ninguna información sobre git. La rama que aparece en la barra procede de su propio script, que ejecuta git branch --show-current. Pase el directorio desde el JSON mediante git -C "$DIR", para que la rama siempre coincida con el directorio que muestra la barra.

¿La línea de estado consume tokens o ralentiza la sesión?

No consume tokens, porque el script se ejecuta localmente y su salida nunca se envía al modelo. La velocidad depende de usted. El comando se ejecuta con cada mensaje del asistente, con un debounce de 300 ms, y Claude Code cancela la ejecución en curso cuando llega una actualización nueva. Por eso, si el script tarda un segundo completo, muestra texto obsoleto. Evite git status en repositorios grandes y almacene en caché cualquier operación lenta en un archivo identificado mediante session_id.

¿Cómo puedo mostrar una línea de estado diferente en cada servidor?

Mantenga un solo script y haga que lea la máquina. El script anterior muestra $HOSTNAME y usa hostname -s como alternativa. De este modo, el mismo archivo copiado en cada servidor identifica correctamente cada máquina, y el método del color basado en la suma de comprobación asigna a cada nombre de host su propio color. Si un servidor necesita un diseño diferente, coloque un bloque statusLine en la configuración del proyecto del repositorio en el que trabaja en ese servidor, porque la configuración del proyecto tiene prioridad sobre la configuración del usuario para ese directorio.