1# SDD 07 — Bus de init y de agente
2
3El sistema se controla por **tuberías UNIX puras**, no por parseo de archivos `.service`
4complejos. Hay dos canales, con propósitos distintos:
5
61. **`/run/init.control`** — FIFO de control **humano**, texto crudo. Ergonomía máxima.
72. **`/run/agent.sock`** — socket de control de **agente** (IA, scripts), JSON-líneas con
8 framing y autenticación. Parseable y fiable.
9
10## 1. El init por eventos UNIX
11
12Tu init no lee configuraciones pesadas: expone una API por FIFO. Cualquier proceso —un script,
13un binario, o tú tecleando— controla el estado del sistema enviando bytes crudos:
14
15```sh
16echo "restart network" > /run/init.control
17echo "start web" > /run/init.control
18echo "stop web" > /run/init.control
19```
20
21Los servicios no se declaran en archivos pesados; se **inyectan dinámicamente**. El estado del
22sistema es un flujo vivo y maleable que manipulas con herramientas estándar (`cat`, `echo`,
23`grep`). Los servicios viven como directorios con un script `run` ejecutable (estilo s6/runit),
24no como unidades declarativas opacas:
25
26```
27/etc/service/web/run # script ejecutable; el init lo supervisa
28/etc/service/network/run
29```
30
31## 2. Por qué un segundo canal para la IA
32
33El FIFO crudo es perfecto para humanos pero malo como API de máquina: no tiene framing fiable,
34ni forma de devolver eventos correlacionados, ni de saber **quién** habla. La IA necesita:
35
36- enviar comandos estructurados y recibir **eventos** correlacionados (éxito/fallo de un build,
37 crash de un servicio),
38- **autenticación** del peer (que no cualquier proceso dispare builds o inyecte binarios),
39- un protocolo pequeño, legible y versionado.
40
41Por eso `/run/agent.sock` es un socket UNIX con:
42
43- **framing** = JSON-líneas (un objeto JSON por línea, `\n`-terminado),
44- **auth** = `SO_PEERCRED` (UID/GID/PID del peer verificados por el kernel) + capacidades que
45 el humano concede explícitamente (ver [SDD 08](08-ai-integration.md)),
46- **versión** en el handshake.
47
48## 3. Protocolo del bus de agente
49
50### Handshake
51
52```json
53{"t":"hello","ver":1,"client":"claude-agent"}
54{"t":"welcome","ver":1,"caps":["compile","query"]} // caps según lo que el humano concedió
55```
56
57### Comandos (cliente → hammerd)
58
59| Comando | Forma | Efecto |
60|---|---|---|
61| `COMPILE` | `{"t":"compile","recipe":{…}}` o `{"repo","commit","patch","build"}` | dispara un build en el lab |
62| `INJECT` | `{"t":"inject","artifact":"b3:…","target":"/bin/grep","overlay":"<id>"}` | hidrata en un overlay (o real si hay cap) |
63| `QUERY` | `{"t":"query","what":"file","path":"/etc/network.conf"}` | estado de un archivo/servicio/artefacto |
64| `INIT` | `{"t":"init","cmd":"start web"}` | proxy autenticado al control del init |
65
66### Eventos (hammerd → cliente)
67
68| Evento | Forma | Significado |
69|---|---|---|
70| `BUILD_READY` | `{"t":"build_ready","artifact":"b3:…","recipe":"grep"}` | build terminó OK |
71| `BUILD_FAILED` | `{"t":"build_failed","recipe":"grep","log_tail":"…"}` | build falló, con cola de log |
72| `CRASHED` | `{"t":"crashed","service":"web","code":127}` | un servicio supervisado murió |
73| `MODIFIED` | `{"t":"modified","path":"/bin/grep","by":{…}}` | el diario registró una mutación |
74
75Ejemplo del bucle de autorreparación: la IA modifica el binario del servidor web, este falla
76al arrancar; `hammerd` emite `{"t":"crashed","service":"web","code":127}`; la IA, escuchando,
77lee el log (texto plano en `/var/log`), corrige la fuente, recompila, y reenvía `start web`.
78Para el humano, el sistema "se autorreparó" — pero cada paso quedó en el bus y en el diario.
79
80## 4. Seguridad del bus
81
82- **Sin auth, sin comandos.** Conexión que no completa `hello` válido se cierra.
83- **Capacidades mínimas.** Por defecto un agente sólo obtiene `query`. `compile`, `inject` (a
84 overlay) e `inject-real` (al FHS real) se conceden explícita y separadamente.
85- **`inject-real` es especial.** Inyectar al sistema real (no a overlay) requiere una capacidad
86 aparte y, por política, confirmación humana. El flujo recomendado de la IA es siempre overlay
87 + `commit` humano.
88- **Todo comando con efecto se registra** (en el diario y/o un audit log del bus).
89
90## 5. Interfaz
91
92```rust
93// hammerd
94pub async fn serve_agent_bus(sock: &Path, caps_policy: CapsPolicy) -> Result<()>;
95pub fn init_control_send(line: &str) -> Result<()>; // escribe en /run/init.control
96```
97
98CLI de conveniencia: `takana ctl "start web"` (humano) · la IA usa el socket directamente.
07-agent-bus.md
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
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
- 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: takana ctl "start web" (humano) · la IA usa el socket directamente.