tawasuyu

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 1182Shell 87Rust 63Markdown 541592 Definitions

la cuenta de sergio en la caja, su jaula propia, y shuma corriendo como él

Pedido: «crea mi cuenta sergio con la clave tawasuyu, desde ahí abrir los claudes como lo estoy
haciendo acá con shuma sobre los proyectos».

  · cuenta `sergio` uid 1001 (el mismo que en gioser), home /home/sergio, clave verificada
  · su propia jaula `claude-sergio`, que concede SU home —su `.claude`: credenciales y memoria— y
    NO el de root. Con la instancia de root, sergio moría en «bwrap: Can't mkdir /root/.claude»
  · `claude` elige instancia por usuario; `PROY=/otra/ruta claude` abre el agente sobre otro proyecto
  · shuma-daemon y shuma-gateway pasan a correr como `sergio`, no como la cuenta de servicio `shuma`:
    shuma es su CONSOLA, y cada pestaña que abre tiene que ser una sesión suya — si no, `claude`
    buscaría una jaula `claude-shuma` que no existe

⚠ NO se eleva con doas/sudo: en esta caja el setuid NO TOMA («doas: Operation not permitted», con
NoNewPrivs 0 y `/` sin nosuid — queda como deuda entender por qué). No hace falta: `qorpa run`
levanta la jaula con user namespaces y anda sin privilegio, siempre que el directorio de la
instancia sea del usuario.

⚠ Y un detalle que costó una vuelta: sin `shift 2`, el HOME y el proyecto que el lanzador pasa como
posicionales se cuelan COMO ARGUMENTOS del agente — la primera sesión se abrió con el prompt
«/home/sergio», y el agente contestó, con razón, que eso es una ruta y no un comando.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

e7b77ff657c6ac09ac700c003290b47f081f1e53 · by Sergio · (1 month ago) · parent d6ba65e23 · browse the tree at this commit

Semantic delta

No definition changed: this change is text, documentation or data.

3 files · +49 −17

diff --git a/recipes/shuma-daemon.toml b/recipes/shuma-daemon.toml
index 4f0bc226..6e6d91ce 100644
--- a/recipes/shuma-daemon.toml
+++ b/recipes/shuma-daemon.toml
@@ -55,8 +55,8 @@ shell = "/bin/sh"
 label      = "shuma-daemon"
 id         = "01M2EKDA00SH0MADAEM0N7X4K2"
 exec       = "/bin/busybox"
-argv = ["sh", "-c", "/bin/grep -q '^shuma:' /etc/passwd || { echo 'shuma-daemon: no existe el usuario `shuma` en /etc/passwd — la receta lo declara con [[user]]; la imagen lo compone con `takana users`' >&2; exit 78; }; mkdir -p /run/shuma /var/lib/shuma || exit 78; chown shuma:shuma /run/shuma /var/lib/shuma || exit 78; cd /var/lib/shuma || exit 78; exec /usr/bin/setuidgid shuma /usr/bin/shuma-daemon"]
-envp       = [["PATH", "/usr/bin:/bin"], ["HOME", "/var/lib/shuma"], ["USER", "shuma"], ["XDG_RUNTIME_DIR", "/run/shuma"]]
+argv = ["sh", "-c", "/bin/grep -q '^sergio:' /etc/passwd || { echo 'shuma-daemon: no existe el usuario `sergio` en /etc/passwd — la receta lo declara con [[user]]; la imagen lo compone con `takana users`' >&2; exit 78; }; mkdir -p /run/shuma /var/lib/shuma || exit 78; chown shuma:shuma /run/shuma /var/lib/shuma || exit 78; cd /home/sergio || exit 78; exec /usr/bin/setuidgid sergio /usr/bin/shuma-daemon"]
+envp       = [["PATH", "/usr/bin:/bin"], ["HOME", "/home/sergio"], ["USER", "sergio"], ["XDG_RUNTIME_DIR", "/run/shuma"]]
 networking = "full"
 cgroup     = "arje.slice/shuma-daemon"
 restart    = { initial_ms = 1000, max_ms = 30000 }
@@ -76,3 +76,10 @@ restart    = { initial_ms = 1000, max_ms = 30000 }
 #
 # ⇒ el aviso del daemon es para el escritorio, no para el servidor. Si algún día hace falta acá,
 # primero hay que resolver el proc-macro de atspi, no reponer la receta.
