Onboarding · sin asumir nada previo

Una oficina
que se opera sola.

Agent Squad es una plataforma donde un equipo de agentes de IA ejecuta el trabajo de una oficina — y deja registro de cada paso, para que un humano pueda verlo, auditarlo y aprobar lo que importa.

Esta guía te lleva de no saber nada a poder operar el sistema y validar que cada componente corre óptimo. Diez minutos. Empezamos por el problema.

El problema que resuelve. Un LLM suelto es brillante pero amnésico: no recuerda qué hizo, no deja rastro, no se le puede pedir cuentas. Si va a hacer trabajo real —mover dinero, mandar correos, cerrar tareas— necesitás saber qué hizo, con qué datos, y poder frenarlo antes de un paso sensible. Eso es lo que agrega el substrato.
Capítulo 1

La idea central: el substrato

El substrato es la capa por debajo de los agentes que convierte "la IA hizo algo" en un grafo trazable. Cada pedido deja una cadena de eslabones, y cada eslabón apunta a su origen (su provenance). Nada se pierde, nada es magia.

Toda la operación gira alrededor de una sola cadena. Aprendela y el resto encaja:

flowchart LR I["intent
lo que se pidió"] --> P["plan
cómo hacerlo"] P --> T["trace
la corrida"] T --> S["step
cada paso"] S --> A["artifact
lo que produjo"] A --> C["claim
lo que afirma"]

intent = el pedido (en lenguaje natural o estructurado). plan = los pasos que lo resuelven (un DAG). trace = una ejecución concreta de ese plan. step = un paso (su definición) vs. step_execution = lo que realmente pasó al correrlo. artifact = lo que produjo. claim = una afirmación con su fuente. Esa distinción definición↔ejecución es la que te deja depurar.

Capítulo 2

El ciclo de un pedido, de punta a punta

Cuando alguien pide algo en la oficina, esto es lo que ocurre por debajo. Los dos puntos de control humano (los gates) son el corazón de la seguridad:

flowchart TB U(["👤 Pedido en la oficina"]) --> NOVA["Nova compone"] NOVA --> PLAN["plan + steps
(en la base de datos)"] PLAN --> EXEC["Executor durable
recorre el DAG"] EXEC --> STEPS["traces + step_executions
+ artifacts + claims"] STEPS --> GATE{"¿paso sensible?"} GATE -->|sí| WAIT["⏸ run-gate
suspende hasta tu OK (≤72h)"] GATE -->|no| DONE["✓ continúa"] WAIT -->|aprobás| DONE
Dos gates, no confundir. El run-gate (human_gate) frena una corrida antes de un paso sensible — "¿mando este correo?". El build-gate (cap. 6) frena la creación de una capacidad nueva antes de registrarla — "¿incorporo esta herramienta?". Uno aprueba acciones; el otro, capacidades.
Capítulo 3

Nova y sus 4 desenlaces

Nova es quien recibe el pedido y decide cómo resolverlo. Frente a cualquier intent, siempre termina en uno de cuatro desenlaces:

① MATCH

Ya existe una superskill del workspace que hace exactamente esto → la usa.

② PLAN

No hay una sola pieza, pero sí las piezas → compone un plan combinando operaciones existentes.

③ FORGE

Falta una capacidad pura y bien definida → la construye en el momento (cap. 6).

④ CANNOT

No se puede (falta info, permiso, o un side-effect no autorizado) → lo dice con honestidad, no inventa.

La regla mental para la taxonomía: una operación es un ladrillo (una función pura), un workflow es una pared (pasos encadenados), una superskill es una casa (capacidad reutilizable del workspace), y un agente es quien las habita. Nova construye paredes con ladrillos; FORGE fabrica un ladrillo que faltaba.

Capítulo 4

Cómo está montado (y qué es el substrato)

Despejemos la confusión más común de una. El substrato no es la base de datos. El producto tiene dos mitades (vas a ver este marco en todos los docs): la app (apps/web, la oficina que ve el usuario) y el substrato (apps/api, el cerebro del backend que ejecuta y registra todo). El substrato es esa plataforma completa: su corazón es el runtime, y a su alrededor usa tres piezas de infraestructura — la base de datos (donde vive el grafo), el motor durable y la observabilidad. La base de datos es una de ellas, no el todo. El prefijo substrate- que vas a ver en la infra (substrate-postgres, substrate-inngest…) marca lo que pertenece al substrato — no que cada pieza sea el substrato.

Todo corre en un servidor Hetzner (8 CPU / 16 GB). Un solo box es un trade-off consciente de etapa: la robustez es fail-loud + aislamiento, no redundancia.

El substrato — cuatro piezas en el box

⚙️

El runtime agent-squad-api

Recibe los pedidos, corre a Nova, ejecuta los planes y dispara FORGE. Es el cerebro; systemd.

🗄️

La base de datos :5433

Postgres donde vive el grafo intent→plan→trace — el system-of-record. En la infra: substrate-postgres.

⏱️

El motor durable Inngest :8288

Corre los pasos, reintenta, y suspende en los gates sin perder estado.

🔭

La observabilidad Langfuse :3030

Cada llamada al modelo con su prompt, respuesta, tokens y costo.

Encima del substrato — dos servicios managed (no en el box)

🏢

apps/web Vercel

La oficina 3D — el único frente que ve el usuario. Se apoya en el substrato vía HTTP.

🔑

InsForge cloud

Auth, control de acceso y estado de la app. Separado del substrato a propósito.

flowchart TB subgraph CLOUD["managed (no en el box)"] WEB["🏢 apps/web · Vercel"] INS["🔑 InsForge"] end subgraph BOX["EL SUBSTRATO · corre en el box Hetzner (8 CPU/16 GB)"] API["⚙️ runtime · agent-squad-api"] DB[("🗄️ base de datos :5433")] INN["⏱️ motor · Inngest :8288"] LF["🔭 observabilidad · Langfuse :3030"] API --> DB API <--> INN API --> LF end WEB -->|HTTPS + bearer| API WEB -.auth.-> INS
Capítulo 5 · lo que vas a hacer todos los días

Operar: validar que todo corre óptimo

No tenés que adivinar si el sistema está sano. Un solo comando lo dice, componente por componente:

# un solo comando · 🟢/🟡/🔴 por pieza · solo lee, no toca nada
cd ~/agent-squad-app && bash scripts/healthcheck.sh

Sale con código 0 (sano) o 1 (algo crítico en rojo). Esto es lo que valida y cómo lo lees:

ComponenteQué = sanoSi está 🔴
Runtime (api)active + /health status oksudo systemctl restart agent-squad-api.service
Base de datos substrate-postgrescontainer healthy, SELECT 1 OKcd ~/substrate-infra/postgres && docker compose up -d
Inngesthealthy, dashboard responderevisar INNGEST_SERVE_HOST (la trampa silenciosa)
Langfuse6 containers runningcd ~/substrate-infra/langfuse && docker compose up -d
Recursosload < cores, RAM > 2Gi, disco < 80%buscar huérfanos de plugins (busy-loop)
Backupsúltimo dump < 26hverificar el cron 03:00 + restore-drill.sh
La trampa que más cuesta. Inngest puede estar "up" pero no invocar ninguna función (los workflows quedan colgados para siempre). Casi siempre es INNGEST_SERVE_HOST mal puesto en localhost en vez de host.docker.internal:4000. Un canario corre cada 10 min y te avisa por Telegram 🔴 Motor async CAÍDO — no esperás a que un usuario lo note.

Si el box se reinició — arranque en frío

El orden importa: la DB primero, el runtime al final.

cd ~/substrate-infra/postgres  && docker compose up -d   # 1. base de datos
cd ~/substrate-infra/inngest   && docker compose up -d   # 2. Motor durable
cd ~/substrate-infra/langfuse  && docker compose up -d   # 3. Observabilidad
sudo systemctl start agent-squad-api.service             # 4. Runtime
bash ~/agent-squad-app/scripts/healthcheck.sh            # 5. validar todo 🟢

¿Algo falló y querés ver por qué? Con un trace_id + workspace_id tenés la vista de un-solo-lugar (GET /api/workspaces/:id/traces/:traceId) y, para profundizar, 4 lugares: la DB (estado crudo), Inngest (la ejecución durable), Langfuse (cada LLM call) y journald (el runtime).

Capítulo 6

FORGE: forjar la capacidad que falta

Es el desenlace ③ de Nova, y lo que hace único al sistema: cuando falta una capacidad pura (entra dato, sale dato, sin efectos en el mundo), el substrato la construye en caliente en un loop seguro:

flowchart LR GAP["falta una
capacidad pura"] --> GEN["genera código + tests"] GEN --> VER["verifica en sandbox
(red denegada)"] VER -->|rojo| GEN VER -->|verde| BG{"⏸ build-gate
humano"} BG -->|aprobás| REG["registra → callable"]

Solo construye ops puras a propósito: algo sin side-effects se puede verificar de forma determinista en un sandbox aislado antes de que un humano lo apruebe. Nada se incorpora solo.

Dos motores intercambiables. El mismo loop puede correr en el motor nativo (Inngest + sandbox bubblewrap — en vivo hoy) o delegarse al brazo de Eve (agentes de Vercel — experimental), detrás de un flag. Eve no es un frente alterno: opera por debajo de la app y registra la capacidad de vuelta vía el substrato — la verdad sigue viviendo en su base de datos, no en Vercel. Encenderlo:
  1. Desplegar el agente Eveeve start (local) o eve deploy (Vercel) desde experiments/forge-eve/.
  2. Apuntar el substrato — en apps/api/.env: FORGE_EVE_ENABLED=true + FORGE_EVE_URL=<base>.
  3. Reiniciarsudo systemctl restart agent-squad-api.service.
  4. Verificar — disparar un cannot y confirmar forge delegated to eve arm en el log.

Default OFF → el camino nativo es idéntico. Para volver: FORGE_EVE_ENABLED=false + restart. Sin estado que migrar.

Capítulo 7

¿A dónde sigo?

Ya tenés el modelo completo: qué resuelve, la cadena del grafo, Nova, el substrato y sus cuatro piezas, cómo validar salud y cómo forja. Para profundizar:

El verdadero test: corré bash scripts/healthcheck.sh y, ante cada 🔴, sabé exactamente dónde mirar y qué hacer. Si eso fluye sin dudar, estás listo para tu primera tarea real.