Saltar a contenido

Incidente: Remote Control caído tras el reinicio de tmux-host (2026-10-23)

Síntoma Ninguna sesión de Claude (lab, cloud-practice, scm-portal) aparecía en claude.ai/code después del reinicio de tmux-host (12:07 UTC)
Servicio afectado Remote Control de las 3 sesiones de Sesión tmux persistente
Causas (1) La pregunta "Resume / Start a new conversation" de --continue frenaba 2 sesiones. (2) Todas arrancaron con el login de Claude vencido, y en 2.1.302 Remote Control solo se activa al lanzar
Estado Resuelto y verificado. Autosanación en healthcheck.sh (imagen tmux-host:2026-10-23-rc-autosana)

Diagnóstico

  1. El estado de cada sesión es legible. Cada proceso claude escribe /root/.claude/sessions/<pid>.json. Con Remote Control conectado tiene "bridgeSessionId":"session_…"; sin conexión, no tiene esa clave.
  2. Dos sesiones estaban frenadas en una pregunta. En los panes de lab y scm-portal:

    This conversation has been inactive for 8h 29m and is 821.7k tokens long.
    Resuming it will use about 15% of your 5-hour usage limit.
    ❯ 1. Resume
      2. Start a new conversation
    

    Claude Code 2.1.x muestra esa pregunta con --continue cuando la conversación es larga o estuvo inactiva. Nadie la respondía, así que la sesión nunca arrancaba. 3. /remote-control no existe en 2.1.302 ("Unknown command"). Remote Control solo se activa con claude --remote-control. Las sesiones que arrancaron con el login vencido seguían sin Remote Control después del /login: hubo que reiniciarlas (/exit + claude --remote-control --continue). 4. La misma conversación abierta 4 veces. Para recuperar el acceso se habían abierto 3 consolas de Portainer con claude --continue en la misma carpeta, además del pane de tmux. Se cerraron las copias sobrantes y se dejó solo el pane de tmux.

Recuperación manual (antes del fix)

  1. /login en cualquier sesión. Las credenciales son compartidas, así que una vez alcanza.
  2. En cada pane: si muestra la pregunta, Enter ("1. Resume"). Si arrancó con el login vencido: /exit y claude --remote-control --continue.
  3. Verificar el bridgeSessionId en /root/.claude/sessions/<pid>.json.

Fix: autosanación en healthcheck.sh

Commits 96691c4 y 7d64e9f en scripts. Imagen tmux-host:2026-10-23-rc-autosana.

Qué hace Cuándo
A Si el pane muestra 1. Resume, manda Enter (y espera 15 s a que la pantalla se redibuje) Al lanzar claude (espera hasta 90 s) y en cada ciclo
B Lee bridgeSessionId. Si falta: con el login vencido avisa por Telegram (máx. 1 cada 6 h) y no reinicia; con el login válido y la sesión no busy, reinicia claude al 2.º ciclo seguido Cada ciclo (30 min)

El login se consulta con claude auth status (JSON con "loggedIn"), que no expone el token. El reinicio usa --continue, así que retoma la misma conversación.

Verificación (2026-10-23 20:48–20:51 UTC, swap a la imagen nueva)

CLAUDE: 'lab' Remote Control ok (session_018r19…)
CLAUDE: 'cloud-practice' Remote Control ok (session_01Cdx7…)
CLAUDE: 'scm-portal' estaba frenada en la pregunta 'Resume / Start a new conversation' -- respondido 'Resume'

Las 3 sesiones quedaron con bridgeSessionId, con los mismos links de siempre. La mejora A actuó sola en el primer arranque.

Antes del swap también se probaron en seco (con reinicio y Telegram simulados) los caminos "sin Remote Control → reinicio al 2.º ciclo" y "login vencido → aviso una sola vez".

Probado y descartado: token de 1 año

claude setup-token genera un token OAuth de larga duración (sk-ant-oat01-…). Con CLAUDE_CODE_OAUTH_TOKEN, Claude Code autentica (/status → Auth token: CLAUDE_CODE_OAUTH_TOKEN), pero Remote Control no se conecta: no hubo bridgeSessionId en más de un minuto. Conclusión: Remote Control necesita el login completo de claude.ai. El token de prueba se borró del NAS y conviene revocarlo en claude.ai.

Error de uso visto en la prueba

En el primer intento se guardó el código de autorización que muestra el navegador, en vez del token, y Claude lo rechazó con 401. El token es lo que imprime claude setup-token después de pegarle ese código, y empieza con sk-ant-oat01-.

Login desde Telegram (bot claude-login-bot)

El login no se puede automatizar, porque se autoriza con la cuenta en el navegador, pero se puede hacer desde el celular sin entrar al NAS. Desde la imagen tmux-host:2026-10-23-rc-bot, entrypoint.sh supervisa claude-login-bot.mjs (Node, sin dependencias), que usa el mismo bot y chat de lab-agent.env:

Mensaje al bot Qué hace
/estado Login de Claude y Remote Control de cada sesión
/login Si hace falta, abre claude auth login en la ventana tmux claude-login y responde con el link de autorización
(el código) Lo pega en esa ventana, borra el mensaje del chat, verifica claude auth status y reinicia las sesiones sin Remote Control

Flujo cuando vence el login:

  1. El healthcheck avisa por Telegram: "login vencido… respondé /login".
  2. Mandás /login y abrís el link que te responde.
  3. Autorizás y le mandás al bot el código que muestra la página. Tenés 10 minutos.
  4. El bot confirma "✅ Login renovado", reinicia las sesiones y te manda el /estado final.

Seguridad:

  • Solo atiende mensajes del TELEGRAM_CHAT_ID configurado.
  • El código es de un solo uso y de corta vida. Nunca se escribe en el log (logs/telegram-login-bot.log) y su mensaje se borra del chat.
  • Sin PIN por ahora, por decisión del usuario el 2026-10-23.

Verificado el 2026-10-23: /estado y /login con el login vigente (responde que no hace falta). Dentro de tmux, claude auth login muestra el link y espera "Paste code here if prompted >", sin necesitar navegador local. El flujo completo con código real queda para el próximo vencimiento.

Un solo lector de mensajes

Telegram entrega los mensajes a un solo proceso que los lea (getUpdates). lab-agent solo envía (sendMessage), así que no compite. Si en el futuro otro componente necesita leer mensajes del mismo bot, hay que unificarlo con este.

Lecciones

  1. "No aparecen las sesiones" se diagnostica en los panes, no en el contenedor. Igual que el 2026-09-25: primero mirar qué muestra cada pane.
  2. Las actualizaciones de Claude Code cambian el flujo interactivo: una pregunta nueva bloqueó un arranque que antes era automático, y un comando (/remote-control) dejó de existir. Por eso la versión está fijada en la imagen (ver el incidente del 2026-10-17).
  3. Una conversación, un proceso. Abrir --continue en varias consolas duplica la conversación.