Seguir con lo que el §7.decies dejó abierto —quién levanta la app, de dónde sale la raíz de las claves— terminó en una respuesta incómoda y en un bug que valía la pena encontrar. La cadena, medida hacia atrás desde la app: · `raiz_de_identidad()` saca la seed del llavero del KERNEL (`pacha_llavero::SEED_IDENTIDAD`); · la escriben dos lugares en todo tawasuyu: `agora-cli identity unlock` y `churay-welcome-runner`; · `agora-cli` está sellado y en `perfiles: []` — en ninguna imagen. Y aunque se declarara, su pin es del 2026-06-18, donde no existen ni `SEED_IDENTIDAD` ni `desbloquear` (git grep sobre el pin, con HEAD de control: 4 y 1 aciertos); · `churay-welcome` no tiene receta en takana. ⇒ en ninguna imagen hay un binario capaz de sembrar la identidad. No es que el usuario no la desbloqueó: es que no tiene con qué. Y lo que el navegador veía NO era «cerrada». Cuando `abrir()` falla, la app levantaba el socket igual, sobre `bóveda_imposible()` —un sled en /tmp/boveda-sin-abrir-<pid>—, así que la extensión recibía `locked:false, count:0` y un `vault.save` consentido guardaba en un temporal que muere con el proceso. La ventana decía la verdad; el navegador, lo contrario. Arreglado en tawasuyu (`7917fbb96`) con test de regresión en los dos sentidos, y probado al revés: con el `if` neutralizado, el test falla con el mensaje que corresponde. Pin de las dos recetas a `6f0408d40`, que trae además el `Cargo.lock` cerrado. Ahí apareció la vuelta que no estaba escrita: la «operación mínima» del §7.octies (`cargo metadata` sin `--locked`) corrida en una jaula con el registro de cargo INCOMPLETO devuelve 0 y deja un lock al que le faltan dos miembros del workspace — y su diff se ve MÁS mínimo que el correcto (−15 líneas contra +1). Que diera byte a byte igual al de otra sesión no lo confirmaba: las dos se calcularon con el mismo instrumento roto. Y una trampa más, medida hoy: la guarda de receta del §7.quinquies.bis NO alcanza para una TANDA. Puesta una vez al principio, `shuma-pregunta` selló bien y `boveda` —once minutos después— dio «artefacto ya en el store» sobre la receta VIEJA, porque el latido revierte el árbol del worker en el medio. La guarda va pegada a CADA build, y la cura de fondo es publicar la receta antes de construir. De paso, dos correcciones a lo que este mismo frente escribió hace unas horas: · el `app_id`: llimphi SÍ lo pone (`with_name`, con el nombre del ejecutable de piso) ⇒ la ventana es `boveda`, igual que el basename del `.desktop`, y por eso no hace falta `StartupWMClass`. Lo que sí queda mal es el TÍTULO, que dice «llimphi»; · el GL: que las imágenes sean iris-only no es una decisión pendiente sino una escrita (SDD 14), y el caso de la VM ya tiene camino — los runbooks montan `mesa-llvmpipe` como capa. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
hammer
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 comparta el sistema.
hammer no es otro gestor de paquetes inmutable. Es una arquitectura de dos mundos:
- El laboratorio compila desde fuentes upstream (commits fijados), de forma
determinista y aislada (
bubblewrap+zig cc+ musl estático), y direcciona cada artefacto por su hash (BLAKE3) en un content-addressed store. - El userland es un Linux clásico, mutable, con FHS de verdad (
/bin,/lib,/etc). Los binarios se hidratan desde el store por hardlinks. Puedes pisar archivos en caliente, romper cosas con unrm -rf, y revertir cuando quieras.
Entre ambos mundos viven las tres piezas que hacen a hammer distinto:
- Overlay de experimentación — prueba cambios sobre el sistema real con red de
seguridad;
hammer try/commit/discard. - Diario de mutaciones — un daemon
fanotifyregistra todo lo que tú (o la IA) cambiáis a mano. Vives imperativamente; el sistema genera el delta contra la base limpia. El diario es tu configuración — sin ser declarativa. - Manifiesto
.swm— compartes la receta de la mutación (parche de fuente + flags + ediciones de config), no el binario cocinado. El receptor reproduce y verifica; no confía en tu binario.
Encima de todo corre el bus de agente (/run/agent.sock): la IA habla un protocolo
pequeño y legible, dispara compilaciones, inyecta en el overlay, escucha fallos y reacciona.
Tú tienes la última palabra.
Estado
Fase de arranque. Validamos la capa AI-nativa sobre Alpine (musl + FHS ya cocidos)
antes de bajar a distro propia. Ver docs/10-roadmap.md.
Documentación de diseño (SDD)
Toda la arquitectura está en docs/. Empieza por
docs/00-vision.md y docs/01-architecture.md.
Estructura
crates/
hammer-core tipos compartidos: Recipe, Swm, hashing CAS, store
hammer-build el laboratorio: sandbox + compilación + hidratación
hammer-cli el binario `hammer` (build, hydrate, try, commit, apply, export…)
hammerd daemon: bus de agente + diario de mutaciones
docs/ SDDs y ADRs
Stack
| Capa | Decisión |
|---|---|
| Base de validación | Alpine (musl + FHS mutable) |
| Tooling / daemons | Rust (estático-musl) |
| Compilador del lab | zig cc por defecto, pluggable por receta |
| Sandbox de build | bubblewrap (namespaces) |
| Direccionamiento | BLAKE3 content-addressed store |
| Despliegue | Hidratación por hardlinks + patchelf |
Filosofía
La automatización es mi empleada en el sótano, pero en el piso de arriba mando yo.
Eficiencia matemática en la manufactura, libertad biológica en la ejecución.