nomadcode/agent-ops/skills/common/orchestrate-agent-task-loop/SKILL.md

9.9 KiB

name description
orchestrate-agent-task-loop Execute dependency-ready PLAN and CODE_REVIEW task loops with workspace write claims, a runtime-injected agent/model catalog, 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: required runtime agent/model catalog path, supplied with --execution-catalog or AGENT_TASK_EXECUTION_CATALOG.
  • task_group: optional agent-task/<task_group> 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.
  • Obtain the execution catalog from the runtime or project layer. Common owns no default agent, model, provider, or route catalog.
  • 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 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, 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}, and {prompt}. 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. loads 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 injected 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 injected 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, and explicit error flags.
  • 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 UTC time, task artifact, plan loop, role, attempt, selected agent/model display, result, and locator.
  • 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

python3 agent-ops/skills/common/orchestrate-agent-task-loop/scripts/dispatch.py \
  --workspace /absolute/repository \
  --execution-catalog /runtime/config/execution-catalog.json \
  --dry-run

Remove --dry-run to start execution. Add --task-group <name>, --max-parallel <n>, 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

  • Catalog was injected, fully validated, preflighted, and revision-pinned.
  • No fixed common agent/model/provider route 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.