diff --git a/workloads/docs-portal/docs/arquitectura/sesion-tmux-persistente.md b/workloads/docs-portal/docs/arquitectura/sesion-tmux-persistente.md index fd83cf8..611b73c 100644 --- a/workloads/docs-portal/docs/arquitectura/sesion-tmux-persistente.md +++ b/workloads/docs-portal/docs/arquitectura/sesion-tmux-persistente.md @@ -230,11 +230,13 @@ falla: contenedor. - **Existencia de la sesión tmux `lab`** (`tmux has-session`): si no existe, **sí se recrea automáticamente** (`tmux new-session -d -s lab - -c `, seguido de `tmux send-keys -t lab claude Enter` — ver - gotcha "sesión recreada pero sin Claude Code adentro" más abajo) — es - solo recuperar el propio entorno de trabajo del contenedor, no tocar - infraestructura externa, así que es seguro hacerlo sin intervención - humana. Si `WORKDIR` todavía no está montado (ver gotcha siguiente), + -c `, seguido de `tmux send-keys -t lab claude --remote-control + --continue Enter` — ver gotcha "sesión recreada pero sin Claude Code + adentro" más abajo, y los gotchas de Remote Control y `--continue` + agregados el 2026-09-20) — es solo recuperar el propio entorno de + trabajo del contenedor, no tocar infraestructura externa, así que es + seguro hacerlo sin intervención humana. Si `WORKDIR` todavía no está + montado (ver gotcha siguiente), no se crea la sesión esa vuelta — se reintenta en el próximo ciclo en vez de crearla mal posicionada. @@ -301,14 +303,111 @@ en un contenedor descartable aparte (mismos mounts de `/DATA` y `docker start` (arranque desde cero, no `restart`) recreó la sesión `lab` con `claude` corriendo adentro sin intervención manual, en ~1 segundo. +## Gotcha: Remote Control nunca se activaba solo (2026-09-20) + +Con la sesión `lab` recreándose sola y `claude` corriendo adentro (gotcha +anterior), quedaba un problema distinto y más sutil: la sesión servía +perfecto para trabajar vía `docker exec`/`lab-session.sh`, pero nunca +aparecía como controlable remotamente en claude.ai — como si Remote +Control jamás se hubiera activado. + +**Causa raíz (confirmado en vivo 2026-09-20):** Remote Control es +opt-in por lanzamiento, vía el flag `claude --remote-control [nombre]` +de la CLI. Nada en `launch_claude_in_session()` lo pasaba nunca, así +que `remoteEnabled` en `~/.claude.json` quedaba en `false` para siempre +porque nadie lo pedía. No existe un paso separado de confirmación +"¿Activar Remote Control? y/n" más allá del diálogo normal de +confianza del folder (una hipótesis inicial de que sí existía tal paso, +y de que había una clave `remoteControlAtStartup` en `settings.json`, +resultó falsa al revisar directamente los archivos de configuración +reales). + +**Cómo se detectó:** lanzar `claude --remote-control` a mano (en una +ventana de tmux en foreground, no vía un `!` de un solo uso que se +mata al terminar) sí registró la sesión y apareció en la lista de +sesiones activas de claude.ai como `zimaos-quizzical` — el hostname del +contenedor (`ZimaOS`) se usa como prefijo por defecto del nombre de +sesión remota. + +**Fix:** cambiar la línea `tmux send-keys` en +`launch_claude_in_session()` para lanzar `claude --remote-control` en +vez de `claude` a secas. + +**Validado en vivo:** tras reconstruir la imagen y swapear el +contenedor real (ver el gotcha del swap más abajo), `health.log` +registró `'claude --remote-control' lanzado...` al recrear la sesión, y +el pane de tmux mostró `/remote-control is active` con un link de +sesión válido — sin que nadie lo activara a mano. + +## Gotcha: cada recreación de la sesión empezaba una conversación en blanco (2026-09-20) + +Con Remote Control ya activándose solo, quedaba una fricción menor pero +molesta: cada vez que la sesión `lab` se recreaba (reinicio del NAS, +`docker rm` + recrear, o el propio healthcheck reaccionando a un +crash), `launch_claude_in_session()` arrancaba una conversación +completamente nueva. El contexto de trabajo en curso —no las +credenciales ni la confianza del folder, que sí persisten vía volumen— +se perdía cada vez, sin relación con los límites de cuota (ver la nota +al principio de este doc). + +**Fix:** agregar `-c`/`--continue` (retoma la conversación más reciente +en el directorio de trabajo actual) al comando de lanzamiento: +`claude --remote-control --continue`. Si no hay ninguna conversación +previa en `WORKDIR`, el propio CLI arranca una nueva sin error — no +hace falta lógica condicional en el script. + +**Validado en vivo — la prueba más fuerte posible:** el swap que +desplegó este mismo cambio (ver gotcha siguiente) mató la sesión de +Claude Code que lo estaba ejecutando. Del otro lado, la *misma +conversación* siguió sin cortarse, con el mismo ID de sesión, sin +ninguna intervención manual — evidencia directa de que `--continue` +efectivamente retoma la conversación y no solo que el contenedor volvió +a levantar. + +## Gotcha: actualizar la imagen de `tmux-host` en caliente mata al propio proceso que hace el swap (2026-09-20) + +Este contenedor tiene un problema estructural para actualizarse a sí +mismo: el proceso de Claude Code que ejecutaría `docker stop tmux-host +&& docker rm tmux-host && docker run ... tmux-host:nueva-imagen` corre +*dentro* del propio contenedor `tmux-host` — el primer `docker stop` +mata su propia shell a mitad de la secuencia, dejando el swap a medio +terminar (visto en vivo: un primer intento así falló en silencio). + +**Fix:** correr la secuencia de swap desde un contenedor *sibling* +efímero, no desde dentro de `tmux-host`: + +```bash +docker run --rm \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v /DATA/AppData/k3d-lab-v3/tmux-host:/tmux-host-cfg \ + docker:cli sh /tmux-host-cfg/swap-retry.sh +``` + +Como este helper solo comparte el socket de Docker (no vive *dentro* +del contenedor `tmux-host`), detener y recrear `tmux-host` no lo afecta +a él ni al proceso que lo lanzó desde el host. El script +(`swap-retry.sh`, junto a sus logs, vive en +`/DATA/AppData/k3d-lab-v3/tmux-host/` — mismo path físico que +`/media/HDD-Storage/AppData/k3d-lab-v3/tmux-host/`, ver el gotcha del +symlink más arriba) deja un log fechado por corrida en `logs/` con el +`docker ps` y un `grep` sobre `healthcheck.sh` dentro de la imagen +nueva, para verificar sin tener que adivinar si el fix realmente quedó +adentro. + +**Validado en vivo dos veces (2026-09-20):** el fix de Remote Control y +el de `--continue` se desplegaron cada uno con este mismo mecanismo, +ambos confirmados por `docker ps` (imagen e `CreatedAt` nuevos) y por +`health.log` mostrando la línea de lanzamiento esperada inmediatamente +después del swap. + ## Qué sobrevive a qué -| Evento | ¿Sobrevive la sesión tmux (`lab`)? | ¿Sobrevive el login de Claude Code? | -|---|---|---| -| Corte de SSH / cerrar la terminal / cambiar de dispositivo | Sí — es exactamente el caso que este setup resuelve | Sí | -| `docker restart tmux-host` (reinicio del NAS) | **No al toque, pero se auto-recupera solo** — el proceso `tmux server` muere con el contenedor; `healthcheck.sh` la recrea en el próximo ciclo (máx. 30 min) sin intervención, o `lab-session.sh` la crea al instante si alguien se reconecta antes | Sí, vía el volumen montado en `/root/.claude` | -| `docker rm` + recrear el contenedor desde cero | No, pero igual se auto-recupera sola (mismo mecanismo de arriba) | Sí, vía el mismo volumen — no hace falta volver a autenticar ni reconfirmar el diálogo de confianza del folder (ver el mount de `claude-code-home.json`) | -| Falla de red real del host/NAS | N/A | N/A — `healthcheck.sh` la detecta y notifica, pero no la corrige (fuera de su alcance) | +| Evento | ¿Sobrevive la sesión tmux (`lab`)? | ¿Sobrevive el login de Claude Code? | ¿Retoma la misma conversación? | +|---|---|---|---| +| Corte de SSH / cerrar la terminal / cambiar de dispositivo | Sí — es exactamente el caso que este setup resuelve | Sí | Sí — el proceso `claude` ni se entera | +| `docker restart tmux-host` (reinicio del NAS) | **No al toque, pero se auto-recupera solo** — el proceso `tmux server` muere con el contenedor; `healthcheck.sh` la recrea en el próximo ciclo (máx. 30 min) sin intervención, o `lab-session.sh` la crea al instante si alguien se reconecta antes | Sí, vía el volumen montado en `/root/.claude` | Sí, desde el 2026-09-20 — `--continue` retoma la conversación más reciente en `WORKDIR` (ver gotcha arriba) | +| `docker rm` + recrear el contenedor desde cero | No, pero igual se auto-recupera sola (mismo mecanismo de arriba) | Sí, vía el mismo volumen — no hace falta volver a autenticar ni reconfirmar el diálogo de confianza del folder (ver el mount de `claude-code-home.json`) | Sí, mismo mecanismo — validado en vivo durante el swap de imagen del 2026-09-20 | +| Falla de red real del host/NAS | N/A | N/A — `healthcheck.sh` la detecta y notifica, pero no la corrige (fuera de su alcance) | N/A | ## Validación en vivo