+
+# ── ⚠ CORRE COMO `sergio`, NO COMO `shuma` (2026-09-17) ─────────────────────────────────────────
+# La cuenta `shuma` se creó cuando la caja no tenía usuario de la persona. Ahora sí, y shuma es su
+# CONSOLA: las pestañas que abre son sesiones suyas, y desde ahí lanza `claude`, que entra a la
+# jaula `claude-sergio` con SU memoria y SUS credenciales. Con el daemon corriendo como `shuma`,
+# cada terminal de la web habría sido de otro usuario que no es nadie — y `claude` habría buscado
+# una jaula `claude-shuma` que no existe.
diff --git a/recipes/shuma-gateway.toml b/recipes/shuma-gateway.toml
index efd2dbb8..3f2d7940 100644
--- a/recipes/shuma-gateway.toml
+++ b/recipes/shuma-gateway.toml
@@ -48,8 +48,15 @@ flags    = ["-p", "shuma-gateway", "--bin", "shuma-gateway"]
 label      = "shuma-gateway"
 id         = "01M2EKDA00SH0MAGATEWAY4K21"
 exec       = "/bin/busybox"
-argv = ["sh", "-c", "/bin/grep -q '^shuma:' /etc/passwd || { echo 'shuma-gateway: falta el usuario `shuma` — lo declara recipes/shuma-daemon.toml' >&2; exit 78; }; test -s /var/lib/shuma/.config/shuma/gateway-token || { echo 'shuma-gateway: falta /var/lib/shuma/.config/shuma/gateway-token (32 B) — viene de ~/.config/shuma/gateway-token del origen; si generás uno nuevo, los clientes emparejados dejan de entrar' >&2; exit 78; }; cd /var/lib/shuma || exit 78; exec /usr/bin/setuidgid shuma /usr/bin/shuma-gateway"]
-envp       = [["PATH", "/usr/bin:/bin"], ["HOME", "/var/lib/shuma"], ["USER", "shuma"], ["XDG_RUNTIME_DIR", "/run/shuma"]]
+argv = ["sh", "-c", "/bin/grep -q '^sergio:' /etc/passwd || { echo 'shuma-gateway: falta el usuario `sergio` — lo declara recipes/shuma-daemon.toml' >&2; exit 78; }; test -s /home/sergio/.config/shuma/gateway-token || { echo 'shuma-gateway: falta /home/sergio/.config/shuma/gateway-token (32 B) — viene de ~/.config/shuma/gateway-token del origen; si generás uno nuevo, los clientes emparejados dejan de entrar' >&2; exit 78; }; cd /home/sergio || exit 78; exec /usr/bin/setuidgid sergio /usr/bin/shuma-gateway"]
+envp       = [["PATH", "/usr/bin:/bin"], ["HOME", "/home/sergio"], ["USER", "sergio"], ["XDG_RUNTIME_DIR", "/run/shuma"]]
 networking = "full"
 cgroup     = "arje.slice/shuma-gateway"
 restart    = { initial_ms = 1000, max_ms = 30000 }
+
+# ── ⚠ CORRE COMO `sergio`, NO COMO `shuma` (2026-09-17) ─────────────────────────────────────────
+# La cuenta `shuma` se creó cuando la caja no tenía usuario de la persona. Ahora sí, y shuma es su
+# CONSOLA: las pestañas que abre son sesiones suyas, y desde ahí lanza `claude`, que entra a la
+# jaula `claude-sergio` con SU memoria y SUS credenciales. Con el daemon corriendo como `shuma`,
+# cada terminal de la web habría sido de otro usuario que no es nadie — y `claude` habría buscado
+# una jaula `claude-shuma` que no existe.
diff --git a/scripts/servidor/claude-caja.sh b/scripts/servidor/claude-caja.sh
index 0a943b2f..c8a860af 100755
--- a/scripts/servidor/claude-caja.sh
+++ b/scripts/servidor/claude-caja.sh
@@ -2,19 +2,37 @@
 # claude — entrar al agente en esta caja. El CLI es glibc y la caja es musl: corre enjaulado
 # (ADR 0015), con el repo, el store, el lab, la memoria y las llaves concedidos y nada más.
 #
