SSD Nodes Learn 🎉 VPS desde $4.99/mes
Guías Matt ConnorPor Matt Connor · Actualizado 2026-08-07

Configurar una statusline de Claude Code en un VPS

Configura statusLine para mostrar host, directorio, rama Git y modelo bajo el prompt. El script recibe el estado JSON por stdin y escribe en stdout.

Qué muestra una statusline de Claude Code

Una statusline de Claude Code es una línea situada debajo del prompt que muestra la salida de un script que usted escribe. Añada un bloque statusLine a settings.json y asígnele 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 en la salida estándar todo lo que el comando escriba.

Ese es todo el contrato. El script lee JSON desde la entrada estándar y muestra texto en la salida estándar. Se ejecuta en su máquina 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 un elemento visual. En tres servidores, es una medida de seguridad. Todas las sesiones de Claude Code tienen el mismo aspecto en cada terminal. Por eso, cuatro ventanas SSH sin etiquetas pueden hacer que una migración se ejecute en el servidor equivocado. Una statusline que empieza con el nombre de host evita este tipo de error.

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

Colóquela en 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 integració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 prompt mostrará ahora el nombre de host corto del servidor. Si sigue vacía, el problema está en la configuración o en el diálogo de confianza, no en el script. Consulte «Por qué statusline permanece vacío» más abajo.

A fecha de agosto de 2026 existen tres claves opcionales. padding añade espacio horizontal en caracteres y tiene el valor predeterminado 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 o algún valor que cambie mientras la sesión permanece inactiva. hideVimModeIndicator suprime el texto integrado -- INSERT -- cuando el propio script 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

Haga que statusLine.command apunte a ese archivo, inicie una sesión y envíe un mensaje. La barra lee captured. Ahora compruebe qué ha llegado:

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á ahora la sesión, 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, algo importante para el almacenamiento en caché posterior.

Tres reglas permiten que un script siga funcionando aunque cambie el esquema.

Algunas claves están ausentes, no tienen el valor 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 tienen el valor null antes de la primera respuesta de la API, y current_usage vuelve a tener el valor 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 el JSON. No existe ningún campo que la indique. Cualquier rama que aparezca en la barra procede de que el script ejecute git directamente.

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í, si una clave se renombra o se elimina, 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 valores alternativos. La rama se obtiene mediante git -C "$DIR" en lugar de usar un git independiente, por lo que 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, apunte la configuración al script utilizando 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 equipo.

Después, la prueba de degradación, que suele omitirse:

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 muestra 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 son el mismo evento.

Lo que debería ver

La línea de estado se muestra en su propia fila, encima de los distintivos del pie integrados, y no los reemplaza. En una configuración operativa, contiene una fila con cuatro elementos: el nombre corto del host en cian, el directorio de trabajo con el directorio personal contraído a ~, el nombre de la rama en amarillo cuando el directorio es un repositorio git y el nombre del modelo atenuado. El resultado debe ser parecido a web-01 ~/api main Opus, con esos cuatro elementos coloreados.

La fila vuelve a ejecutar el script cuando se inicia una sesión, incluido un reanudo, cuando llega un mensaje nuevo del asistente, después de que finaliza /compact, 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 vuelve a mostrarse después.

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 se equivocan. 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 de tmux separada 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 directamente para cada sesión, a partir de los datos que esa sesión conserva. No puede heredarse del panel equivocado ni quedar obsoleta porque un indicador de shell no se haya actualizado. Lo que muestra es el servidor en el que el agente está escribiendo los archivos.

Asigne a cada servidor su propio color 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 muestra una suma de comprobación del nombre de host, por lo que un nombre determinado siempre se asigna al mismo color dentro del rango 31 a 36, que va del rojo al cian. Copie el mismo script en cada servidor y cada uno se identificará por sí solo.

El directorio merece su lugar 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 justifican el espacio: el modelo indica qué sesión reanudó, y la rama indica si el agente está a punto de hacer commit en main.

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

Mantenga el script rápido

El script se ejecuta con 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 nada.

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

Si añade una operación más pesada, guarde el resultado 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 del script, que cambia en cada ejecución, por lo que una caché basada en él nunca tiene coincidencias y siempre se paga el coste completo. session_id permanece estable durante toda la sesión y cambia entre sesiones, de modo que dos sesiones de Claude Code en dos repositorios no pueden leer el nombre de rama almacenado en la caché de la otra sesión.

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 asociar el script al terminal, por lo que la detección del ancho no tiene ningún valor que medir. Claude Code establece las variables de entorno COLUMNS y LINES antes de ejecutar el comando, en v2.1.153 y versiones 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 con 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 cuadro de diálogo de confianza para ese directorio. Esto es habitual en un VPS, donde cada clon nuevo está en un directorio que Claude Code todavía no conoce. Reinicie Claude Code en ese directorio y acepte el cuadro de diálogo.

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

La fila imprime null. Un selector de jq llegó a una clave que falta o cuyo valor es 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 código sea también el código de salida de todo el script. Mantenga printf al final 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 esas 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 truncado. Las notificaciones del sistema y el contador de tokens del modo detallado comparten esa fila desde la derecha, y un terminal estrecho provoca una superposición. Mantenga corta la salida. Para obtener un recuento real del uso en lugar de un número en una barra, consulte cómo cuenta los tokens Claude Code.

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 de 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 será visible con el siguiente desencadenador de actualización, como el siguiente mensaje.

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

Casi todos los casos se deben a una de cuatro causas. El script no tiene el permiso de ejecución, por lo que el shell devuelve Permission denied y no se escribe nada en 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 comprobación. O el script termina con un código distinto de cero y deja la fila vacía. Pruébelo primero manualmente: echo '{}' | ~/.claude/statusline.sh debe imprimir algo.

¿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 valores de la ventana de contexto y el coste. No contiene información de 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 corresponda al 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 una ejecución en curso cuando llega una nueva actualización. Por eso, un script que 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 muestro 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. Así, el mismo archivo copiado en cada servidor identifica correctamente cada máquina, y el método basado en el color de la suma de comprobación asigna un color propio a cada nombre de host. 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, ya que la configuración del proyecto tiene prioridad sobre la configuración de usuario para ese directorio.