Files
fn_registry/.claude/commands/orquestador.md
T
agent 9365def3dd feat: cerebro reactivo del meta-orquestador (flow 0012, fase 2)
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>
2026-06-20 20:19:26 +02:00

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 (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:

  1. Objetivo claro — qué construir/arreglar, acotado y verificable.
  2. Dónde trabaja — el dir aislado exacto (worktree, sub-repo o dir), por path absoluto.
  3. 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 con git add de paths específicos, nunca git add -A; si es worktree, push de la rama al terminar, sin merge a master (lo integra el orquestador).
  4. Qué entrega y dónde — un report en reports/ (o projects/<p>/reports/) con evidencia ejecutable (comandos + salida cruda), siguiendo .claude/rules/reports.md y .claude/rules/dod_quality.md. Reports son artefacto local gitignored: se escriben, no se commitean.
  5. 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).
  6. La coletilla: "reporta tu progreso en esta terminal" — para que el humano que mire la kitty vea el estado sin abrir el report.
  7. 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 el goal.json del secundario con set_dod_contract en cuanto conozcas su sessionId (paso 5). Es el blanco estable contra el que el verificador juzgará el cierre. Sin dod_contract, el agente se clasifica MAL_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]) — cruza pgrep -x claude con los sessions/<PID>.json (con validación anti-PID-reciclado), marca tu propia sesión como SELF, y reporta cwd + sessionId de cada secundario (para retomar con claude --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> (o kill <KITTY_PID> para cerrar su ventana). Verifica que NO es tu SELF.
  • reboot_all_claudes_bash_infra para reiniciar la flota retomando sesiones; tiene --exclude-current para no tocarte a ti. Es dry-run por defecto; --go para ejecutar.

7. Integrar

Cuando un secundario termina (rama pusheada + report verde):

  1. 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).
  2. Mergea si procede desde el working tree principal (ahí suele estar master checked-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.
  3. 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 con fn-recopilador. Más barato, sin terminal, sin supervisión humana. Para esto NO lances kitty: usa Agent(...) 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. Marca set_dod_contract <sid> "<contract>" met.
  • failednudge 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 -A en 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 o reboot_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.mdfn-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 de git init antes 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 a fn-constructor igual que tú.
  • Memorias: lanzar-agentes-skip-permissions, multi-agent-git-race-same-repo, claude-session-pid-mapping, prefiere-kitty-terminal.