Files
hammer/docs/08-ai-integration.md
Sergio 89ecd54135 Fase 6 — bucle agéntico: hammer-agent (cliente + translator + orchestrator) y hammer ai
- proto: mover hammerd::proto a hammer-core::proto para que hammerd y hammer-agent
  compartan los tipos del bus sin duplicar.
- hammer-agent (crate nuevo):
  * client: AgentClient síncrono. Handshake hello/welcome; compile/inject/query/init
    bloqueantes con timeout; reader thread interno demultiplexa async events (Modified/
    Crashed) en una cola que el caller drena vía drain_async/next_async.
  * translator: trait IntentTranslator + MockTranslator (HashMap<intent, Swm>) +
    IntentCatalog YAML (swm_inline o swm_path). El traductor LLM real se enchufa
    detrás del mismo trait sin cambios al orquestador.
  * orchestrator: Orchestrator::run(intent) -> Proposal con plan -> schema -> base ->
    try (overlay|prefix) -> apply (config_edit/file_drop con hammer-core::apply,
    source_patch via bus opcional) -> verify (spot-checks) -> propose. Devuelve
    overlay_id (para `hammer commit`) o prefix usado.
- hammer-cli: subcomando `hammer ai <intent> --catalog F [--prefix DIR --base-ref F
  --bus SOCK --state-root DIR]`. Imprime el Proposal y el siguiente paso humano.
- Tests:
  * 10 unit (translator + catalog + orchestrator).
  * 3 e2e del bucle agéntico (intent -> archivos esperados bajo un prefix tmp).
  * 1 e2e del cliente contra un stub bus (handshake + Compile -> BuildReady +
    Modified asíncrono), sin depender de hammerd ni del lab.
- Docs: SDD 08 actualizado con el API del crate; roadmap marca lo cerrado y lo
  pendiente (LLM real, lenguaje de consulta, bucle de auto-reparación con Crashed).
2026-06-09 15:47:37 +00:00

143 lines
6.9 KiB
Markdown

