# 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: ```sh 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](08-ai-integration.md)), - **versión** en el handshake. ## 3. Protocolo del bus de agente ### Handshake ```json {"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":""}` | 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 ```rust // 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: `takana ctl "start web"` (humano) · la IA usa el socket directamente.