Diseño del sistema para manejar 20-30 agentes Claude hablando solo con uno: 4 roles (orquestador/splitter/ejecutores/verificador), DoD-contrato fijo en goal.json como criterio estable de terminación, máquina de terminación clasificable sin LLM, y 3 fases (watcher edge-triggered, orquestador reactivo + verificador independiente, spawn en flota + splitter). Métrica de salud = throughput de DoD cumplidos. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
11 KiB
name, id, status, created, updated, priority, risk, related_issues, apps, trigger, schedule, expected_runtime_s, tags, dod_evidence_schema
| name | id | status | created | updated | priority | risk | related_issues | apps | trigger | schedule | expected_runtime_s | tags | dod_evidence_schema | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| fleet-orchestrator-dod | 0012 | pending | 2026-06-20 | 2026-06-20 | high | medium |
|
manual | 0 |
|
|
Goal
Un meta-orquestador que permita a una persona manejar una flota de 20-30 agentes Claude hablando solo con uno. El orquestador no entra nunca en los detalles de cada agente: vigila estados, persigue que cada agente termine lo que empieza (cumpla un DoD-contrato fijo), y solo escala a la persona lo que requiere su decisión. La métrica de salud es el throughput de DoD cumplidos, no el número de agentes vivos.
Problema que resuelve
Hoy lanzar muchos Claudes produce saturación: N ventanas dispersas, N agentes que quedan idle sin cerrar nada, y la persona como cuello de botella revisando todo. El criterio de "terminado" tampoco existe de forma estable: el campo dod del goal.json lo reescribe el hook GOAL-TRACKER con cada prompt (es un resumen móvil), así que no hay un blanco fijo contra el que evaluar la terminación. Resultado: 30 agentes vivos que no resuelven nada.
Arquitectura: 4 roles
El orquestador delega, nunca ejecuta (regla orquestador-delega-no-ejecuta). Reparto:
orquestador (la persona habla SOLO con el; solo vigila, agrupa y escala)
├── splitter agente EFIMERO. Tarea grande -> la parte en sub-tareas
│ atomicas (paralelas o secuenciales), cada una con su
│ dod_contract pequeno y verificable. Tope de fan-out.
├── ejecutores Claudes INTERACTIVOS en la flota tmux (los 20-30 que la
│ persona ve). Cada uno con UNA tarea y UN dod_contract.
└── verificador agente EFIMERO e INDEPENDIENTE del ejecutor. Al cierre:
compara lo hecho contra el dod_contract -> met | failed
con evidencia citada. Cero auto-aprobacion.
Distinción dura: splitter y verificador son agentes efímeros (subagentes vía Agent tool / SDK: corren, devuelven un resultado estructurado y mueren). NO ocupan slot en la flota visible. La flota que la persona maneja = solo ejecutores con tarea. La maquinaria de verificación y descomposición es invisible para ella.
El reparto de coste: el watcher vigila (barato, sin LLM, siempre activo); el orquestador y los agentes efímeros piensan (caro, solo cuando hay algo que decidir).
Modelo de datos: DoD-contrato fijo
En el goal.json de cada agente conviven dos campos distintos:
dod(ya existe) — resumen móvil que el hook GOAL-TRACKER reescribe con cada prompt. Se queda como está.dod_contract(NUEVO, FIJO) — criterio de aceptación con evidencia ejecutable, escrito UNA vez al lanzar el agente y nunca reescrito por hooks. Es el blanco estable contra el que se evalúa "terminado".dod_status(NUEVO) —pending | met | failed, lo actualiza el verificador.
El hook GOAL-TRACKER debe respetar dod_contract/dod_status (solo reescribe dod). Spawn sin dod_contract se rechaza: ningún agente arranca sin saber cuándo habrá terminado.
Máquina de terminación (lo que el watcher clasifica, mecánico, sin LLM)
| Estado del agente | Clasificación | Acción |
|---|---|---|
waiting / phase preguntando/bloqueado |
RECLAMA | escalar a la persona (push inmediato) |
idle + phase hecho |
DICE-TERMINADO | orquestador lanza verificador contra dod_contract |
idle + phase≠hecho + sin actividad N min |
ESTANCADO | nudge automático: "cierra tu DoD" |
busy + phase haciendo/testeando |
TRABAJANDO | no molestar |
sin dod_contract |
MAL LANZADO | bloquear / re-lanzar con DoD |
"Dar por terminado al hablar con ellos": cuando la persona se enruta a un ejecutor, lo primero es cerrar su dod_contract — si el verificador dice met, se cierra/reasigna; si quedó a medias, se empuja a terminar antes de abrir nada nuevo.
Fases de construcción
Fase 1 — fleet_watcher (cerebro barato, sin LLM)
Service liviano (Go o bash) que corre como step de dag_engine o systemd-user. Cada N segundos:
- Snapshot del fleet (
fleetview list --json, extendido condod_contract/dod_status/phase). - Diff contra el snapshot anterior -> transiciones (edge-triggered, no nivel).
- Clasifica cada transición según la máquina de terminación.
- Escribe un evento por transición en
apps/fleet_watcher/operations.db(tablafleet_events). - Push inmediato (PushNotification) para clasificación RECLAMA.
DoD Fase 1:
- Golden: un agente pasa busy->idle -> aparece 1 evento
DICE-TERMINADOoESTANCADOenfleet_events. - Edge 1: el mismo agente sigue idle 10 ticks -> NO se duplica el evento (edge, no nivel).
- Edge 2: un agente pasa a waiting -> evento RECLAMA + push en < 1 min.
- Error 1: goal.json corrupto/ausente -> el agente se clasifica MAL LANZADO sin crash del watcher.
- Vida: 7 días corriendo, 0 crashes (
journalctl/log), cola sin huecos.
Fase 2 — orquestador-Claude reactivo + verificador + splitter
Extiende el skill /orquestador. NO hace polling. Despierta por: la persona | heartbeat largo (ScheduleWakeup 20-30 min) | push del watcher. Al despertar:
- Vacía
fleet_events, agrupa por prioridad (RECLAMA > DICE-TERMINADO > ESTANCADO) y por ámbito. - Para DICE-TERMINADO: lanza un verificador (Agent efímero) que compara el output del ejecutor con su
dod_contract-> met/failed+evidencia. met -> autocierra y reporta; failed -> nudge al ejecutor con el gap o escala. - Para ESTANCADO: nudge (send-keys) bajo política (solo idle con DoD pendiente; jamás waiting).
- Para RECLAMA: presenta a la persona UN resumen corto con la decisión concreta que se necesita. Usa
/fleet focuspara saltarla al agente elegido.
DoD Fase 2:
- Golden: un agente DICE-TERMINADO con DoD realmente cumplido -> verificador met -> autocierre + reporte, sin intervención humana.
- Edge 1: agente DICE-TERMINADO con DoD a medias -> verificador failed -> nudge con el gap, no se cierra.
- Edge 2: 10 agentes con eventos a la vez -> un solo resumen agrupado, no 10 mensajes.
- Error 1: verificador no puede leer el output -> reporta "no evaluable", escala, no autocierra en falso.
- Vida: 7 días gestionando flota real; la persona responde solo decisiones, no enrutamiento.
Fase 3 — spawn dentro de la flota + splitter
Extiende /orquestador para lanzar ejecutores con TmuxNewClaudeWindow (socket fleet) en vez de kitties sueltas, escribiendo dod_contract en el goal.json del nuevo agente y un prompt con el DoD claro. Antes de spawnar, si la tarea se estima grande, pasa por el splitter (Agent efímero) que devuelve un plan de sub-tareas con dependencias; el orquestador spawna un ejecutor por sub-tarea (paralelas a la vez, secuenciales encadenadas).
DoD Fase 3:
- Golden: una tarea atómica -> 1 ejecutor en la flota con
dod_contractescrito;/fleetlo lista. - Edge 1: una tarea grande -> splitter devuelve >=2 sub-tareas, cada una con su
dod_contract; se spawnan respetando deps. - Edge 2: tope de fan-out -> el splitter nunca genera más de K sub-agentes de golpe (sin explosión).
- Error 1: spawn sin
dod_contract-> rechazado con mensaje claro. - Vida: 7 días lanzando trabajo real por esta vía.
Pre-requisitos
- Sesión tmux fleet activa (perfil
launch_fleetclaude);/fleetoperativo (flow previo). - PushNotification configurado (Remote Control activo en el móvil).
- dag_engine activo para schedule del watcher (regla
dag-engine-over-cron).
Acceptance
dod_contractfijo escrito al spawn y respetado por el hook GOAL-TRACKER.- watcher edge-triggered con eventos en
fleet_events+ push en RECLAMA. - verificador independiente del ejecutor, con veredicto+evidencia.
- splitter con tope de fan-out para tareas grandes.
- orquestador presenta resumen agrupado, no N mensajes; usa
/fleet focus. - la persona maneja >=10 agentes respondiendo solo decisiones.
Definition of Done
- Mecánica: watcher + funciones del registry compilan,
fn doctorverde, sin driftuses_functions. - Cobertura: cada fase con su golden + >=2 edge + >=1 error path, evidencia ejecutable (ver DoD por fase).
- Vida útil: >=7 días de uso real gestionando flota, 0 crashes del watcher, 0 "done" falsos detectados (verificador funciona).
- Carga humana: medible reducción — la persona responde decisiones, no enrutamiento ni vigilancia.
- Secrets: cero credenciales fuera de pass/vaults; el watcher no loguea contenido de sesiones, solo estados/transiciones.
Notas (onboarding)
Para usarlo: lanzas trabajo por el orquestador (no abres Claudes a mano). Cada tarea recibe un dod_contract. El watcher vigila en background y empuja al móvil cuando un agente te reclama. Cuando vuelves, el orquestador te da un resumen agrupado y te lleva (/fleet focus) solo a lo que necesita tu decisión; lo demás (verificar cierres, empujar estancados, dividir tareas grandes) lo hace solo con agentes efímeros. La flota que ves = ejecutores con tarea; la maquinaria de verificación/división es invisible.
Relación con otras reglas: dod_quality (las 3 capas + verificador independiente), orquestador-delega-no-ejecuta (el orquestador no ejecuta), dag-engine-over-cron (schedule del watcher), autonomous_loop (fn-orquestador autónomo es el primo no-interactivo de este flujo), y el flow previo de /fleet/fleetview (la base de datos de estado).