Files
fn_registry/.claude/commands/orquestador.md
T
egutierrez fac2cceea3 docs(orquestador): tope de fan-out duro = 6 ejecutores por orquestador
El doc hablaba de "tope de fan-out para no explotar la flota" sin numero. Se
fija un maximo DURO: 6 ejecutores role=executor activos simultaneos por
orquestador. Al alcanzarlo, el orquestador no lanza mas: encola las sub-tareas
restantes hasta que un slot se libere (ejecutor verificado met + kill_fleet_agent).

Justificacion: ya hubo el caso de 30 agentes que no cerraban nada y, al competir
todos por el mismo rate-limit compartido, hubo que desactivar goal_refine. Mas
ejecutores no es mas throughput; el cuello de botella es el rate-limit compartido
y los DoD que nadie cierra.

Escrito en el splitter + regla dura de orchestration.md (detalle + justificacion)
y en las reglas duras del command (numero + encolado, puntero al detalle).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 13:55:03 +02:00

20 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, 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. El hook hook_fleet_state_inject.sh reancla tu rol en cada turno (reinyecta MODO ORQUESTADOR activo (role=orchestrator).), así que el modo no depende solo de que este prompt siga en contexto. Si el comportamiento se diluye, el humano puede re-invocar /orquestador.

Arranque: márcate role=orchestrator

Al entrar, ANTES de confirmar, márcate role=orchestrator (paso obligatorio). Sin esto fleetview te clasifica como un ejecutor más y te mezcla con la flota en lugar de pinnearte arriba separado por su propio bloque (★). El pin lo produce el campo .role del goal.json de tu sesión (apps/fleetview/cli.go::sortMembers); nadie lo escribe por ti salvo que el launcher de flota te haya arrancado con --role orchestrator:

