gioser

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 815Rust 56Shell 37Markdown 291229 Definiciones

feat(qorpa): concesion host_pids — sin ella el «restaurar» de shuma devolvia un shell mudo

Pedido del operador: "por que aca reinicio y abren los tabs pero sin claude,
mientras que en mi laptop reinicio y tengo el restaurar".

La maquinaria de restaurar YA EXISTE y no habia que disenar nada: es AE1 de
COLA-SHUMA.md, y shuma-daemon/src/claude_sesion.rs, dado el pid del proceso de un
panel, encuentra el claude que corre debajo y devuelve la linea para reabrirlo EN
LA MISMA CHARLA (claude --resume <uuid>). El dato sale del registro vivo que deja
Claude Code en ~/.claude/sessions/<pid>.json.

Lo que fallaba era la jaula, por dos razones y la segunda es peor:

1. El pid es de otro namespace. Con --unshare-pid, adentro el claude es el pid 2,
   y el archivo se llama 2.json con "pid":2. El daemon vive en el anfitrion,
   donde el pid 2 es kthreadd, y claude_sesion.rs exige que el pid sea
   descendiente del panel: no casa nunca. El propio modulo dice que en ese caso
   "el puesto se guarda como el shell que es", que es exactamente el sintoma.

2. Y las jaulas SE PISAN el registro. El $HOME va bind-mounteado compartido y
   TODAS ven su claude como pid 2, asi que todas escriben el MISMO 2.json.
   Medido: los tres registros que habia eran de una sola jaula y ninguno de la
   sesion viva (procStart 72597 contra 988468 del archivo).

Por eso no alcanzaba con tocar shuma: con los registros pisandose no hay nada que
cruzar, y cualquier arreglo del lado del daemon habria sido imposible de
certificar. La concesion es la pieza que lo desbloquea, y con ella el pid que el
registro guarda ya es el del anfitrion, asi que claude_sesion.rs funciona SIN
cambios.

`host_pids` arranca cerrada como todas las demas y se enciende por instancia. En
la del agente va encendida, con el porque escrito al lado. Es una concesion real
y esta dicho en su doc: un `ps` de adentro ve los procesos del host. No abre nada
mas -- fs, red y capacidades siguen igual.

Certificado en metal con su brazo de control: una jaula de la instancia del
agente reporta `pid-adentro=32721` (antes 2) y su `ps` ve shuma-daemon y
sshd-session; una instancia sin la concesion sigue con su arbol propio.

f48a7e8aa03a2a6eacdff402e8abd32d61e25cd9 · por Sergio · (hace 26 d) · padre 2a0175eb3 · ver el árbol en este commit

Delta semántico · 3

crates/takana-cli/src/qorpa.rs

2 archivos · +35 −1

diff --git a/crates/takana-cli/src/qorpa.rs b/crates/takana-cli/src/qorpa.rs
index 65230406..0ae14708 100644
--- a/crates/takana-cli/src/qorpa.rs
+++ b/crates/takana-cli/src/qorpa.rs
@@ -816,6 +816,23 @@ struct Grants {
     /// instancia recupera la familia `mount`/`setns` que la jaula deniega por defecto.
     #[serde(default)]
     nesting: bool,
+    /// Compartir el **árbol de procesos del host** en vez de armar uno propio (`--unshare-pid`).
+    ///
+    /// Apagado por defecto: un `ps` de adentro no tiene por qué ver la máquina entera. Se
+    /// enciende cuando algo de ADENTRO tiene que ser identificable desde AFUERA por su pid.
+    ///
+    /// El caso que lo trajo (2026-09-25): Claude Code deja un registro vivo en
+    /// `~/.claude/sessions/<pid>.json` para poder reanudar una conversación, y shuma lo usa para
+    /// que restaurar una pestaña devuelva **la charla** y no un shell pelado. Con el namespace
+    /// propio ese pid es el de adentro —**2**, en todas las jaulas a la vez— así que (a) el
+    /// daemon, que vive afuera, no puede cruzarlo contra `/proc`, y (b) como el `$HOME` está
+    /// compartido, **todas las jaulas escriben el mismo `2.json` y se pisan**. Medido: los tres
+    /// registros que había eran de la misma jaula y ninguno de la sesión viva.
+    ///
+    /// ⚠ Es una concesión real: con esto la instancia ve y puede señalizar los procesos del host
+    /// que su uid alcance. No abre nada más (fs, red y capacidades siguen igual).
+    #[serde(default)]
+    host_pids: bool,
     /// Mapear tu uid a **root adentro**. Encendido por defecto: es lo que quieren `dnf`/`pacman`.
     ///
     /// ⚠ MEDIDO 2026-09-03, y es un conflicto real con `nesting`: con `--uid 0`, un userns anidado
@@ -954,6 +971,7 @@ impl Default for Grants {
         Grants {
             sockets: Vec::new(), devices: Vec::new(), dirs: Vec::new(),
             network: false, nesting: false, root: true, seal_image: false,
+            host_pids: false,
             wayland_raw: false, wayland_globals: Vec::new(),
         }
     }
@@ -1590,11 +1608,16 @@ fn run_instance(
     }
 
     let mut args: Vec<String> = vec![
-        "--unshare-pid", "--unshare-ipc", "--unshare-uts", "--unshare-cgroup-try",
+        "--unshare-ipc", "--unshare-uts", "--unshare-cgroup-try",
         "--hostname", "qorpa",
         "--clearenv",
         "--die-with-parent",
     ].into_iter().map(String::from).collect();
+    // El árbol de procesos propio se arma salvo que la instancia pida compartir el del host
+    // (`host_pids`). Va al FRENTE para no cambiar el orden que tenían las banderas.
+    if !inst.grants.host_pids {
+        args.insert(0, "--unshare-pid".into());
+    }
     if mapeado.is_none() {
         // bwrap crea el suyo, con un solo id.
         args.insert(0, "--unshare-user".into());
diff --git a/scripts/servidor/qorpa-claude.instance.toml b/scripts/servidor/qorpa-claude.instance.toml
index afb8af96..41b016fb 100644
--- a/scripts/servidor/qorpa-claude.instance.toml
+++ b/scripts/servidor/qorpa-claude.instance.toml
@@ -25,6 +25,17 @@ network = true
 # `nesting`: `takana build` levanta su sandbox con bwrap ADENTRO. Sin esto, la jaula puede leer las
 # recetas y no puede construir ninguna, que es justo la mitad del pedido.
 nesting = true
+# `host_pids`: comparte el árbol de procesos del host en vez de armar uno propio.
+#
+# Hace falta para que «el restaurar» de shuma devuelva la CONVERSACIÓN y no un shell pelado.
+# Claude Code deja un registro vivo en `~/.claude/sessions/<pid>.json` y shuma lo cruza contra
+# /proc para reabrir la charla con `--resume <uuid>`. Con namespace propio ese pid es el de
+# adentro —**2**, en todas las jaulas a la vez— así que el daemon no puede cruzarlo, y como el
+# $HOME está compartido todas las jaulas escriben el MISMO `2.json` y se pisan (medido el
+# 2026-09-25: los tres registros eran de una sola jaula, ninguno de la sesión viva).
+#
+# ⚠ Es una concesión real: un `ps` de adentro ve los procesos del host. No abre nada más.
+host_pids = true
 root = true
 wayland_raw = false
 seal_image = false