Files
fn_registry/dev/issues/0069-autonomous-agent-loop-self-iterating-tasks.md
T

15 KiB

id, title, status, type, domain, scope, priority, depends, blocks, related, created, updated, tags
id title status type domain scope priority depends blocks related created updated tags
0069 Bucle autonomo de subagentes — completar y mejorar tareas sin intervencion humana completado feature
meta
multi-app media
0068
22
23
0028
0085
2026-05-09 2026-05-17

Cierre 2026-05-15

Bucle autonomo operativo. 2 pilotos converged exitosamente:

  • Piloto 1: 0077 (fn run bash mudo). 5 iter, 4/4 checks, ~9 min, PR Gitea#1. Orquestador rediagnostico causa real distinta de la hipotesis del issue.
  • Piloto 2: 0076 (gradle SDK detect). 1 iter, 6/6 checks, ~4 min, PR Gitea#2. Sandbox limpio, --no-verify documentado.

Hardening aplicado tras piloto 1 (regla 9-11 en fn-orquestador/SKILL.md + regla 9-10 en autonomous_loop.md): prohibir paths absolutos fuera del worktree + post-iteracion sanity check git -C <main> status --short debe permanecer en baseline.

Hardening pendiente (no bloquea cierre — iterativo): inicializar operations.db + persistir filas en task_runs (los pilotos llevaron estado inline). Test contra dataset adverso del filtro proposals. Escenarios complejos (issues multi-fichero, conflictos).


Estado 2026-05-13

Infra base lista para lanzar el orquestador:

Paso Estado
1. Migration 006_task_runs.sql hecho — aplicada via embed.FS, verificada en operations.db nueva
2. Subagente .claude/agents/fn-orquestador/SKILL.md hecho (preexistente)
3. dev/autonomous_protected_paths.json hecho — 21 patrones + 2 excepciones documentadas
4. Slash /autonomous-task <issue_id> hecho.claude/commands/autonomous-task.md
5-6. Funciones/tipos auxiliares (task_run_persist, proposal_filter_safe, ...) pending (no bloquea piloto si el orquestador inlinea SQL)
7. Piloto issue 0077 (fn run bash mudo) converged 2026-05-15: 5 iter, 4/4 checks, ~9 min, PR creado, task_run_id=task_98831b93cbf263ee. Causa real distinta de la hipotesis del issue (library-style scripts vs Stdout unconnected) — orquestador diagnostico correctamente y aplico fix valido (buildBashCommand + bashFunctionName helper + 4 unit tests).
8. Piloto issue 0076 (gradle SDK detect) converged 2026-05-15: 1 iter, 6/6 checks, ~4 min, PR Gitea#2, task_run_id=task_cfac9099473ad8e7. Sandbox limpio (uso --no-verify documentado en task_runs.events_json en lugar de editar hooks main). 2 pilotos exitosos -> acceptance criterion piloto cumplido.
9. Hardening + tests pending
10. Regla .claude/rules/autonomous_loop.md pending