# SDD 08 — Integración de la IA
La IA es un **artesano hiperveloz en el taller**; el humano es **el dueño que decide si el
mueble entra a la casa o se va a la basura.** Esta sección define el bucle agéntico, sus
garantías de seguridad, y cómo una intención en lenguaje natural se vuelve un cambio real.
## 1. La terminal como runtime de la IA
La IA no es un chat en una ventana que te dice qué teclear. Opera directamente sobre el sistema
a través del **bus de agente** ([SDD 07](07-agent-bus.md)) y de un **overlay**
([SDD 04](04-overlay.md)). Su entorno de trabajo es el sistema real, con red de seguridad.
## 2. El bucle agéntico
```
intención (NL)
│ "que grep ignore binarios por defecto y use regex Perl,
│ y que la red use IP estática 192.168.1.100"
┌─────────────┐
│ PLAN │ la IA traduce la intención a un .swm: qué herramienta,
│ │ qué patch de fuente, qué flags, qué config editar
└──────┬──────┘
┌─────────────┐
│ BUILD │ COMPILE por el bus → el lab clona repo@commit, aplica patch,
│ (lab) │ compila estático con zig cc → artifact_hash
└──────┬──────┘
┌─────────────┐
│ TRY │ hammer try → overlay temporal; INJECT del artefacto y de las
│ (overlay) │ ediciones de config en la capa. El sistema real intacto.
└──────┬──────┘
┌─────────────┐
│ VERIFY │ corre el test harness; escucha BUILD_FAILED / CRASHED por el bus.
│ │ si falla → corrige fuente → recompila (vuelve a BUILD).
└──────┬──────┘
┌─────────────┐
│ PROPOSE │ la IA avisa: "listo, probé esto, aquí el diff y el resultado".
│ │ presenta el .swm y la evidencia.
└──────┬──────┘
┌─────────────┐
│ HUMANO │ tú decides: hammer commit (promueve + diario) o hammer discard.
│ decide │ La IA NUNCA promueve al FHS real por su cuenta (ver §4).
└─────────────┘
```
## 3. Por qué esta arquitectura se presta (y otras no)
- **Determinismo del lab** → la IA puede recompilar y volver atrás sin dramas; el resultado es
predecible.
- **Texto plano + binarios atómicos** → la IA lee/escribe archivos e inspecciona binarios con
`readelf`/`objdump`; no parsea bases de datos opacas.
- **musl legible** → el código C de la libc base es comprensible en el contexto de un LLM
(glibc es un laberinto de macros).
- **Enlazado estático** → una herramienta mutada corre sin romper enlaces de otros programas.
- **Mutabilidad + overlay** → agencia real con red de seguridad; sin rollbacks pesados.
En distros inmutables/declarativas, la IA tendría que lidiar con generadores de config y
políticas read-only; en tradicionales, no tendría provenance. `hammer` mantiene las **tuberías
expuestas y de baja entropía**, que es justo lo que un agente necesita.
## 4. Garantías de seguridad (no negociables)
1. **La IA trabaja en overlay por defecto.** Sin capacidad `inject-real`, no puede tocar el
FHS base. El flujo es siempre overlay → `commit` humano.
2. **Capacidades mínimas y explícitas.** El humano concede `query`/`compile`/`inject` por
separado vía la política del bus ([SDD 07](07-agent-bus.md)).
3. **Toda acción es reversible y registrada.** `discard` revierte el overlay; el `commit`
entra al diario firmado ([SDD 05](05-journal.md)).
4. **Recetas, no binarios.** La IA produce `.swm` (fuente + flags + config), no binarios
opacos. Lo que comparte es verificable por terceros ([SDD 06](06-swm-format.md)).
5. **El humano tiene la última palabra.** Ningún cambio se vuelve permanente sin `commit`.
## 5. De la intención al `.swm`: el rol del modelo
El traductor intención→`.swm` se conecta detrás del trait `IntentTranslator` del crate
`hammer-agent`. Contrato:
- **Entrada:** intención en NL + `SystemContext` (lo que el orquestador recolecta por
`QUERY`: `BaseRef` local, extras JSON).
- **Salida:** un `Swm` válido ([SDD 06](06-swm-format.md)).
Fase 6 entrega un `MockTranslator` que resuelve intentos contra un `IntentCatalog` YAML
(intent exacto → `.swm` inline o `swm_path` relativo). Eso permite probar el bucle sin LLM:
el humano que descubrió la intención con un modelo real congela el resultado y los CI lo
reproducen byte-a-byte. El traductor LLM (Claude API u otro) implementa el mismo trait y se
enchufa sin tocar el `Orchestrator`.
**El modelo nunca ejecuta nada directamente:** emite comandos por el bus, que `hammerd`
valida contra las capacidades concedidas, y el `Orchestrator` traduce las mutaciones a
`hammer-core::apply` o a `Compile` por el bus.
## 6. Lenguaje de consulta/transformación (visión, Fase posterior)
Para que la IA refiera partes del sistema sin rutas absolutas frágiles, un mini-lenguaje de
consulta sobre el grafo del sistema:
```
find /service/web -where "depends_on(libssl)" -> replace_with my_tls
```
El daemon traduce esa consulta estructurada a acciones reales del bus. La terminal sigue siendo
el lugar de validación final. Esto es visión, no Fase 0 — se diseñará cuando el bucle básico
esté probado.
## 7. Interfaz
El crate `hammer-agent` (Fase 6) expone:
```rust
// hammer_agent::client
pub struct AgentClient { pub welcome: Welcome, /* … */ }
impl AgentClient {
pub fn connect(sock: &Path) -> Result<Self>;
pub fn compile(&mut self, recipe: RecipeInline, timeout: Duration) -> Result<String>; // artifact
pub fn inject(&mut self, artifact: &str, target: &str, overlay: Option<&str>, t: Duration) -> Result<usize>;
pub fn query_file(&mut self, path: &str, timeout: Duration) -> Result<serde_json::Value>;
pub fn init(&mut self, cmd: &str, timeout: Duration) -> Result<()>;
pub fn drain_async(&self) -> Vec<Event>;
pub fn next_async(&self, timeout: Duration) -> Result<Event>;
}
// hammer_agent::translator
pub trait IntentTranslator { fn translate(&self, intent: &str, ctx: &SystemContext) -> Result<Swm, TranslateError>; }
pub struct MockTranslator { /* HashMap<intent, Swm> */ }
pub struct IntentCatalog { pub intents: Vec<CatalogEntry> } // YAML loader
// hammer_agent::orchestrator
pub struct Orchestrator<T: IntentTranslator> { /* … */ }
impl<T> Orchestrator<T> {
pub fn new(t: T, base: BaseRef, apply: ApplyTarget, compile: CompileMode) -> Self;
pub fn run(&self, intent: &str) -> Result<Proposal>;
}
```
Los tipos del protocolo (`Command`/`Event`/`Cap`/`Peer`/`RecipeInline`) viven en
`hammer-core::proto` para ser compartidos por `hammerd`, `hammer-agent` y cualquier cliente
externo escrito en Rust.