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>
This commit is contained in:
@@ -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:
|
||||
|
||||
Executable
+15
@@ -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 "$@"
|
||||
@@ -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]
|
||||
Reference in New Issue
Block a user