Files
takana/docs/10-roadmap.md
T
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

151 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SDD 10 — Roadmap
## Estrategia: validar la capa AI-nativa sobre Alpine antes de la distro propia
La innovación de `hammer` no es la distro — es el substrato AI-nativo (build determinista +
mutable + diario + `.swm`). Construir bootstrap + init + userland de cero antes de validar esa
capa sería arriesgar meses contra una hipótesis no probada. Por eso:
> **Fase 06:** montamos `hammer` **sobre Alpine** (musl + busybox + FHS mutable, ya cocidos).
> Validamos el bucle completo en semanas.
> **Track posterior:** una vez probado, bajamos a distro propia (init propio, bootstrap propio,
> userland propio) reusando todo el tooling sin retrabajo.
Ver [ADR 0002](adr/0002-alpine-first.md).
---
## Fases (sobre Alpine)
### Fase 0 — Laboratorio de build ✅
- [x] `hammer-core`: tipos `Recipe`, `ArtifactHash`, `Store` (BLAKE3, layout `/store`).
- [x] `hammer-build`: sandbox con `bubblewrap` + `zig cc` → binario musl estático.
- [x] CAS: hashing de entrada, caché por hash, sellado en el store.
- [x] `hammer build <recipe.toml>` → imprime el hash del artefacto.
- [x] Fuente git **y** tarball (sha256 fijado), patches opcionales.
- [x] Heurística de build system: autotools / cmake / meson / make plano.
- [x] Caché persistente de zig entre builds (~30s/build ahorrados).
### Fase 1 — Hidratación ✅
- [x] `hydrate(hash, target, mode)`: hardlink a FHS, `patchelf` para el caso dinámico.
- [x] `hammer hydrate <hash> --into /`.
### 🎯 Primer entregable (Fase 0 + 1) ✅
**GNU grep 3.12 compilado estático desde el tarball upstream, sellado en el store
(`b3:b81e893e…`), hidratado por hardlink a `/usr/bin/grep` y ejecutado dentro del rootfs
Alpine vía `bwrap`** — confirma el corazón "fábrica funcional → FHS mutable" sobre el
substrato Alpine. La VM/LXC dedicada queda como ejercicio de empaque, no como
pre-requisito de validación.
### Fase 2 — Overlay de experimentación ✅
- [x] Crate `hammer-overlay`: `try` / `commit` / `discard` / `status` sobre `overlayfs`.
- [x] Manifiesto persistente en `<state_root>/<id>/state.json`; `status` enumera.
- [x] `commit` promociona archivos y procesa whiteouts (char dev 0/0) como remove.
- [x] Subcomandos del CLI: `hammer try [targets…]`, `commit <id>`, `discard <id>`, `status`.
- [x] Tests E2E con bwrap+user-ns, gateados en `HAMMER_OVERLAY_TESTS=1` (kernel-dependiente).
- [x] Hook al diario en `commit` (Fase 3 lo añadió vía `commit_with_journal`).
- [ ] Anidación real de overlays (un solo overlay activo por target hoy).
### Fase 3 — Diario de mutaciones ▶ *en progreso*
- [x] Crate `hammer-journal`: `MutationEvent`, `Source` (HammerHydrate/HammerCommit/External),
append/read/tail/follow JSON-líneas. RFC 3339 sin chrono.
- [x] `hammerd` con `fanotify` (FAN_CLOSE_WRITE) sobre `/bin`,`/sbin`,`/usr/bin`,`/usr/sbin`,
`/lib`,`/usr/lib`,`/etc`. Filtra eventos bajo overlays activos. Fallback graceful sin
CAP_SYS_ADMIN.
- [x] `hammer journal [--tail N] [--follow] [--format pretty|json]`.
- [x] `hammer commit` registra cada archivo promocionado vía `commit_with_journal`.
- [ ] Refinar op del watcher (Create vs Replace vs Edit con FAN_REPORT_DFID_NAME).
- [ ] Hash del contenido tras la mutación (`content_hash`) y de-dup idempotente.
### Fase 4 — Formato y flujo `.swm` ▶ *en progreso*
- [x] `Swm` de/serialización YAML estable (roundtrip).
- [x] `verify_schema` (estructura + invariantes por mutación) y `verify_base` (distro_version
+ pins) con `BaseRef` / `BaseCompat`.
- [x] `apply_config_edit` (hunks `-/+` con búsqueda exacta, no-fuzz) y `apply_file_drop`
(base64 inline + verificación BLAKE3 vs `content_hash`).
- [x] Bridge `Mutation::SourcePatch``Recipe` + `build` + hidratación.
- [x] CLI: `hammer apply [--prefix DIR] [--base-ref base.json]`,
`hammer swm-verify`, `hammer export --journal DIR > out.swm`.
- [ ] `patch_url` / `content_url` remotos (hoy sólo inline).
- [ ] Provenance en `export`: mapa artefacto→receta para emitir `source_patch` en vez de
`file_drop`. Hoy se emiten file_drops con `content_b64`, lo que reproduce byte-a-byte
pero pierde la receta original.
- [ ] Firma `signature` (ed25519) y `TrustStore` local.
- **Hecho cuando:** exportas un cambio, lo aplicas en otra máquina y reproduce idéntico.
✅ Demostrado en `crates/hammer-cli/tests/swm_roundtrip.rs` para
`config_edit` + `file_drop`. `source_patch` reusa el camino de Fase 0/1 (gated en
`HAMMER_NETWORK_TESTS`).
### Fase 5 — Bus de agente ▶ *en progreso*
- [x] `/run/init.control` (FIFO humano): `mkfifo`, reader que loguea cada línea, y
`hammer ctl <line>` que escribe al FIFO con error claro si no existe.
- [x] `/run/agent.sock` (JSON-líneas) con handshake `Hello/Welcome`, auth via
`SO_PEERCRED` y `CapsPolicy` por UID.
- [x] Comandos `Compile`/`Inject`/`Query`/`Init`; eventos
`Welcome`/`BuildReady`/`BuildFailed`/`Injected`/`QueryResult`/`InitAck`/
`Modified`/`Crashed`/`Error`.
- [x] EventBus in-process: el watcher publica `Modified` y todas las conexiones lo reciben.
- [x] Subsistemas independientes en `hammerd::main` (FIFO/watcher/bus en threads); si uno
falla en init, los demás siguen.
- [ ] Política expresiva: hoy es código (`default_policy`), pendiente leerla de
`/etc/hammer/agent-caps.toml`.
- [ ] `CRASHED` real (requiere supervisión de servicios, que llega con el init propio del
track posterior).
- [ ] `BuildFailed.log_tail` con cola real del lab (hoy es `None`; el `reason` viene del
`Error` de Rust pero no se conserva el log textual del sandbox).
- **Hecho cuando:** un cliente externo dispara un build y recibe el evento de fin por el
socket. ✅ Camino implementado (`Compile``BuildReady`/`BuildFailed`) y la maquinaria
alrededor cubierta por `crates/hammerd/tests/bus_e2e.rs`: handshake con peer creds,
gating `no_cap`, `Query`, `Modified` fan-out, `Init`→FIFO. Un `Compile` real reusa el
camino de Fase 0/1 (gated en `HAMMER_NETWORK_TESTS`).
### Fase 6 — Integración de la IA ▶ *en progreso*
- [x] Crate `hammer-agent` con tres piezas:
- `AgentClient`: cliente síncrono del bus (handshake, `compile`/`inject`/`query`/`init`
bloqueantes, drenado de eventos asíncronos).
- `IntentTranslator` (trait) + `MockTranslator` cargado desde un `IntentCatalog` YAML
(intent → `.swm` pre-armado). La integración con un LLM real se enchufa detrás del
mismo trait sin tocar el bucle.
- `Orchestrator` con `run(intent) → Proposal`: plan → schema → base → try (overlay
o prefix) → apply (mutaciones puras + source_patch vía bus opcional) → verify →
propose.
- [x] CLI: `hammer ai <intent> --catalog F [--prefix DIR --base-ref F --bus SOCK]`.
- [x] Tipos del protocolo del bus movidos a `hammer-core::proto` para que `hammerd` y
`hammer-agent` los compartan.
- [x] Tests:
- 10 unit en `hammer-agent` (translator + catalog + orchestrator).
- 3 e2e del bucle agéntico (prefix tmp → archivos esperados en disco).
- 1 e2e del cliente contra un *stub* del bus (handshake + Compile→BuildReady + Modified
asíncrono).
- [ ] Traductor LLM real (Claude API u otro), opcional vía feature flag o crate aparte.
- [ ] Lenguaje de consulta del sistema (SDD 08 §6) para que la IA refiera servicios y
archivos sin rutas frágiles.
- [ ] Bucle de auto-reparación (cliente reacciona a `Crashed` con un nuevo plan).
- **Hecho cuando:** una intención en lenguaje natural produce un cambio probado en overlay,
presentado para `commit` humano. ✅ Demostrado por `hammer ai` con `MockTranslator`:
intent → `.swm` → mutaciones aplicadas → `Proposal` con `overlay_id` + checks. El humano
decide `commit`/`discard`. El upgrade a LLM real reusa todo el bucle.
---
## Track posterior — distro propia
- Reemplazar el init de Alpine por **tu init** (bus por pipes nativo).
- **Bootstrap from-scratch** con `zig`/`musl-cross-make` (Stage 0/1/2 → imagen destino).
- Userland propio (busybox/toybox a elección), `/etc/service/*` propios.
- Decidir particionado/montaje de `/store` y `/var/lib/hammer`.
- Log de transparencia para compartir en comunidad ([SDD 09](09-trust-model.md) §4).
- Mini-lenguaje de consulta del sistema para la IA ([SDD 08](08-ai-integration.md) §6).
---
## Estado actual
- ✅ Repo y workspace Rust inicializados.
- ✅ SDDs y ADRs redactados.
- ✅ Esqueletos de crates que compilan (`hammer build` stub).
- ⏭️ Siguiente: implementar el sandbox de build real (Fase 0) y montar la VM/LXC Alpine.
## Notas de entorno
- Desarrollo principal: laptop del autor.
- Host actual: Proxmox (`gioser.net`). La VM/LXC Alpine de pruebas vivirá aquí o en la laptop.
- Repo: `https://gitea.gioser.net/sergio/hammer`.