Files
fn_registry/.claude/commands/orquestador.md
T

31 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, 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), y nadie lo escribe por ti salvo que el launcher de flota te haya arrancado con --role orchestrator. Cuando entras a /orquestador en una sesión normal, eres tú quien debe marcarlo:

# 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: re-marcarlo no rompe nada. Si ya fuiste lanzado por el launcher de flota con --role orchestrator, este paso es un no-op seguro.

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

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 de abajo cuando estás en un perfil fleet; el bloque kitty es el fallback para secundarios que deban vivir fuera de la flota. Lanzar un agente de trabajo con el Agent tool lo deja invisible: el humano no lo ve en fleetview, no puede saltar a él con /fleet focus ni retomarlo — exactamente lo contrario de lo que este modo busca.

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.

En la flota tmux (PREFERIDO cuando operas en un perfil fleet)

Si estás dentro de un perfil FleetView (variable $FLEET_SOCKET seteada — eres el orquestador de una flota tmux montada con launch_fleetclaude), 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>"
# 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> para arrancar en un modo), y con --role executor|orchestrator marca su goal.json (via mark_claude_role). El aislamiento git (sub-repo / worktree / scope) sigue imponiéndose en el prompt igual que con kitty.
  • Usa kitty (arriba) solo para secundarios que deban vivir 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 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>).

Flota tipada (goal/phase/window/age) — usa el binario fleetview, NO fn run. La flota con goal, phase, status, tmux_window y age/idle_seconds la da el CLI de la app fleetview:

apps/fleetview/fleetview list --json   # flota tipada: session_id, goal, phase, status, tmux_window, age, idle_seconds
apps/fleetview/fleetview list          # tabla legible (incluye columna AGE)

Nota: NO uses ./fn run list_claude_fleetlist_claude_fleet_go_infra es una función Go con tests, así que fn run la despacha como go test (corre la suite, no imprime la flota). La vía ejecutable es el binario apps/fleetview/fleetview (el atajo /fleet del humano envuelve este mismo CLI). Gotcha: el JSON de fleetview list no incluye todavía role/dod_contract/dod_status; para esos campos lee el sidecar ~/.claude/goals/<session_id>.json (ver abajo).

Tiempo — usa el de ACTIVIDAD, no el del proceso. Para "cuánto lleva cada agente" usa la columna AGE de fleetview list (o age/idle_seconds en --json): es el tiempo desde su última actividad (proxy de cuánto lleva sin avanzar / en su estado), lo útil para detectar estancados. El etime de list_claude_agents es la vida del proceso (cuánto lleva la terminal abierta, p.ej. 8h) — NO es el tiempo de la tarea; nunca lo reportes como progreso.

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. Cómo lanzar un agente: SIEMPRE terminal del fleet (regla dura)

Todo agente que lances para que EJECUTE trabajo va como terminal visible, NUNCA como sub-agente headless del Agent tool. El humano quiere ver y poder saltar a cada agente en la flota; un sub-agente del Agent tool corre invisible, no aparece en fleetview, no es conmutable con /fleet focus y no se puede retomar. Jerarquía obligatoria al lanzar un agente:

  1. Estás en un perfil fleet ($FLEET_SOCKET seteada, lo normal) → spawn_fleet_agent (window de la flota tmux). Es el default duro: el agente vive en la flota, se ve y se conmuta. Ver paso 2.
  2. Fuera de un perfil fleet → kitty con launch_claude_agent_kitty (paso 2).
  3. Agent tool (sub-agente headless)PROHIBIDO para lanzar un agente de trabajo. Se permite SOLO para las utilidades internas read-only del propio orquestador que devuelven un resultado y mueren sin que el humano las gestione como agentes de la flota: el verificador adversarial de un cierre (DICE_TERMINADO), el splitter (Plan) de una tarea grande, o una búsqueda puntual en el codebase (Explore). Nunca para ejecutar una sub-tarea.

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

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

No te vigiles a ti mismo. Al procesar la cola, ignora los eventos de tu propia sesión y de cualquier agente con role=orchestrator. Como fleetview list --json no expone role, resuélvelo leyendo el sidecar del goal de cada session_id:

jq -r '.role // "executor"' ~/.claude/goals/<session_id>.json   # "orchestrator" => ignóralo

El orquestador no tiene dod_contract y aparecería como MAL_LANZADO — es ruido, no un ejecutor que vigilar. Solo actúas sobre los ejecutores (role=executor o sin role).

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 es el campo tmux_window (p.ej. @20) de apps/fleetview/fleetview list --json:

apps/fleetview/fleetview list --json | jq -r '.[] | select(.session_id|startswith("<sid>")) | .tmux_window'

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

  • 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, ni explicaciones extensas — eso te frena cuando gestionas muchos proyectos a la vez. El detalle y el trabajo viven en los ejecutores; tú despachas, vigilas y escalas. Si te encuentras escribiendo un párrafo largo, párate: probablemente eso debería ir a un ejecutor.
  • El orquestador va pinneado arriba en el sidebar. Gracias a role=orchestrator, fleetview lo fija arriba de la lista (★), separado de los ejecutores, para que el humano lo localice de un vistazo y no baile entre la flota que rota por estado.
  • 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?
  • Todo agente que lances va como terminal del fleet, NUNCA como sub-agente headless. Si hay $FLEET_SOCKET, spawn_fleet_agent (window de la flota); si no, kitty. El Agent tool queda solo para utilidades internas read-only tuyas (verificador, splitter, búsqueda con Explore), jamás para lanzar un agente de trabajo. Ver paso 8. Cuando el humano dice "lanza un agente", significa terminal visible en la flota.
  • 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 un agente de trabajo con el Agent tool (sub-agente headless) Corre invisible: no sale en fleetview, el humano no puede verlo, saltarle con /fleet focus ni retomarlo spawn_fleet_agent (window de la flota) o kitty fuera de fleet; Agent tool SOLO para utilidades internas read-only (verificador, splitter, 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/role + tmux_window (alimenta /fleet y el watcher). Invócala por el binario apps/fleetview/fleetview list --json, NUNCA por ./fn run (la despacha como go test). El JSON del CLI aún no expone role/dod_contract/dod_status; léelos de ~/.claude/goals/<session_id>.json
spawn_fleet_agent_bash_infra Lanzar un ejecutor (o el orquestador) como window de la flota tmux — preferido sobre kitty cuando hay perfil fleet
mark_claude_role_py_infra Marcar role (orchestrator/executor) en el goal.json de un Claude resolviendo PID→sessionId

Cómo invocarlas. Las Bash y Python del grupo se lanzan con ./fn run <id> [args] (verificado: list_claude_agents, drain_fleet_events, reboot_all_claudes, set_dod_contract, mark_claude_role, launch_claude_agent_kitty, spawn_fleet_agent). Las Go con tests NO: ./fn run las despacha como go test. Por eso list_claude_fleet_go_infra se usa por el binario apps/fleetview/fleetview list --json, y classify_fleet_termination_go_infra la consume el watcher embebido en fleetview (no se invoca a mano).

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.