Claude Code siempre encendido: Remote Control, tmux y systemd para retomar desde el móvil
Las dos GX10 arrancan solas con Claude Code dentro, reanudando la última conversación y visibles desde claude.ai/code. Cómo se monta, y las dos puertas que pueden dejarlo esperando una tecla sin que nada parezca roto.
Un 11 de agosto una de nuestras GX10 se reinició sola en mitad de la noche. Por la mañana, la sesión de Claude Code con la que se estaba trabajando había desaparecido y no había forma de retomarla desde el móvil. Esa misma tarde quedó montado lo que cuenta esta guía:
- tras cualquier reinicio, Claude Code arranca solo dentro de una sesión
tmux; - con Remote Control activado, así que aparece en
claude.ai/codey en la app del móvil con el nombre de la máquina; - y reanudando la última conversación del usuario, no la última cosa que se ejecutó.
Hoy funciona en las dos GX10, cada una con su sesión.
Las piezas
| pieza | qué hace |
|---|---|
claude-autostart.sh |
elige la sesión a reanudar y lanza claude --remote-control <nombre> --resume <id> dentro de tmux |
claude-remote.service |
unidad de usuario de systemd que ejecuta el script al arrancar |
loginctl enable-linger |
permite que los servicios de usuario arranquen sin que nadie inicie sesión |
sesión tmux claude |
donde vive el proceso; te puedes enganchar con tmux attach -t claude |
Paso 1 · Linger: sin esto no arranca nada
Los servicios de usuario de systemd solo arrancan cuando el usuario inicia sesión. Tras un reinicio remoto, nadie inicia sesión. Linger lo cambia:
sudo loginctl enable-linger $USER
loginctl show-user $USER | grep Linger # Linger=yes
Paso 2 · La unidad
~/.config/systemd/user/claude-remote.service, en su forma mínima:
[Unit]
Description=Claude Code con Remote Control en tmux
After=network-online.target
Wants=network-online.target
[Service]
Type=forking
ExecStart=%h/ai/tools/claude-autostart/claude-autostart.sh
ExecStop=/usr/bin/tmux kill-session -t claude
Restart=on-failure
RestartSec=30
[Install]
WantedBy=default.target
systemctl --user daemon-reload
systemctl --user enable --now claude-remote.service
Paso 3 · Reanudar la conversación correcta (no --continue)
La tentación es claude --continue, que reanuda la sesión más reciente del directorio. El
problema: los trabajos en segundo plano de Claude Code se guardan en la misma carpeta que
tus conversaciones. Después de una noche de trabajo autónomo, «la más reciente» casi siempre
es un trabajo, no tu conversación.
La forma de distinguirlas: cada trabajo en segundo plano crea un directorio en
~/.claude/jobs/ con los primeros ocho caracteres de su id de sesión. El script descarta las
sesiones cuyo prefijo aparece ahí y se queda con la interactiva más reciente:
#!/usr/bin/env bash
# claude-autostart.sh (resumen)
proj="$HOME/.claude/projects/-home-$USER"
jobs="$HOME/.claude/jobs"
pick=""
for f in $(ls -t "$proj"/*.jsonl 2>/dev/null); do
id=$(basename "$f" .jsonl)
[ -d "$jobs/${id:0:8}" ] && continue # es un trabajo en segundo plano
pick="$id"; break
done
args=(--remote-control "$(hostname)")
[ -n "$pick" ] && args+=(--resume "$pick")
tmux new-session -d -s claude -c "$HOME" claude "${args[@]}"
Paso 4 · Credenciales que sobreviven sin escritorio
Para que un servicio sin sesión gráfica pueda autenticarse, las credenciales de Claude Code
tienen que estar en un fichero (~/.claude/.credentials.json, modo 600) y no en el llavero
del escritorio. Se hace una vez con el flujo oficial:
claude auth login --claudeai
claude auth status # loggedIn: true
Si un día Remote Control devuelve 403, casi siempre es esto: el token de refresco caducó. Nos pasó en las dos máquinas a la vez; la solución fue repetir el login en cada una y reiniciar solo el servicio, sin tocar nada más.
Las dos puertas que lo dejan esperando una tecla
Esto es lo que ningún tutorial cuenta. Un arranque desatendido puede quedarse parado en un
diálogo mientras todos los indicadores dicen que va bien: systemctl dice active, tmux
existe, el proceso está vivo (P-052).
- «¿Confías en esta carpeta?» La primera vez que Claude Code abre un directorio pregunta
si es de confianza. Se resuelve una vez aceptándolo para tu
$HOME. Es una decisión de seguridad consciente: estás pre-aprobando que lea, edite y ejecute ahí sin preguntar. - «Esta sesión es muy grande, ¿reanudar desde un resumen?» Aparece con sesiones de cientos de miles de tokens. No hemos encontrado un ajuste persistente para saltarla; en la práctica, tras reanudar desde el resumen la sesión nueva es pequeña y el siguiente arranque ya no pregunta.
Por eso la comprobación honesta no es systemctl status. Es mirar el panel:
tmux capture-pane -p -t claude | tail -20 # debe verse "/remote-control is active"
Otra trampa: el chequeo de red que nunca pasa
Si pones un ExecStartPre que comprueba la conexión con curl -f https://claude.ai, no
arrancará nunca: esa URL responde 403 a un curl sin navegador (P-051). Si
quieres esperar a la red, espera a network-online.target o comprueba DNS, no esa página.
En Windows: lo mismo, con el Programador de tareas
En el portátil hacemos lo equivalente con un script de PowerShell que vigila cada 30 segundos que haya un Claude Code con Remote Control por cada proyecto activo y lo relanza si falta. Una advertencia que nos costó descubrir: las tareas programadas de Windows se detienen solas al pasar a batería y siguen informando de que todo va bien (P-090). Desmarca «Iniciar la tarea solo si el equipo está conectado a la corriente alterna» y también «Detener si el equipo pasa a alimentación por batería».
Verificar sin reiniciar la máquina
systemctl --user is-enabled claude-remote # enabled
loginctl show-user $USER | grep Linger # Linger=yes
systemctl --user restart claude-remote
sleep 40 && tmux capture-pane -p -t claude | tail -20
Y desde el móvil: abre Claude, ve a Code y busca la sesión con el nombre de la máquina.
Deshacerlo
systemctl --user disable --now claude-remote
tmux kill-session -t claude
Siguiente: lo mismo con Codex en tu servidor, controlable desde la app de ChatGPT.