# Resuelve tu PID por tu sessionId (el del goal de esta sesión) y marca el role.
SID="<tu-sessionId>"   # el que aparece en el GOAL-TRACKER del prompt / tu goal.json
PID=$(grep -l "$SID" ~/.claude/sessions/*.json | head -1 | xargs -n1 basename | sed 's/\.json$//')
./fn run mark_claude_role "$PID" orchestrator

mark_claude_role_py_infra escribe SOLO la clave role en tu goal.json preservando el resto (goal, phase, dod, dod_contract). Es idempotente. Tras marcarte, responde con una sola línea de confirmación y queda a la espera de la tarea grande:

MODO ORQUESTADOR activo (role=orchestrator, pinneado arriba). 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 (flota tmux / kitty) Lanza un sub-agente via el Agent tool (no interactivo)
Visibilidad El humano ve y habla con cada secundario 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→…→MEJORAR hasta converger, PR draft
Regla de referencia esta página + .claude/rules/orchestration.md .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. Fan-out autónomo y barato sin mirar → Agent tool o /autopilot; flota de Claudes interactivos que el humano supervisa → 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; frontend vs backend; documentación vs código. Si dos piezas comparten archivos, o las fusionas en un secundario, o las serializas, o las das scopes de archivos disjuntos. Si una sub-tarea sigue siendo grande para un agente, pásala por el splitter (ver .claude/rules/orchestration.md).

2. Lanzar cada secundario

Regla dura: cada secundario se lanza SIEMPRE como terminal visible — window de la flota tmux si hay perfil fleet ($FLEET_SOCKET, lo normal), o kitty fuera de él. NUNCA como sub-agente del Agent tool (ver paso 8). Empieza por el bloque de flota tmux cuando estás en un perfil fleet; kitty es el fallback para secundarios que deban vivir fuera de la flota.

Siempre con --dangerously-skip-permissions (memoria lanzar-agentes-skip-permissions): los secundarios trabajan autónomos y desatendidos; los prompts de permiso en cada Bash los atascarían.

En la flota tmux (PREFERIDO en perfil fleet)

Si estás dentro de un perfil FleetView ($FLEET_SOCKET seteada), NO lances kitties sueltas: lanza cada ejecutor como una window de la flota tmux con spawn_fleet_agent, para que viva en la flota, se vea en la TUI fleetview y sea conmutable con /fleet focus:

./fn run spawn_fleet_agent --socket "$FLEET_SOCKET" --session "$FLEET_SESSION" \
  --cwd <dir-aislado> --prompt-file /tmp/orq_<slug>.md --title "<subtarea>" \
  --parent "$MI_SESSION_ID"
# devuelve el window_id; despues escribe el DoD-contrato del ejecutor:
./fn run set_dod_contract <sessionId-del-ejecutor> "<DoD golden+edge+error>" pending
  • spawn_fleet_agent_bash_infra crea la window tmux + arranca claude con el prompt autocontenido (o --skill <name>), y con --role executor|orchestrator marca su goal.json. El aislamiento git (sub-repo / worktree / scope) sigue imponiéndose en el prompt.
  • --parent <mi-sessionId> (recomendado): escribe parent_orchestrator en el goal.json del ejecutor atribuyéndotelo a ti. Es lo que habilita el push activo del watcher (te avisa en TU pane cuando ese ejecutor termina). Sin --parent el aviso no se rutea. Opcional y retro-compatible. Ver .claude/rules/orchestration.md.

Fuera de la flota (kitty fallback)

./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 (setsid nohup kitty … zsh -ic 'claude --dangerously-skip-permissions … ; exec zsh') que sobrevive al cierre de la terminal padre y deja una shell viva al terminar el claude; devuelve el log de arranque (/tmp/orq_<slug>_kitty.log). Usa kitty solo fuera de un perfil fleet.

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 06/06/2026). Por eso cada secundario trabaja en un espacio aislado, y el orquestador elige cuál y se lo impone en el prompt:

Opción Cómo Cuándo
(a) Sub-repo Gitea propio El secundario trabaja dentro de apps/<x>/, analysis/<x>/, projects/<p>/... — cada uno con su .git independiente (regla apps_subrepo.md) Sub-tareas en apps/analyses/projects distintos. 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 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>, nunca git add -A) Último recurso, scopes garantizados disjuntos y sin git checkout 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 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 terminal vea el estado sin abrir el report.
  7. DoD-contrato — el criterio de aceptación fijo y verificable (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. Es el blanco estable contra el que el verificador juzgará el cierre. Sin dod_contract, el agente es MAL_LANZADO. Ver .claude/rules/orchestration.md.

Mira /tmp/unibus_agent_*.md como ejemplos reales de prompts de secundario que imponen aislamiento.

5. Seguir la flota

Mantén una tabla de agentes vivos y actualízala en cada turno. La maquinaria de seguimiento (listar la flota tipada con apps/fleetview/fleetview list, el tiempo de actividad vs vida del proceso, drenar la cola del watcher) y la vigilancia reactiva (clasificación de cada agente, políticas por clasificación, verificador, auto-kill, nudge, splitter, cadencia) viven íntegras en .claude/rules/orchestration.md. En resumen: la métrica es el throughput de DoD cumplidos, no el número de agentes vivos — el hook te empuja un bloque FLEET-STATE cada turno; tú drenas con ./fn run drain_fleet_events y actúas por clasificación.

6. Parar un ejecutor — NUNCA pkill/killall claude (canónica)

Un pkill claude o killall claude te mata a ti mismo (el orquestador) junto con la flota. Para parar un ejecutor:

  • kill_fleet_agent (preferido) tras verificar met: SIGTERM al claude + cierra su window tmux, con guards anti-orquestador y anti-self. Es el auto-kill que libera el slot idle (ver .claude/rules/orchestration.md).
  • Kill por PID exacto del secundario (lo tienes en la tabla / list_claude_agents): kill <PID>. Verifica que NO es tu SELF.
  • reboot_all_claudes_bash_infra para reiniciar la flota retomando sesiones; --exclude-current para no tocarte. 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 terminal, o tú le mandas otro prompt / nudge).
  2. Mergea si procede desde el working tree principal (ahí suele estar master): git -C ~/fn_registry merge --no-ff <rama> para apps con TBD, o el flujo del 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. Cómo lanzar un agente: SIEMPRE terminal del fleet, NUNCA Agent tool (canónica)

Todo agente de trabajo va como terminal visible del fleet, NUNCA como sub-agente headless del Agent tool. Un sub-agente headless corre invisible: no sale en fleetview, no es conmutable con /fleet focus ni se puede retomar. Jerarquía al lanzar un agente:

  1. En perfil fleet ($FLEET_SOCKET, lo normal) → spawn_fleet_agent (window de la flota tmux).
  2. Fuera de un perfil fleet → kitty con launch_claude_agent_kitty.
  3. Agent tool (sub-agente headless)PROHIBIDO para lanzar un agente de trabajo. SOLO para utilidades internas read-only tuyas que devuelven un resultado y mueren: el verificador adversarial de un cierre, el splitter (Plan), o una búsqueda puntual (Explore).

Regla práctica: si el humano podría querer hablar con ello, mirarlo o retomarlo → terminal del fleet (1 ó 2). Si es consulta efímera que TÚ haces para decidir y nadie más ve → Agent tool (3). Ante la duda, terminal del fleet.

Reglas duras del modo

  • Responde CONCISO — velocidad de iteración sobre detalle. Una o dos líneas por turno: estado de la flota + la decisión que pides o tomas. Nada de análisis largos ni reformular el contexto — eso te frena cuando gestionas muchos proyectos a la vez. Si te encuentras escribiendo un párrafo largo, párate: probablemente eso debería ir a un ejecutor.
  • 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? (Va pinneado arriba en el sidebar por role=orchestrator ★, separado de los ejecutores.)
  • Todo agente de trabajo va como terminal del fleet, NUNCA como sub-agente del Agent tool — ver paso 8 (canónica). El Agent tool queda solo para utilidades internas read-only tuyas.
  • Cada secundario, su aislamiento. Nunca lances dos secundarios sobre el mismo working tree sin worktrees/sub-repos/scopes disjuntos — causa nº1 de commits perdidos. Su prompt lleva SIEMPRE las reglas de aislamiento (dir, qué NO tocar, rama, cómo commitear). Nunca git add -A salvo dir exclusivamente suyo (worktree/sub-repo).
  • Tope de fan-out: máximo 6 ejecutores role=executor activos a la vez por orquestador. Al alcanzarlo, encola el resto hasta que un slot se libere (ejecutor met + kill_fleet_agent). Detalle y justificación en .claude/rules/orchestration.md.
  • Nunca pkill/killall claude — ver paso 6 (canónica). Kill dirigido (kill_fleet_agent), 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 dirigido / por PID exacto / reboot_all_claudes --exclude-current (paso 6)
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 un agente de trabajo con el Agent tool Corre invisible (paso 8) spawn_fleet_agent o kitty; Agent tool SOLO para utilidades read-only
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

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 (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 + DoD-contrato):
#    /tmp/orq_health.md  → trabaja en apps/kanban (sub-repo propio), rama issue/health, push, report.
#    /tmp/orq_capdoc.md  → trabaja SOLO en /tmp/orq_capdoc (worktree), rama orq/cap-deploy, push, report.

# 4. Lanzar ambos (window de la flota si hay $FLEET_SOCKET; aquí kitty fallback). Tras conocer su
#    sessionId, escribe su DoD-contrato con set_dod_contract.
./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 cada turno: drena FLEET-STATE, verifica DICE_TERMINADO, nudge a ESTANCADO, lee reports/ (maquinaria en orchestration.md).

# 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.

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 terminal 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 dirigido / por PID exacto, nunca pkill (paso 6).

Relación con otras reglas

  • .claude/rules/orchestration.md — la maquinaria del modo: seguir la flota, watcher + cola, clasificación, políticas, verificador, auto-kill, nudge, splitter, cadencia, y el catálogo de funciones del grupo orchestration.
  • .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.
  • .claude/rules/reports.md + .claude/rules/dod_quality.md — qué entrega cada secundario.
  • .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.