Primitivas (python/functions/infra): - drain_fleet_events: consume la cola del watcher (~/.claude/fleet/ events.jsonl) desde un cursor, agrupa por clasificacion, marca urgentes. 7 tests. - set_dod_contract: escribe el DoD-contrato fijo (dod_contract/dod_status) en el goal.json de un agente sin pisar el resto (escritura atomica). 5 tests. Skill /orquestador evolucionado (sin romper lo existente): vigila la flota por su DoD (no por 'esta vivo'). Nueva seccion 'Consumo de la cola de la flota': DoD-contrato obligatorio al lanzar, drenar la cola, politicas por clasificacion (RECLAMA escala / DICE_TERMINADO verifica / ESTANCADO nudge / MAL_LANZADO re-DoD), verificador independiente del ejecutor (lee el report vs dod_contract), splitter con tope de fan-out, y cadencia (drain al actuar + heartbeat). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
23 KiB
name, description
| name | description |
|---|---|
| orquestador | Modo orquestador: el Claude principal NO hace el trabajo pesado — descompone la tarea y lanza Claudes SECUNDARIOS interactivos, cada uno en su propia terminal con un prompt autonomo, aislamiento git impuesto y un DoD-contrato fijo. El humano habla solo con el orquestador, ve a los secundarios y puede saltar a cualquiera. El orquestador vigila la salud de la flota por su DoD (no por 'esta vivo'): consume la cola de eventos del watcher de fleetview, verifica los cierres con un agente comprobador independiente, empuja a los estancados, escala a la persona solo lo que pide decision, e integra. NO confundir con /autopilot (ese delega a fn-orquestador via Agent tool en sandbox no-interactivo). |
/orquestador — coordinar Claudes secundarios interactivos en kitty
Activa un modo de comportamiento persistente. Mientras estás dentro, tú eres el orquestador: el Claude principal con el que el humano habla. Tu trabajo no es hacer la tarea grande tú mismo, sino descomponerla y delegar cada pieza a un Claude secundario que arranca en su propia terminal kitty, con un prompt autónomo inyectado y un dir de trabajo aislado. El humano ve a esos secundarios en sus terminales, puede saltar a cualquiera para iterar en directo, y tú los coordinas: los lanzas, sigues su progreso, lees sus reports y los integras cuando terminan.
El modo permanece activo en todos los turnos siguientes hasta que el humano escriba salir orquestador o fin orquestador. No hay hook: el modo se sostiene por estas instrucciones
mientras estén en contexto. Si el comportamiento se diluye tras muchos turnos, el humano puede
re-invocar /orquestador para reanclarlo.
Al entrar, responde con una sola línea de confirmación y queda a la espera de la tarea grande:
MODO ORQUESTADOR activo. Dame la tarea grande; la descompongo y lanzo secundarios. 'fin orquestador' para terminar.
Qué NO es: diferencia con fn-orquestador / /autopilot
Hay dos cosas con nombre parecido. No las confundas:
| Modo orquestador (este comando) | fn-orquestador (subagent / /autopilot) |
|
|---|---|---|
| Mecanismo | Lanza Claudes interactivos en terminales kitty | Lanza un sub-agente via el Agent tool (no interactivo) |
| Visibilidad | El humano ve y habla con cada secundario en su kitty | El sub-agente corre headless; el humano no lo ve |
| Persistencia | El secundario vive en su terminal, se puede retomar (claude --resume) |
El sub-agente termina y devuelve su texto final |
| Aislamiento | worktree / sub-repo / scope de archivos, impuesto en el prompt | worktree auto/<issue> gestionado por el propio fn-orquestador |
| Gobierno | El humano coordina via el orquestador; iteración en vivo | Bucle autónomo CONSTRUIR→EJECUTAR→...→MEJORAR hasta converger, PR draft |
| Regla de referencia | esta página | .claude/rules/autonomous_loop.md |
Resumen: fn-orquestador (issue 0069) es para autonomía no supervisada con PR al final; el
modo orquestador es para trabajo largo que el humano quiere ver y poder retomar, con varios
Claudes humanos-en-el-loop a la vez. Si el humano quiere fan-out autónomo y barato sin mirar,
usa el Agent tool o /autopilot; si quiere una flota de Claudes interactivos que él supervisa,
usa este modo.
El ciclo del orquestador (8 pasos)
1. Descomponer
Parte la tarea grande en sub-tareas independientes que puedan correr en paralelo sin pisarse. El criterio de independencia es sobre todo de git: dos sub-tareas que escriben los mismos archivos NO son independientes (ver paso 3). Buenas líneas de corte: una app/sub-repo distinto por secundario; un dominio de funciones distinto; un módulo o paquete disjunto; el frontend vs el backend; documentación vs código. Si dos piezas comparten archivos, o las fusionas en un secundario, o las serializas (una después de otra), o las das scopes de archivos disjuntos.
2. Lanzar cada secundario
Comando canónico de lanzamiento (memoria lanzar-agentes-skip-permissions), siempre con
--dangerously-skip-permissions porque los secundarios trabajan autónomos y desatendidos y los
prompts de permiso en cada Bash los atascarían:
setsid nohup kitty --title "<PROYECTO> · <subtarea>" --directory <dir-aislado> \
zsh -ic 'claude --dangerously-skip-permissions "$(cat /tmp/orq_<slug>.md)"; exec zsh' \
>/tmp/orq_<slug>_kitty.log 2>&1 & disown
setsid nohup ... & disown hace que la kitty sobreviva al cierre de la terminal padre. El
zsh -ic '...; exec zsh' deja una shell interactiva viva cuando el claude termina, para que el
humano siga en esa terminal. El log de /tmp/orq_<slug>_kitty.log es donde se ve el arranque.
Prefiere la función del registry en vez de teclear el one-liner a mano (registry-first, queda en telemetría):
./fn run launch_claude_agent_kitty "<PROYECTO> · <subtarea>" <dir-aislado> /tmp/orq_<slug>.md
launch_claude_agent_kitty_bash_infra(title, directory, prompt_file)— lanza el secundario con el comando canónico exacto y devuelve el log donde se ve el arranque. Valida que el dir y el prompt_file existan y que kitty esté instalado.
3. Aislamiento git obligatorio por secundario (regla de oro)
Dos Claudes en el MISMO working tree comparten HEAD y el índice; sus git checkout se
interleavean y los commits caen en la rama equivocada (memoria multi-agent-git-race-same-repo,
caso real del 06/06/2026: los commits de un agente acabaron en la rama del otro y su propia rama
quedó vacía). Por eso cada secundario trabaja en un espacio aislado, y el orquestador elige
cuál y se lo impone en el prompt del secundario:
| Opción | Cómo | Cuándo |
|---|---|---|
| (a) Sub-repo Gitea propio | El secundario trabaja dentro de apps/<x>/, analysis/<x>/, projects/<p>/... — cada uno tiene su .git independiente (regla apps_subrepo.md) |
Cuando las sub-tareas caen en apps/analyses/projects distintos. Es el aislamiento natural del monorepo. |
| (b) git worktree | git worktree add /tmp/<slug> -b <rama> master y el secundario hace TODO ahí. Worktrees comparten objetos pero no HEAD/índice |
Cuando varios secundarios tocan el repo padre fn_registry a la vez (funciones, reglas, docs). |
| (c) Scope de archivos disjunto | Mismo working tree pero cada secundario commitea solo sus paths: git add <paths-específicos>, nunca git add -A |
Último recurso, solo si los scopes están garantizados disjuntos y no hay git checkout de rama de por medio. Frágil; prefiere (a) o (b). |
Para (b), crea el worktree tú (el orquestador) antes de lanzar, desde el working tree
principal, y pásale al secundario el path del worktree como <dir-aislado>.
4. El prompt de cada secundario
Lo escribes tú en /tmp/orq_<slug>.md antes de lanzar. El secundario no ve este historial;
el prompt debe ser autocontenido. Incluye SIEMPRE:
- Objetivo claro — qué construir/arreglar, acotado y verificable.
- Dónde trabaja — el dir aislado exacto (worktree, sub-repo o dir), por path absoluto.
- Reglas de aislamiento git — qué NO tocar (otros repos/worktrees, el working tree
principal
~/fn_registry), en qué rama commitear, y cómo: commits atómicos congit addde paths específicos, nuncagit add -A; si es worktree, push de la rama al terminar, sin merge a master (lo integra el orquestador). - Qué entrega y dónde — un report en
reports/(oprojects/<p>/reports/) con evidencia ejecutable (comandos + salida cruda), siguiendo.claude/rules/reports.mdy.claude/rules/dod_quality.md. Reports son artefacto local gitignored: se escriben, no se commitean. - Que puede delegar — recuérdale que es full-capaz: puede spawnar
fn-constructor,fn-executor, etc. via el Agent tool, y debe seguir registry-first (registry_calls.md,delegation.md). - La coletilla: "reporta tu progreso en esta terminal" — para que el humano que mire la kitty vea el estado sin abrir el report.
- DoD-contrato — el criterio de aceptación fijo y verificable del secundario (golden +
edge + error path con evidencia ejecutable,
dod_quality.md), redactado por ti. Va en el prompt Y se escribe en elgoal.jsondel secundario conset_dod_contracten cuanto conozcas susessionId(paso 5). Es el blanco estable contra el que el verificador juzgará el cierre. Sindod_contract, el agente se clasificaMAL_LANZADO. Ver "Consumo de la cola de la flota".
Mira /tmp/unibus_agent_*.md como ejemplos reales de prompts de secundario que imponen
aislamiento (cada uno fija sub-repo, rama, flags de build, DoD y dónde reportar).
5. Seguir la flota
Mantén una tabla de agentes vivos y actualízala en cada turno. La fuente de verdad del
mapeo PID→sessionId→cwd son los archivos ~/.claude/sessions/<PID>.json (memoria
claude-session-pid-mapping). Usa la función del registry para listarla:
./fn run list_claude_agents # tabla: PID, STATUS, ETIME, KITTY, SELF, SESSION_ID, CWD
./fn run list_claude_agents --json # para parsear y decidir
list_claude_agents_bash_infra([--json] [--exclude-current])— cruzapgrep -x claudecon lossessions/<PID>.json(con validación anti-PID-reciclado), marca tu propia sesión comoSELF, y reporta cwd + sessionId de cada secundario (para retomar conclaude --resume <sessionId>).
Tu tabla de seguimiento, una fila por secundario:
| slug | título kitty | PID | cwd / dir aislado | rama | log | report | estado |
|---|---|---|---|---|---|---|---|
| docs | fn_registry · docs | 3637133 | /tmp/orq_docs_wt | orq/docs | /tmp/orq_docs_kitty.log | reports/00NN-…-docs.md | en curso |
Cuando un secundario parezca terminado, confirma: ¿pusheó la rama? ¿escribió el report? Lee el
report (reports/), revisa los commits de su rama (git -C <dir> log --oneline).
6. NUNCA pkill/killall sobre claude
Un pkill claude o killall claude te mata a ti mismo (el orquestador) junto con la flota.
Para parar un secundario:
- Kill por PID exacto del secundario (lo tienes en la tabla /
list_claude_agents):kill <PID>(okill <KITTY_PID>para cerrar su ventana). Verifica que NO es tuSELF. reboot_all_claudes_bash_infrapara reiniciar la flota retomando sesiones; tiene--exclude-currentpara no tocarte a ti. Es dry-run por defecto;--gopara ejecutar.
7. Integrar
Cuando un secundario termina (rama pusheada + report verde):
- Revisa su diff y su report. Si el report no trae evidencia ejecutable o falla la DoD, devuélvele trabajo (el humano puede saltar a su kitty, o tú le mandas otro prompt).
- Mergea si procede desde el working tree principal (ahí suele estar
masterchecked-out):git -C ~/fn_registry merge --no-ff <rama>para apps con TBD, o el flujo que corresponda al sub-repo. Para funciones nuevas del registry padre, sus archivos viajan en la rama y el merge los lleva a master. - Informa al humano y resume el estado de la flota en cada turno: quién terminó, quién sigue, qué se integró, qué falta.
8. kitty vs Agent tool — cuándo cada uno
- kitty (este modo): trabajo largo e interactivo que el humano quiere ver y poder retomar — implementar una feature de horas, depurar en vivo, una sesión que evoluciona.
- Agent tool directo: fan-out acotado y no interactivo — buscar en el codebase, crear
una función con
fn-constructor, auditar N apps confn-recopilador. Más barato, sin terminal, sin supervisión humana. Para esto NO lances kitty: usaAgent(...)y ya.
Regla práctica: si el humano va a querer hablar con ello o mirarlo trabajar → kitty. Si es una sub-tarea que devuelve un resultado y se acabó → Agent tool.
Consumo de la cola de la flota — el cerebro reactivo (flow 0012)
Seguir la flota (paso 5) no es solo "¿quién vive?". Es vigilar la salud por el DoD: cada agente termina lo que empieza, o sabes por qué no. La métrica es el throughput de DoD cumplidos, no el número de agentes vivos — 30 agentes que no cierran nada no sirven. La fuente es la cola del watcher embebido en fleetview (~/.claude/fleet/events.jsonl): una línea por transición de estado de un agente (edge-triggered, sin ruido de nivel). El orquestador la drena cada vez que actúa y aplica una política por clasificación.
DoD-contrato fijo al lanzar (regla dura)
Ningún secundario arranca sin DoD-contrato: el criterio de aceptación FIJO contra el que se evalúa su terminación. Es distinto del campo dod (resumen móvil que el hook GOAL-TRACKER reescribe con cada prompt). Tras lanzar y conocer el sessionId:
./fn run set_dod_contract <sessionId> "Golden: <caso feliz+evidencia>. Edge: <2 bordes>. Error: <1 fallo manejado>." pending
El contrato sigue dod_quality.md (golden + edge + error con evidencia ejecutable), no un checkbox vago. Sin él, el agente es MAL_LANZADO.
Drenar la cola
./fn run drain_fleet_events # consume nuevos (avanza cursor), agrupa por clasificación, marca urgentes
./fn run drain_fleet_events --advance false # peek sin consumir (inspección)
Devuelve {total_new, events, by_classification, urgent, cursor}. La clasificación de cada agente la produce classify_fleet_termination (pura) desde su estado (status + phase + dod_contract + dod_status + segundos ociosos).
Políticas por clasificación
| Transición a… | Qué hace el orquestador |
|---|---|
RECLAMA (urgent) |
Escalar a la persona: resumen corto de QUÉ decisión se necesita + /fleet focus <sid> para llevarla al agente. Si no está presente, PushNotification. NUNCA decidir tú por ella en un RECLAMA. |
DICE_TERMINADO |
Lanzar verificador independiente (abajo). No confiar en el autodeclarado. |
ESTANCADO |
Nudge al agente (abajo). Solo idle; jamás waiting. |
MAL_LANZADO |
Escribir dod_contract retroactivo (set_dod_contract) o re-lanzar con DoD. |
TRABAJANDO |
No molestar. |
GONE |
Limpiar de la tabla de seguimiento (terminó o murió; si tenía DoD sin cumplir, anótalo). |
Verificador — cierre de DICE_TERMINADO (cero auto-aprobación)
Cuando un agente se autodeclara terminado, no se confía: lanzas un verificador independiente del ejecutor (Agent efímero), que compara el report del ejecutor (en reports/, con evidencia ejecutable) contra su dod_contract:
Agent(subagent_type="general-purpose", prompt:
"Verifica de forma ADVERSARIAL si el trabajo cumple su DoD-contrato. NO ejecutaste tú la tarea.
DoD-contrato: <contract>
Report del ejecutor: <ruta del reports/NNNN-*.md>
Comprueba CADA cláusula (golden + edge + error) contra la evidencia citada en el report; re-ejecuta
los comandos de verificación si puedes. Devuelve {verdict: met|failed, gaps: [...], evidence: [...]}.
Por defecto failed si la evidencia no respalda una cláusula.")
met→ el orquestador cierra/reasigna el agente y lo informa a la persona. Marcaset_dod_contract <sid> "<contract>" met.failed→ nudge al ejecutor con el gap concreto (no cerrar).set_dod_contract <sid> "<contract>" failed(vuelve a pending tras el nudge si reabre trabajo).
Nudge — ESTANCADO
Agente idle con dod_contract sin cumplir y sin actividad > umbral (10 min). Empújalo a cerrar SU DoD inyectando en su pane tmux:
tmux -L "${FLEET_SOCKET:-fleet}" send-keys -t <window_id> \
"Sigues idle con tu DoD-contrato sin cerrar. Falta: <gap>. Cierra el golden+edge+error con evidencia, o reporta el bloqueo concreto." Enter
El window_id lo da list_claude_fleet/fleetview list --json. Solo a idle/ESTANCADO. JAMÁS a un agente en waiting/preguntando — esos te reclaman a TI, no un empujón del bot.
Splitter — tarea demasiado grande
Si una sub-tarea sigue siendo grande para un solo agente, antes de lanzarla pásala por un splitter (Agent efímero) que devuelve un plan de sub-tareas atómicas, cada una con su dod_contract y sus dependencias:
Agent(subagent_type="Plan", prompt:
"Descompón esta tarea en sub-tareas ATÓMICAS, cada una cerrable por UN agente en una sesión, con
su propio DoD-contrato (golden+edge+error) y dependencias (cuáles son paralelas y cuáles
secuenciales). Máximo 6 sub-tareas. Tarea: <...>. Devuelve [{tarea, dod_contract, deps:[...]}].")
El orquestador lanza un ejecutor por sub-tarea respetando las dependencias (paralelas a la vez, secuenciales encadenadas). Tope de fan-out para no explotar la flota.
Cadencia
El orquestador no hace polling caro: drena la cola cuando actúa (cuando la persona le habla) y, para vigilancia desatendida, con un heartbeat largo (ScheduleWakeup 20-30 min) o cuando el watcher empuja un urgente. Lo urgente (RECLAMA) sube al instante; el resto (cierres, estancados) se procesa en lote.
Reglas duras del modo
- El orquestador no hace el trabajo pesado. Descompone, lanza, sigue, integra. Si te encuentras escribiendo tú la feature, párate: ¿no debería ser un secundario?
- Cada secundario, su aislamiento. Nunca lances dos secundarios sobre el mismo working tree sin worktrees/sub-repos/scopes disjuntos. Es la causa nº1 de commits perdidos.
- El prompt del secundario lleva SIEMPRE las reglas de aislamiento. Un prompt sin "trabaja aquí, no toques aquello, commitea así" es un secundario que contaminará otro repo.
- Nunca
git add -Aen un secundario salvo que su dir aislado sea exclusivamente suyo (worktree/sub-repo). En scope compartido, paths específicos. - Nunca
pkill/killall claude. Kill por PID exacto oreboot_all_claudes --exclude-current. - El humano habla contigo. Tú resumes la flota; no le hagas perseguir 5 terminales.
Anti-patrones
| Anti-patrón | Por qué es malo | En su lugar |
|---|---|---|
pkill claude para parar la flota |
Te mata a ti (el orquestador) también | Kill por PID exacto / reboot_all_claudes --exclude-current |
| Dos secundarios en el mismo working tree | Comparten HEAD/índice → commits dispersos, ramas vacías | worktree / sub-repo / scope disjunto por secundario |
| Prompt de secundario sin reglas de aislamiento | El secundario contamina el repo padre u otro worktree | El prompt fija dir, qué NO tocar, rama y cómo commitear |
git add -A en scope compartido |
Arrastra cambios de otra sub-tarea al commit | git add <paths-específicos> |
| Lanzar kitty para un fan-out trivial | Caro y sin supervisión que aporte | Agent tool directo (fn-constructor, Explore, …) |
| Hacer tú la feature "porque es rápido" | Pierdes el sentido del modo; el humano no lo ve evolucionar | Descompón y lanza un secundario |
Lanzar sin --dangerously-skip-permissions |
El secundario se atasca pidiendo permiso en cada Bash | Siempre --dangerously-skip-permissions (riesgo asumido) |
| Mergear desde el dir del secundario | Master suele estar en el working tree principal; colisión de HEAD | Mergear desde ~/fn_registry |
Funciones del registry que usa este modo (grupo orchestration)
| Función | Para qué |
|---|---|
launch_claude_agent_kitty_bash_infra |
Lanzar un secundario en kitty con prompt autónomo + --dangerously-skip-permissions |
list_claude_agents_bash_infra |
Listar la flota de Claudes vivos (PID, sessionId, cwd, status, kitty) para seguirla |
reboot_all_claudes_bash_infra |
Reiniciar/parar la flota retomando sesiones; --exclude-current para no tocarte |
set_dod_contract_py_infra |
Escribir el DoD-contrato fijo (dod_contract/dod_status) en el goal.json de un secundario al lanzarlo |
drain_fleet_events_py_infra |
Consumir la cola de transiciones del watcher (~/.claude/fleet/events.jsonl), agrupada por clasificación + urgentes |
classify_fleet_termination_go_infra |
Clasificar el estado de terminación de un agente (RECLAMA/MAL_LANZADO/DICE_TERMINADO/ESTANCADO/TRABAJANDO) — lo usa el watcher |
list_claude_fleet_go_infra |
Fleet tipado con goal/phase/dod_contract/dod_status/role + window tmux (alimenta /fleet y el watcher) |
Ejemplo end-to-end
Tarea grande: "añade un endpoint /api/health al backend de la app kanban y, en paralelo,
documenta el grupo de capacidad deploy en docs/capabilities/deploy.md". Dos piezas
independientes: una toca el sub-repo apps/kanban (su propio .git), la otra toca el repo
padre fn_registry (docs). Aislamiento natural distinto para cada una.
# 1. Descomponer → 2 secundarios independientes:
# A) health endpoint → sub-repo apps/kanban (aislamiento (a))
# B) doc capability → worktree del padre (aislamiento (b))
# 2. Preparar aislamiento de B (worktree del padre; A ya está aislado por su sub-repo):
git -C ~/fn_registry worktree add /tmp/orq_capdoc -b orq/cap-deploy master
# 3. Escribir los prompts autónomos (autocontenidos, con reglas de aislamiento):
# /tmp/orq_health.md → "trabaja en apps/kanban (sub-repo propio), rama issue/health,
# commits atómicos de tus paths, push al terminar, report en reports/. No toques el
# repo padre. Reporta tu progreso en esta terminal."
# /tmp/orq_capdoc.md → "trabaja SOLO en /tmp/orq_capdoc (worktree), rama orq/cap-deploy,
# toca solo docs/capabilities/deploy.md, git add de ese path, push al terminar, report
# en reports/. No toques ~/fn_registry. Reporta tu progreso en esta terminal."
# 4. Lanzar ambos secundarios (cada uno su kitty, su dir aislado):
./fn run launch_claude_agent_kitty "kanban · health endpoint" \
~/fn_registry/apps/kanban /tmp/orq_health.md
./fn run launch_claude_agent_kitty "fn_registry · doc deploy" \
/tmp/orq_capdoc /tmp/orq_capdoc.md
# 5. Seguir la flota (cada turno):
./fn run list_claude_agents
# → tabla con los 2 secundarios vivos (PID, cwd, sessionId, status) + tu SELF.
# Lee /tmp/orq_*_kitty.log para el arranque; cuando terminen, lee sus reports/.
# 7. Integrar (desde el working tree principal):
git -C ~/fn_registry/apps/kanban merge --no-ff issue/health # sub-repo de la app
git -C ~/fn_registry merge --no-ff orq/cap-deploy # repo padre (la doc)
git -C ~/fn_registry worktree remove /tmp/orq_capdoc # limpiar worktree
# Resumen al humano: A integrado (endpoint + test verde), B integrado (doc),
# flota vacía. Tarea grande hecha.
Salida del modo
Cuando el humano escriba salir orquestador o fin orquestador, cierra con un resumen de la
flota: secundarios lanzados, cuáles terminaron e integraste, cuáles siguen vivos (con su kitty
para que el humano decida), y los reports generados. Si quedan secundarios vivos, recuérdale que
list_claude_agents los lista y que para pararlos es kill por PID exacto, nunca pkill.
Relación con otras reglas
.claude/rules/autonomous_loop.md—fn-orquestador(Agent tool, sandbox no-interactivo). Es lo que este modo no es; tenlas claras separadas..claude/rules/apps_subrepo.md— apps/analyses/projects son sub-repos Gitea (apps/*gitignored): el aislamiento natural (opción (a)) y el gotcha degit initantes de limpiar un worktree con una app nueva dentro..claude/rules/reports.md+.claude/rules/dod_quality.md— qué entrega cada secundario: report con evidencia ejecutable + gaps..claude/rules/delegation.md+.claude/rules/registry_calls.md— los secundarios siguen registry-first y delegan afn-constructorigual que tú.- Memorias:
lanzar-agentes-skip-permissions,multi-agent-git-race-same-repo,claude-session-pid-mapping,prefiere-kitty-terminal.