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 177Rust 55Shell 28Markdown 271211 Definiciones

el agente corre en la caja y puede construir — la condición que el usuario puso para borrar gioser

  $ claude -p "Decí exactamente: CLAUDE CORRIENDO EN LA CAJA"
  CLAUDE CORRIENDO EN LA CAJA

Turno real —API, credenciales, respuesta— desde 2.29.29.217. El CLI es un ELF glibc de 360 M y la
caja es musl, así que va enjaulado (ADR 0015, el caso de sergioh-api). La instancia declara red,
nesting y SEIS directorios: /opt/takana, /work/dev-fs, /store, /root/.claude, /root/.ssh (ro) y el
CLI (ro). Es ANCHA y está dicho: un agente que construye, commitea y empuja necesita lo mismo que un
humano; lo que la jaula compra es que el alcance esté escrito y acotado.

⚠ El `takana` que construye NO se instala adentro: sale del store, que ya está concedido — es
estático musl y corre igual dentro de una imagen glibc.

LA CAJA CONSTRUYE: sellados hoy `intel-ucode` (156 signatures) y `sof-firmware` (2 firmware + 8
topologías). Faltaba una pieza que el lab no traía: `.dev-fs/tools` (zig 0.13/0.16 y go, 1 G) — la
imagen del lab empaqueta `alpine/` y nada más, y el primer intento murió con «zig no encontrado».

🧱 Y lo que NO anda, con su rodeo: `takana build` dentro de la jaula muere con «bwrap: Can't mount
proc on /proc» aunque `nesting = true`. No es el anidamiento —un `bwrap --proc /proc` a mano SÍ
funciona adentro— sino el userns anidado del sandbox del build; probado también con `root = false`,
que es la sospecha que el propio código documenta, y falla igual. El rodeo que sí anda, escrito en el
lanzador: pedirle el build al ANFITRIÓN por ssh a 127.0.0.1:22022. Así se selló sof-firmware desde
dentro de la jaula.

Manifiesto y lanzador versionados en scripts/servidor/: una instancia que sólo existe en la caja se
pierde con la caja.

⚠ Pendiente menor: la memoria del agente está en `-mnt-vvv-takana` y allá el repo vive en
/opt/takana ⇒ el índice POR RUTA no coincide y arranca sin memoria del proyecto aunque los 733
ficheros estén en disco.

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

eb96c9219e07051d088884e038f86b63921e72c0 · por Sergio · (hace 1 mes) · padre b3f098767 · ver el árbol en este commit

Delta semántico

Ninguna definición cambió: el cambio es de texto, documentación o datos.

3 archivos · +157 −0

diff --git a/docs/28-servidor-de-produccion.md b/docs/28-servidor-de-produccion.md
index c5acb772..16355a8e 100644
--- a/docs/28-servidor-de-produccion.md
+++ b/docs/28-servidor-de-produccion.md
@@ -2842,6 +2842,76 @@ faltan en el destino**.
 `api/main.py` se publica es del dueño del repo, no de la mudanza. El `LEEME.txt` del paquete lleva el
 comando exacto para reapuntarlo.
 