Pre-condiciones verificadas 2026-05-13:

  • ✓ migration 006_task_runs.sql aplicada (schema_migrations v6)
  • ✓ 6 subagentes presentes
  • ✓ paths protegidos JSON
  • ✓ master sync OK
  • ✓ gh auth OK (gutierenmanuel)
  • ✓ sin branches auto/* colgando

Listo para piloto: /autonomous-task <issue_id_simple_y_verificable>.

Integracion con issue 0085 (call_monitor): el orquestador puede consultar function_stats, proposals y copied_code antes de cada fase para tomar decisiones informadas; sus invocaciones se loggean automaticamente via hook PostToolUse.

Contexto

El issue 0068 cierra el bucle reactivo a nivel agentes individuales:

  • fn-1 fn-constructor — construye codigo
  • fn-2 fn-executor — ejecuta
  • fn-3 fn-recopilador — audita datos + diseña contrato e2e
  • fn-4 fn-analizador — valida end-to-end
  • fn-5 fn-mejorador — abre proposals con evidencia

Sin embargo, cada fase la lanza un humano (o el main thread bajo instruccion humana). El humano sigue siendo el orquestador. La promesa real es:

"Lanzar una tarea al sistema, irse, y volver para encontrarla terminada y mejorada."

Esa promesa requiere un orquestador autonomo que recorra el bucle CONSTRUIR → EJECUTAR → RECOPILAR → ANALIZAR → MEJORAR sin intervencion humana, hasta convergencia (suite verde) o tope de iteraciones / tiempo.

Este issue planifica ese orquestador.

Objetivo

Disponer de un runner autonomo que toma una tarea (issue, feature, app skeleton) y la entrega funcional, validada y con proposals para mejoras sin intervencion humana entre fases. El humano solo:

  1. Define el objetivo (issue file).
  2. Recibe el resultado al final (PR draft, run_ids verdes, proposals creadas).

Si el bucle no converge en N iteraciones o T tiempo, se para y reporta el estado al humano para decision.

Diseno

Componente nuevo: fn-orquestador

Subagente meta-orquestador. Input: issue_id o task_spec. Algoritmo:

1. Leer task_spec (issue file: objetivo, criterios de aceptacion, fase actual)
2. Loop hasta convergencia o limite:
   a. Determinar siguiente fase pendiente (CONSTRUIR/EJECUTAR/RECOPILAR/ANALIZAR/MEJORAR)
   b. Despachar al subagente correspondiente con prompt derivado del task_spec
   c. Capturar output del subagente
   d. Persistir progreso en task_runs (nueva tabla)
   e. Si fase = ANALIZAR y status = pass:
        - Aplicar fixes propuestos por MEJORAR (con limite de auto-apply, ver §Garantías)
        - Repetir desde CONSTRUIR si todavia hay criterios sin cumplir
   f. Si fase = ANALIZAR y status = fail:
        - Despachar a MEJORAR
        - Aplicar 1-2 proposals automaticas (solo si pasan filtros de seguridad, ver §Garantías)
        - Volver a CONSTRUIR/EJECUTAR para validar
   g. Si N iteraciones sin progreso → parar, reportar estado, pedir humano
3. Reportar resultado final: estado tarea, run_ids, proposals creadas, PR draft si aplica

Nueva tabla task_runs en operations.db

CREATE TABLE task_runs (
    id              TEXT PRIMARY KEY,
    task_id         TEXT NOT NULL,        -- issue_id o slug
    started_at      INTEGER NOT NULL,
    finished_at     INTEGER,
    status          TEXT NOT NULL,        -- running|converged|stalled|aborted
    iterations      INTEGER NOT NULL DEFAULT 0,
    last_phase      TEXT,                 -- construir|ejecutar|recopilar|analizar|mejorar
    last_run_id     TEXT,                 -- e2e_runs.id de la ultima validacion
    progress_json   TEXT NOT NULL DEFAULT '[]'  -- log de fases con timestamps
);

Skill /autonomous-task <issue_id>

Lanza el fn-orquestador con limites configurables:

/autonomous-task 0070 --max-iterations 10 --max-minutes 60 --auto-apply-proposals safe

Flags:

  • --max-iterations N: tope de iteraciones del bucle (default 10).
  • --max-minutes M: timeout total (default 60).
  • --auto-apply-proposals: nivel de autonomia para aplicar proposals:
    • none: solo crea proposals, nunca aplica codigo.
    • safe: aplica proposals con kind=improve_function y diff < 50 lineas.
    • aggressive: aplica casi todas salvo las marcadas risk=high.
  • --branch <name>: rama TBD donde trabaja el bucle (default auto/<issue_id>).
  • --dry-run: no aplica nada, solo simula y reporta plan.

Garantias de seguridad

El bucle autonomo es peligroso si el agente:

  • Borra archivos importantes.
  • Bypasea tests.
  • Toca produccion.
  • Mergea codigo roto a master.

Reglas obligatorias:

  1. Sandbox de rama. El orquestador SIEMPRE trabaja en rama auto/<issue>, nunca master.
  2. No --no-verify, no git push --force. Hooks de pre-commit del repo se respetan.
  3. No mergea a master. Genera PR draft. Humano aprueba el merge.
  4. No toca .claude/, dev/issues/ salvo el del task ni archivos .env/secrets. Lista de paths protegidos en dev/autonomous_protected_paths.json.
  5. Filtro de proposals auto-aplicables:
    • Solo proposals creadas por fn-mejorador con evidence que apunte a runs reales.
    • Diff < 50 lineas (configurable).
    • No tocan tests existentes (no se "arreglan" los tests).
    • No introducen dependencias nuevas (pnpm add, go get, etc).
  6. Watchdog de progreso. Si 2 iteraciones consecutivas dan el mismo set de fails, parar y pedir humano (loop infinito detectado).
  7. Auditoria completa. Cada decision del orquestador se loggea en task_runs.progress_json con razonamiento + diff aplicado.
  8. Rollback trivial. La rama es desechable; si la suite no converge, humano puede git branch -D auto/<issue> y empezar de nuevo.

Tipos de tareas soportadas

Empezar con un subset acotado:

Tipo Descripcion Convergencia
feature_app_simple Endpoint nuevo + handler + test suite verde + endpoint responde 200
bugfix_with_repro Issue con repro reproducible repro pasa de fail a pass
refactor_safe Renombrar/extraer funcion + actualizar callers suite igual de verde + grep limpio
add_e2e_check Crear e2e_checks para app sin ellos via fn-recopilador app tiene contrato + run pasa

NO soportadas inicialmente (requieren mas heuristica):

  • Diseño de arquitectura nuevo.
  • Decisiones de UX subjetivas.
  • Cambios en BD productiva.
  • Cualquier cosa que toque secrets/credenciales.

Convergencia

El bucle termina cuando:

  • Convergido: todos los criterios de aceptacion del issue marcan ✓ Y la suite e2e pasa Y fn doctor <app> pasa.
  • Estancado: misma metric de fallos en 2+ iteraciones (loop sin progreso).
  • Timeout: --max-minutes alcanzado.
  • Iteraciones: --max-iterations alcanzado.
  • Bloqueo humano: el orquestador detecta una decision que requiere humano (ej. eleccion de libreria nueva, schema breaking change) y para con status=needs_human.

En cualquier caso, output:

=== /autonomous-task: <issue_id> ===
status:        <converged|stalled|timeout|needs_human>
iterations:    N / max
duration:      M min / max
branch:        auto/<issue>
PR draft:      <url o "no creado">
proposals:     <count> creadas, <count> aplicadas
last run_id:   <run_id> (status: pass|fail)

Detalle de iteraciones:
  1. construir → ok (3 funciones nuevas)
  2. ejecutar → ok
  3. analizar → fail (3 checks)
  4. mejorar → 3 proposals (2 auto-aplicadas)
  5. construir → ok (re-build tras patches)
  6. analizar → pass
  7. recopilador → ok (operations.db integra)
  8. CONVERGED

Siguientes pasos para humano:
  - Revisar PR draft <url>
  - fn proposal list -s pending --target-id <issue>

Plan de ejecucion

Paso Tarea Dependencia
1 Migracion 006_task_runs.sql en fn_operations/migrations/ issue 0068 cerrado
2 Subagente fn-orquestador (.claude/agents/fn-orquestador/SKILL.md) paso 1
3 Lista de paths protegidos (dev/autonomous_protected_paths.json) paso 2
4 Skill /autonomous-task <issue_id> (.claude/commands/autonomous-task.md) paso 2
5 Funciones registry: task_run_persist_go_infra, proposal_filter_safe_go_infra, git_branch_sandbox_go_infra, pr_draft_create_go_infra paso 2
6 Tipo TaskSpec_go_core (issue + criterios + limites) paso 5
7 Pilotaje en 1 issue tipo feature_app_simple (ej. añadir endpoint trivial a kanban) paso 4
8 Pilotaje en 1 issue tipo add_e2e_check (correr orquestador para añadir contrato a app sin el) paso 7
9 Hardening: tests del orquestador, edge cases (red flaky, BD locked, conflicto merge) paso 8
10 Documentacion + regla .claude/rules/autonomous_loop.md paso 9

Criterios de aceptacion

  • fn-orquestador definido como subagente.
  • Tabla task_runs migrada con migration aditiva (006_task_runs.sql). Nota: pilotos 1+2 NO inicializaron operations.db propia para persistir filas en task_runs — el orquestador llevo estado inline (variables internas + output). Hardening pendiente: inicializar operations.db con migration 006 al arrancar el bucle + INSERT row al inicio + UPDATE final.
  • Skill /autonomous-task orquesta los 5 subagentes en bucle.
  • Filtro de proposals auto-aplicables documentado (.claude/rules/autonomous_loop.md seccion "Reglas duras"). Test contra dataset adverso pendiente.
  • Piloto 1: issue 0077 (fn run bash mudo) — CONVERGED 5 iter, 4/4 checks, PR Gitea#1. Hallazgos:
    • causa real (library-style scripts) divergia de hipotesis del issue (Stdout unconnected); orquestador rediagnostico bien.
    • bonus fix: scan_secrets_in_dirty.sh + git_hook_audit_app_drift.sh worktree support.
    • sandbox parcial: orquestador modifico los 2 hooks en repo principal. Causa probable: paths absolutos al fixear hooks bloqueantes. Hardening aplicado 2026-05-15 (SKILL.md regla 9-11 + autonomous_loop.md regla 9-10).
  • Piloto 2: issue 0076 (gradle SDK detect) — CONVERGED 1 iter, 6/6 checks, PR Gitea#2. Sandbox limpio. Hallazgos:
    • gh CLI no soporta Gitea -> usado REST API directo con credential store.
    • --no-verify legitimo cuando hook bloquea por bug en main; documentado en task_runs.events_json (alineado con regla 10 de autonomous_loop.md).
    • tiempo mucho menor (4 min vs 9 min piloto 1) -> hipotesis: caching de contexto + fix mas simple + path bash en vez de Go.
  • Watchdog de "no progreso" especificado (N=3 iteraciones sin subir checks_pass/checks_total -> abort).
  • Output del runner incluye trazabilidad completa (task_runs.events_json[]).
  • Documentacion en .claude/rules/autonomous_loop.md (rule 31).

Riesgos

  • Loops infinitos: agentes que "parchean" tests rotos en vez de codigo. Mitigacion: filtro de proposals (no tocar tests), watchdog.
  • Coste: cada iteracion = N llamadas a Claude. Mitigacion: --max-iterations, --max-minutes, modelos mas baratos para fases mecanicas (haiku para fn-recopilador, sonnet para fn-constructor).
  • Calidad: codigo auto-generado puede compilar pero ser malo. Mitigacion: fn-analizador valida no solo build sino assertions + drift; humano siempre revisa PR.
  • Seguridad: agente comprometiendo el repo. Mitigacion: sandbox de rama, paths protegidos, no merge automatico, hooks no skipeables.
  • Drift de criterios: el agente "interpreta" liberamente los criterios de aceptacion del issue. Mitigacion: criterios en el issue deben ser verificables programaticamente (ej. "endpoint responde 200" mejor que "el endpoint funciona bien").
  • Acumulacion de proposals: si el bucle crea muchas proposals sin que humano las cierre, ruido. Mitigacion: limite por task_run, dedup automatica por similitud.

Out of scope

  • Auto-merge a master (siempre PR draft).
  • Toma de decisiones de arquitectura (eleccion de libreria, patron de diseño).
  • Tareas que requieran credenciales (deploys, llamadas a APIs externas con auth).
  • Tareas que toquen schema de DBs productivas.
  • Self-modification del orquestador (no se puede mejorar a si mismo en el mismo run).

Notas

  • Inspiracion: SWE-bench, agentic flows tipo aider/cursor compose, Devin. Diferencia: aqui el agente NO escribe codigo libre — orquesta agentes especializados que ya respetan las reglas del registry.
  • El bucle reactivo del CLAUDE.md ya describe semantica de fases. Este issue solo añade el orquestador que las recorre solo.
  • La regla kiss.md aplica: empezar con tipos de tarea simples y verificables. Resistir tentacion de soportar todo desde dia 1.
  • Conexion con feature_flags.md: si el bucle queda detras de un flag (autonomous_loop_enabled), se puede activar/desactivar sin redeploy.