Arranque del proyecto hammer (distro AI-nativa: laboratorio funcional en el sótano, terminal mutable clásica arriba, integración de IA programadora). - Workspace Rust (compila, tests verdes): hammer-core, hammer-build, hammer-cli (bin `hammer`), hammerd. - SDDs 00-10 + 6 ADRs en docs/ con toda la arquitectura. - Esqueletos navegables mapeados a las fases del roadmap; Fase 0/1 listas para implementar el sandbox real. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.4 KiB
SDD 07 — Bus de init y de agente
El sistema se controla por tuberías UNIX puras, no por parseo de archivos .service
complejos. Hay dos canales, con propósitos distintos:
/run/init.control— FIFO de control humano, texto crudo. Ergonomía máxima./run/agent.sock— socket de control de agente (IA, scripts), JSON-líneas con framing y autenticación. Parseable y fiable.
1. El init por eventos UNIX
Tu init no lee configuraciones pesadas: expone una API por FIFO. Cualquier proceso —un script, un binario, o tú tecleando— controla el estado del sistema enviando bytes crudos:
echo "restart network" > /run/init.control
echo "start web" > /run/init.control
echo "stop web" > /run/init.control
Los servicios no se declaran en archivos pesados; se inyectan dinámicamente. El estado del
sistema es un flujo vivo y maleable que manipulas con herramientas estándar (cat, echo,
grep). Los servicios viven como directorios con un script run ejecutable (estilo s6/runit),
no como unidades declarativas opacas:
/etc/service/web/run # script ejecutable; el init lo supervisa
/etc/service/network/run
2. Por qué un segundo canal para la IA
El FIFO crudo es perfecto para humanos pero malo como API de máquina: no tiene framing fiable, ni forma de devolver eventos correlacionados, ni de saber quién habla. La IA necesita:
- enviar comandos estructurados y recibir eventos correlacionados (éxito/fallo de un build, crash de un servicio),
- autenticación del peer (que no cualquier proceso dispare builds o inyecte binarios),
- un protocolo pequeño, legible y versionado.
Por eso /run/agent.sock es un socket UNIX con:
- framing = JSON-líneas (un objeto JSON por línea,
\n-terminado), - auth =
SO_PEERCRED(UID/GID/PID del peer verificados por el kernel) + capacidades que el humano concede explícitamente (ver SDD 08), - versión en el handshake.
3. Protocolo del bus de agente
Handshake
{"t":"hello","ver":1,"client":"claude-agent"}
{"t":"welcome","ver":1,"caps":["compile","query"]} // caps según lo que el humano concedió
Comandos (cliente → hammerd)
| Comando | Forma | Efecto |
|---|---|---|
COMPILE |
{"t":"compile","recipe":{…}} o {"repo","commit","patch","build"} |
dispara un build en el lab |
INJECT |
{"t":"inject","artifact":"b3:…","target":"/bin/grep","overlay":"<id>"} |
hidrata en un overlay (o real si hay cap) |
QUERY |
{"t":"query","what":"file","path":"/etc/network.conf"} |
estado de un archivo/servicio/artefacto |
INIT |
{"t":"init","cmd":"start web"} |
proxy autenticado al control del init |
Eventos (hammerd → cliente)
| Evento | Forma | Significado |
|---|---|---|
BUILD_READY |
{"t":"build_ready","artifact":"b3:…","recipe":"grep"} |
build terminó OK |
BUILD_FAILED |
{"t":"build_failed","recipe":"grep","log_tail":"…"} |
build falló, con cola de log |
CRASHED |
{"t":"crashed","service":"web","code":127} |
un servicio supervisado murió |
MODIFIED |
{"t":"modified","path":"/bin/grep","by":{…}} |
el diario registró una mutación |
Ejemplo del bucle de autorreparación: la IA modifica el binario del servidor web, este falla
al arrancar; hammerd emite {"t":"crashed","service":"web","code":127}; la IA, escuchando,
lee el log (texto plano en /var/log), corrige la fuente, recompila, y reenvía start web.
Para el humano, el sistema "se autorreparó" — pero cada paso quedó en el bus y en el diario.
4. Seguridad del bus
- Sin auth, sin comandos. Conexión que no completa
helloválido se cierra. - Capacidades mínimas. Por defecto un agente sólo obtiene
query.compile,inject(a overlay) einject-real(al FHS real) se conceden explícita y separadamente. inject-reales especial. Inyectar al sistema real (no a overlay) requiere una capacidad aparte y, por política, confirmación humana. El flujo recomendado de la IA es siempre overlaycommithumano.
- Todo comando con efecto se registra (en el diario y/o un audit log del bus).
5. Interfaz
// hammerd
pub async fn serve_agent_bus(sock: &Path, caps_policy: CapsPolicy) -> Result<()>;
pub fn init_control_send(line: &str) -> Result<()>; // escribe en /run/init.control
CLI de conveniencia: hammer ctl "start web" (humano) · la IA usa el socket directamente.