+### 6.50 🤖 El agente corre en la caja — y puede construir *(2026-09-17)*
+
+Pedido del usuario, y es la condición que él mismo puso para borrar gioser: *«no borramos gioser
+hasta tenerte corriendo de aquel lado, con capacidad de compilar tawasuyu y las recetas de takana»*.
+
+```
+  $ claude -p "Decí exactamente: CLAUDE CORRIENDO EN LA CAJA"
+  CLAUDE CORRIENDO EN LA CAJA
+```
+
+Eso es un turno REAL —API, credenciales, respuesta— desde `2.29.29.217`.
+
+#### Por qué va enjaulado, y qué se le concedió
+
+El CLI es un **ELF glibc de 360 M** (`interpreter /lib64/ld-linux-x86-64.so.2`, `NEEDED libc.so.6`)
+y la caja es musl: no hay camino nativo. Es el caso del ADR 0015, el mismo de `sergioh-api`. La
+instancia `claude` declara, y **conviene decir que es ANCHA en vez de disimularlo**: red, `nesting`,
+y seis directorios —`/opt/takana` (el trabajo), `/work/dev-fs` (lab + zig/go), `/store`,
+`/root/.claude` (memoria y credenciales), `/root/.ssh` (ro) y el CLI (ro)—. Un agente que construye,
+commitea y empuja necesita lo mismo que un humano haciendo ese trabajo; lo que la jaula compra es
+que ese alcance esté **escrito y acotado**, no que sea pequeño.
+
+⚠ El `takana` que construye **no se instala adentro**: sale del store, que ya está concedido. Es
+estático musl y corre igual dentro de una imagen glibc — comprobado (`takana 0.0.1`).
+
+#### La caja construye: dos recetas selladas hoy
+
+Antes faltaba una pieza que el lab no traía: **`.dev-fs/tools`** (zig 0.13/0.16 y go, 1 G). El
+primer intento murió con `zig no encontrado en .dev-fs/tools/zig/zig` — la imagen del lab empaqueta
+`alpine/` y **nada más**. Copiado eso:
+
+```
+  intel-ucode   → sellado: 156 signatures + GenuineIntel.bin (17 MB)
+  sof-firmware  → sellado: 2 firmware + 8 topologías (IPC3 v2.2, TigerLake)
+```
+
+#### 🧱 Lo que NO funciona, y su rodeo
+
+**`takana build` NO corre DENTRO de la jaula**, aunque la instancia declare `nesting = true`:
+
+```
+  bwrap: Can't mount proc on /proc: Operation not permitted
+```
+
+Y no es que el anidamiento esté roto: **un `bwrap --dev-bind / / --proc /proc` a mano SÍ funciona
+adentro**, con y sin `--unshare-pid`. Lo que falla es el userns anidado que arma el sandbox del
+build. Probado también con `root = false` —la sospecha que el propio código documenta (§`grants.root`
+⚠ del 2026-09-03)— y falla igual: no es el remapeo a root.
+
+El rodeo que sí anda, y quedó escrito en el lanzador para que el agente lo use:
+
+```sh
+  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>'
+```
+
+Con eso, **desde dentro de la jaula se selló `sof-firmware`**. El agente vive enjaulado y le pide
+los builds al anfitrión, que es donde el sandbox del build tiene los permisos que necesita.
+
+#### Cómo se entra
+
+`claude` en el PATH de la caja (`/usr/bin/claude`), que envuelve
+`takana qorpa run claude -- env HOME=/root …`. El manifiesto y el lanzador están versionados en
+`scripts/servidor/`, porque una instancia que sólo existe en la caja se pierde con la caja.
+
+⚠ Pendiente menor: la memoria del agente está en `/root/.claude/projects/-mnt-vvv-takana/`, y allá el
+repo vive en `/opt/takana` ⇒ **el índice por ruta no coincide**. Se resuelve renombrando el
+directorio a `-opt-takana` o dándole al repo la misma ruta; hasta entonces el agente arranca sin su
+memoria del proyecto aunque los 733 ficheros estén en disco.
+
 ## 7. Reusar los scripts que ya existen, y no escribir de nuevo
 
 Pedido explícito del usuario. El inventario de lo que ya hace el trabajo:
