--- name: orchestrate-agent-task-loop description: Execute dependency-ready PLAN and CODE_REVIEW task loops with workspace write claims, a bundled default agent/model catalog, runtime catalog overrides, deterministic target failover, and persistent recovery state. --- # Orchestrate Agent Task Loop ## Final-channel gate Do not end the caller turn through `final` until either: - every in-scope task has a verified archived `complete.log`, every generated work log is archived, no task or execution remains active, and the dispatcher exits `0`; or - the user explicitly asks to stop the current run. Use `commentary` for non-terminal status, blockers, questions, recovery notices, and partial completion. If the user asked for a persistent run, successful completion alone does not release this gate. ## Purpose Monitor the file-backed workflow under `agent-task/` and converge ready PLAN implementation, optional self-check, official review, follow-up PLAN, and archive completion. The dispatcher owns deterministic scheduling, recovery, target transitions, and runtime evidence. Child agents own implementation and review judgments within their assigned artifact. ## Inputs - `workspace`: trusted repository root containing `agent-task/`; defaults to the current directory. - `execution_catalog`: optional runtime agent/model catalog override, supplied with `--execution-catalog` or `AGENT_TASK_EXECUTION_CATALOG`; otherwise use `assets/default-execution-catalog.json`. - `task_group`: optional `agent-task/` scope. - `dry_run`: inspect routes, dependencies, claims, and catalog validity without launching an agent. - `max_parallel`: workspace-wide active task-stage limit; defaults to `3`; `0` means unlimited. - `retry_blocked`: retry eligible blocked tasks without changing their catalog route history. `--validate-plan` validates one PLAN without launching orchestration and therefore does not require an execution catalog. ## Preconditions - Read the current plan and code-review contracts routed by `agent-ops/skills/common/router.md`. - Use the bundled default catalog unless the runtime or project layer supplies an override. - Run `--dry-run` before the first live execution. - Never bypass the physical-workspace dispatcher lock. - Keep automatic approval inside the current workspace and the PLAN's declared write set. ## Runtime catalog contract The bundled catalog is `assets/default-execution-catalog.json`. Catalog resolution order is explicit argument, `AGENT_TASK_EXECUTION_CATALOG`, then the bundled default. Every catalog root contains exactly `schema_version`, `targets`, and `routes`. It must cover `worker` and `review`, and each stage must define every `local-G01` through `local-G10` and `cloud-G01` through `cloud-G10` route. Each target has: - an opaque `agent` identity; - an opaque `model` identity; - `execution_class`: `local_model` or `cloud_model`; - optional `selfcheck_required` boolean; - `runtime.command`: a non-empty argv template executed without a shell; - optional `runtime.resume_command`, `preflight_command`, `environment`, `session_path`, `native_session_monitor`, `terminal_success`, and `auxiliary_logs`; - optional `runtime.output_format`: `text` or `jsonl`. Command templates may use only `{agent}`, `{model}`, `{target_id}`, `{workspace}`, `{attempt_dir}`, `{session_id}`, `{resume_session}`, `{resume_session_dir}`, and `{prompt}`. `native_session_monitor=true` requires both `resume_command` and `session_path`. `terminal_success=agent_end` requires JSONL output and accepts only a non-retrying final `agent_end` whose last assistant message has `stopReason=stop`; `error`, `aborted`, a missing event, or another stop reason fails closed. The catalog must not embed repository secrets; environment values should refer only to runtime-provided non-secret configuration. Each route owns its ordered `candidates` plus optional `rule_id`, `policy_priority`, and `reason_codes`. A route may use catalog-owned `windows` instead of a fixed candidate list; every window supplies an IANA timezone, start/end time, and candidates. Exactly one window must match. Before work starts, the dispatcher: 1. resolves and validates the entire catalog; 2. verifies exact route coverage and every target reference; 3. verifies each target command is executable; 4. runs an optional target `preflight_command` for live execution; 5. records the catalog source and SHA-256 revision in the decision. A persisted decision is valid only while the resolved catalog revision and selected target snapshot still match. Catalog changes fail closed instead of silently changing an active work unit. ## Selection and failover - Initial execution selects the first candidate in the resolved route. - Resume pins the persisted target and route revision. - The dispatcher never queries quota before admission and never accepts a quota snapshot as selector input. - Classify actual terminal output after an attempt. `provider-quota`, `context-limit`, `model-unavailable`, `provider-stream-disconnect`, and `provider-connection` may advance to the next unused route candidate. - In particular, a confirmed quota/rate-limit error advances directly to the next candidate. A plain mention of quota in source text, model prose, or non-terminal output is not sufficient evidence. - `generic-error`, process termination, work-log failure, and review-control failure do not imply quota and do not change the selected target. - Never use a hidden promotion table or provider-specific fallback. If no next catalog candidate exists, keep recovery within the stage budget or block the task with evidence. - Transfer logical context using the prior locator, normalized output, raw stream, workspace, and PLAN. Use native resume only when both targets opt into the same catalog-declared native-session mechanism and the session belongs to the current workspace. ## Scheduling and write claims - Admit every dependency-ready task whose canonical PLAN write set does not collide with another active claim. - Require exactly one non-empty `Modified Files Summary` or supported legacy heading. Reject broad, malformed, directory, outside-workspace, or missing paths. - Atomically claim canonical paths before worker, self-check, or review execution. Keep a task's claim across retries and follow-up PLANs; release it only after verified archive completion. - Treat explicit predecessors as unfinished while matching live execution evidence exists, even if a `complete.log` is already visible. - Apply `max_parallel` across the physical workspace, independent of task-group filtering. Do not count internal helper coroutines as agent slots. - A blocker delays only that task and its dependency closure. Continue draining independent work. ## Prompt and child boundary Prefix worker and review prompts with the dispatcher-child boundary that prohibits starting or monitoring another orchestration loop. A child may use `dispatch.py --validate-plan` only when its plan or review finalization requires it. Prompts must include absolute artifact paths and instruct the child to follow the repository's language and output rules. Do not hardcode a programming language, human language, agent, model, or provider in common prompts. Never ask a child to create, edit, or summarize `WORK_LOG.md`; that file is dispatcher-owned. ## Self-check Run self-check only when the selected catalog target declares `selfcheck_required=true`. The completing decision, not a fixed agent identity or execution class, determines the requirement. Accept self-check completion only when `## Implementation Checklist` or its supported legacy heading contains at least one checkbox and every checkbox has a non-empty value. Run one full pass, then resume the latest successful native context for at most 10 unchecked-item retries when the target supports native resume. Block instead of silently starting a new context when a required persisted context is unavailable. ## Runtime evidence and recovery - Store each attempt under the dispatcher state directory with `locator.json`, `stream.log`, `normalized-output.log`, and `heartbeat.log`. - Record the target id, opaque agent/model identity, execution class, runtime contract, catalog evidence, process identity, workspace identity, timestamps, result, and exact failure evidence. - Treat stderr as terminal diagnostic evidence. For JSONL, recognize generic terminal event fields such as error/fatal type or severity, rejected/failed status with an error code, explicit error flags, and a non-retrying `agent_end` whose last assistant message ends with `error` or `aborted`. - Determine liveness from PID/start-token/process-marker evidence and actual stream or native-session progress. Heartbeat mtime is never agent progress. - Never start a duplicate attempt while owned live evidence remains. - Keep a 10-consecutive-failure budget per task stage. Reset only that stage's budget after success. - Preserve failed attempt logs. Delete successful attempt logs only after verified archive completion and no live evidence. ## Work log - Keep one dispatcher-owned `WORK_LOG.md` per task group. - Append chronological `START` and `FINISH` rows with KST (`Asia/Seoul`) time, task artifact, plan loop, role, attempt, selected agent/model display, result, and locator. Use the PLAN artifact for worker and self-check rows; use the CODE_REVIEW artifact only for official review rows. - Archive the group log as the next `work_log_N.log` only after every observed task in the group is verified complete and idle. - Work-log write or archive failure is a retryable control-plane failure and prevents exit `0`. ## Invocation ```bash python3 agent-ops/skills/common/orchestrate-agent-task-loop/scripts/dispatch.py \ --workspace /absolute/repository \ --dry-run ``` Remove `--dry-run` to start execution. Add `--execution-catalog ` only to override the bundled default. Add `--task-group `, `--max-parallel `, or `--retry-blocked` only when requested by the workflow. Launch the live dispatcher as one persistent foreground process. Do not wrap it in an arbitrary timeout and do not start a second dispatcher after a normal tool yield. Wait on the same execution handle until an attention event or terminal exit. ## Completion checklist - [ ] The resolved catalog was fully validated, preflighted, and revision-pinned. - [ ] No hidden route outside the resolved catalog or quota probe was used. - [ ] Runtime quota errors moved only to the next catalog candidate. - [ ] Dependencies, write claims, and workspace concurrency were enforced. - [ ] Required self-check and official review stages completed. - [ ] Every observed task has a verified archived `complete.log`. - [ ] Work logs and successful attempt cleanup were reconciled. - [ ] No active, waiting, pending, or blocked in-scope task remains. - [ ] Dispatcher exited `0` before successful final response.