ar deterministas — dos builds sellaban bytes distintos
CÓMO SE VIO. Construir zlib en gioser y en el worker nuevo dio el MISMO ArtifactHash y BYTES DISTINTOS. `hammer why-differs` lo nombró exacto: 13 entradas idénticas, 1 diverge — `usr/lib/libz.a`, cabecera `ar` del miembro `/` (la tabla de símbolos), mtime 1787326910 vs 1787950875. Es la hora de pared de cada build. CAUSA, AISLADA POR BISECCIÓN EN EL LAB (no por lectura de código): · `zig ar` (llvm-ar) → mtime 0 ✅ · `ranlib` del rootfs Alpine → mtime 0 ✅ (Alpine compila binutils con --enable-deterministic-archives) · `ar` y `ranlib` de NUESTRO recipes/binutils.toml → hora de pared ❌ · los mismos con `-D` → mtime 0 ✅ La receta de binutils no pasa --enable-deterministic-archives, así que toda receta que lo materialice como build-dep y llame a ar/ranlib hereda la hora. Y el comentario de SOURCE_DATE_EPOCH en este mismo fichero AFIRMABA cubrir `ar`. Era falso: binutils no lee esa variable. Corregido, porque una suposición escrita en un comentario es la que impide que alguien vuelva a medir. ARREGLO. Wrappers `ar`/`ranlib` en /usr/local/bin (que gana al /usr/bin del PATH) que anteponen `-D`. Mismo patrón que ya usa el sandbox para arreglar esta CLASE de bug sin re-hashear: -mcpu=baseline, CARGO_PROFILE_RELEASE_CODEGEN_UNITS, CARGO_BUILD_JOBS. `-D` antepuesto y no como modificador de la cadena de operación, porque la operación la pone el llamador en "$@" y no se puede reescribir. Verificado: la secuencia exacta de zlib (`ar rc` + `ranlib`) da mtime 0 y el índice del archivo sigue siendo legible (`ar t`, `nm -s`). POR QUÉ AQUÍ Y NO EN LA RECETA. Arreglar recipes/binutils.toml es la cura de raíz, pero `yupana radio binutils` da 421 dependientes transitivos y 365 sellados a deuda, en las siete imágenes — desproporcionado frente a los 9 artefactos realmente contaminados (medidos barriendo los 185 artefactos con .a del store: elfutils, elfutils-libdw ×4, zlib, musl-fts, musl-obstack, argp-standalone). La cura de raíz se agenda para el próximo rebuild del corpus que ya haya que hacer por otro motivo. PENDIENTE Y DICHO EN VOZ ALTA: esto cambia los BYTES sin cambiar la DIRECCIÓN de esos 9. Hay que re-sellarlos a propósito — es el mismo peligro que la huella del lab existe para eliminar, y no se cierra solo. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LykB7vw38b4Ck1Zij15RQ4
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.