diff --git a/scripts/servidor/claude-caja.sh b/scripts/servidor/claude-caja.sh
new file mode 100755
index 00000000..3f9c848d
--- /dev/null
+++ b/scripts/servidor/claude-caja.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+# 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.
+#
+# ⚠ 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:
+#
+#   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>'
+#
+# Comprobado el 2026-09-17: así se selló `sof-firmware` desde dentro de la jaula.
+exec takana qorpa run claude -- env HOME=/root TERM="${TERM:-xterm-256color}" \
+  /work/claude-cli/2.1.240 "$@"
diff --git a/scripts/servidor/qorpa-claude.instance.toml b/scripts/servidor/qorpa-claude.instance.toml
new file mode 100644
index 00000000..afb8af96
--- /dev/null
+++ b/scripts/servidor/qorpa-claude.instance.toml
@@ -0,0 +1,72 @@
+# Manifiesto de la instancia — ESTO es la verdad, `upper/` es caché descartable (ADR 0015 D3).
+#
+# ── POR QUÉ EXISTE ESTA JAULA (2026-09-17) ──────────────────────────────────────────────────────
+# Pedido del usuario: «no borramos gioser hasta tenerte corriendo de aquel lado, con capacidad de
+# compilar tawasuyu y las recetas de takana». El CLI de Claude Code es un **ELF glibc de 360 M**
+# (`interpreter /lib64/ld-linux-x86-64.so.2`, NEEDED libc.so.6) y esta caja es musl: no hay camino
+# nativo. Es el caso del ADR 0015, igual que `sergioh-api`.
+base = "sha256:895661bdf6c64e91b7725874165fd05dd30c438d3ffec661671ab5cfb261ca58"
+distro = "arch"
+
+# Lo que hace falta ADENTRO para trabajar el repo: git para commitear y empujar, openssh para
+# llegar al gitea y al worker, y las CA para TLS. El CLI trae su propio node y su propio ripgrep.
+# `bubblewrap`: `takana build` levanta SU PROPIO sandbox adentro. Sin esto la jaula lee recetas y no
+# construye ninguna, que es la mitad del pedido. El `takana` que las construye NO se instala acá:
+# sale del STORE, que ya está concedido — es estático musl y corre igual dentro de una imagen
+# glibc (comprobado: `takana 0.0.1` desde /store dentro de la jaula).
+packages = ["git", "openssh", "ca-certificates", "bubblewrap"]
+
+[grants]
+# ⚠ ESTA JAULA ES ANCHA A PROPÓSITO, Y CONVIENE DECIRLO EN VEZ DE DISIMULARLO. Un agente que
+# construye recetas, commitea y empuja necesita exactamente lo que un humano haciendo ese trabajo:
+# el repo, el store, el lab y las llaves. Lo que la jaula sigue comprando es que ese alcance esté
+# ESCRITO y acotado a estos directorios — no que sea pequeño.
+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
+root = true
+wayland_raw = false
+seal_image = false
+
+# El repo: es el trabajo.
+[[grants.dirs]]
+host = "/opt/takana"
+inside = "/opt/takana"
+mode = "rw"
+
+# El lab y el toolchain (zig, go). `.dev-fs` del repo es un symlink acá, así que se concede el
+# destino real o el build no encuentra nada.
+[[grants.dirs]]
+host = "/work/dev-fs"
+inside = "/work/dev-fs"
+mode = "rw"
+
+# El store: sin esto no hay cache-hit, ni sellado, ni hash comparable.
+[[grants.dirs]]
+host = "/store"
+inside = "/store"
+mode = "rw"
+
+# La memoria del agente y sus credenciales. 733 ficheros de memoria y un `.credentials.json` de
+# 509 B: sin lo primero el agente arranca sin saber nada del proyecto; sin lo segundo, no arranca.
+[[grants.dirs]]
+host = "/root/.claude"
+inside = "/root/.claude"
+mode = "rw"
+
+# Las llaves: el gitea (push), el worker de la granja y el Storage Box. Sólo lectura.
+[[grants.dirs]]
+host = "/root/.ssh"
+inside = "/root/.ssh"
+mode = "ro"
+
+# El propio CLI, que vive fuera de la imagen a propósito: la imagen es ajena y pineada, y el CLI se
+# actualiza solo. Mezclarlos haría que `recreate` borrara el binario o que la imagen dejara de ser
+# la que dice ser.
+[[grants.dirs]]
+host = "/work/claude-cli"
+inside = "/work/claude-cli"
+mode = "ro"
+
+[export]