Files
hammer/docs/07-agent-bus.md
sergioandClaude Opus 4.8 8bf1623044 Scaffold inicial: workspace Rust + SDDs completos
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>
2026-06-06 19:06:04 +00:00

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:

  1. /run/init.control — FIFO de control humano, texto crudo. Ergonomía máxima.
  2. /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 hello válido se cierra.
  • Capacidades mínimas. Por defecto un agente sólo obtiene query. compile, inject (a overlay) e inject-real (al FHS real) se conceden explícita y separadamente.
  • inject-real es 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 overlay
    • commit humano.
  • 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.