+# ── UNA JAULA POR PERSONA, Y SIN PRIVILEGIO ─────────────────────────────────────────────────────
+# `root` usa la instancia `claude`; cada usuario usa `claude-<usuario>`. No es purismo: la instancia
+# concede el HOME de quien entra —su `.claude`, o sea sus credenciales y su memoria— y una sola
+# instancia obligaría a compartirlo. Medido: con la instancia de root, `sergio` muere en
+# `bwrap: Can't mkdir /root/.claude: Permission denied`.
+#
+# ⚠ Y NO se eleva con `doas`/`sudo`: en esta caja **el setuid no toma** («doas: Operation not
+# permitted», con `NoNewPrivs: 0` y `/` sin `nosuid` — queda como deuda entender por qué). No hace
+# falta: `qorpa run` levanta la jaula con user namespaces y anda **sin privilegio**, siempre que el
+# directorio de la instancia sea del usuario.
+#
 # ⚠ LOS BUILDS NO CORREN DENTRO DE LA JAULA. `takana build` levanta su propio bwrap y ahí falla con
-# «Can't mount proc on /proc» aunque la instancia declare `nesting = true` (un `bwrap --proc /proc`
-# a mano SÍ funciona adentro: lo que falla es el userns anidado que arma el sandbox del build).
-# El camino que sí anda —y el que el agente debe usar— es pedírselo al ANFITRIÓN por ssh:
+# «Can't mount proc on /proc» aunque la instancia declare `nesting = true`. El camino que sí anda es
+# pedírselo al ANFITRIÓN por ssh:
 #
-#   ssh -p 22022 -i /root/.ssh/github5 root@127.0.0.1 \
-#     'cd /opt/takana && flock -o work/.farm-build.lock takana --store /store build <receta>'
+#   ssh -p 22022 root@127.0.0.1 'cd /opt/takana && flock -o work/.farm-build.lock takana build <r>'
+set -eu
+
+_yo="$(id -un)"
+_hogar="${HOME:-/root}"
+_inst="claude"
+[ "$_yo" != "root" ] && _inst="claude-$_yo"
+
+# El `cd` no es comodidad: la memoria del agente se indexa POR RUTA DE TRABAJO. Desde `/` —que es
+# donde `qorpa run` deja el shell— la sesión usa el proyecto `-` y el agente empieza sin saber nada
+# aunque su memoria esté en disco. `PROY` permite abrir el agente sobre OTRO proyecto:
 #
-# Comprobado el 2026-09-17: así se selló `sof-firmware` desde dentro de la jaula.
-# ⚠ EL `cd` NO ES COMODIDAD: la memoria del agente se indexa POR RUTA DE TRABAJO. Arrancando desde
-# `/` —que es donde `qorpa run` deja el shell— la sesión usa el proyecto `-` y el agente **empieza
-# sin saber nada**, aunque sus 163 ficheros de memoria estén en disco. Desde `/opt/takana` usa
-# `-opt-takana`, que es donde se renombró la memoria que vino de gioser (allá el repo era
-# `/mnt/vvv/takana`). Comprobado: preguntado por el logo, contesta «martillo 7×7, cuatro colores
-# exactos», que es exactamente lo que dice su memoria.
-exec takana qorpa run claude -- sh -c '''cd /opt/takana && exec env HOME=/root TERM="${TERM:-xterm-256color}" /work/claude-cli/2.1.240 "$@"''' -- "$@"
+#   PROY=/opt/tawasuyu claude
+# ⚠ El `shift 2` no es adorno: sin él, el HOME y el proyecto que se pasan como posicionales se
+# cuelan COMO ARGUMENTOS del agente. Medido: la primera versión abrió la sesión con el prompt
+# «/home/sergio», y el agente contestó —con razón— que eso es una ruta, no un comando.
+exec takana qorpa run "$_inst" -- sh -c \
+  'hogar="$1"; proy="$2"; shift 2; cd "$proy" && exec env HOME="$hogar" TERM="${TERM:-xterm-256color}" /work/claude-cli/2.1.240 "$@"' \
+  _ "$_hogar" "${PROY:-/opt/takana}" "$@"