Loop Tasks Driver

SkillProductivity

Lets your agent run a task graph from start to finish, making commits, QA checks, and reviews until the work is done.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Loop Tasks Driver skill

About this capability

Run a requested Compozy spec delivery loop through task checkpoints, scoped QA, review, and PR CI.

What this skill tells your AI

The instructions your AI receives, as published by compozy/compozy in .agents/skills/cy-loop-tasks/SKILL.md and read by ahel’s review.

Drive a Compozy spec to completion as a self-healing continue loop: each iteration detects the current phase, runs exactly one phase action, writes memory, updates state.yaml, and prints the iteration summary — then continues at detect unless the outcome is an evidence-backed external blocker or Phase E. A failed command stays inside the current phase action: diagnose, repair, and rerun it before writing iteration state. Filesystem state still resumes cleanly if the session ends mid-loop.

The loop is a five-phase state machine:

PhaseActionExecutor
0bootstraporchestrator
Bone task or slice + verify + checkpoint commitorchestrator, or herdr frontend worker
Cqa_report, then qa_executionFable 5 herdr worker, then orchestrator
Ddeep-review rounds until SHIP + checkpoint commit per roundorchestrator
Edone-signatureorchestrator

Compatible with ~/dev/ai/codex-loop-plugin goal mode; the plugin itself is never modified. Prefer in-session continue over waiting for a Stop→restart — restarts are a resume safety net, not the driver.

Inputs

  • <slug> — directory name under .compozy/tasks/.
  • <goal_text> — verbatim [[CODEX_LOOP goal="..."]] text or the manual reason for the run. Captured once at bootstrap into state.yaml.goal_signature.
  • --frontend <claude|cursor> — optional. Selects the frontend worker agent and activates the herdr frontend lane for the whole loop. Captured once at bootstrap into state.yaml.frontend_agent; when absent, every task runs locally. Syntax examples in references/goal-header-template.md.
  • --stacked — optional, default off, tasks mode only. Publishes each Phase B checkpoint as one layer of a GitHub stacked-PR chain (gh stack). Captured once at bootstrap into state.yaml.stacked. When present, read references/stacked-prs.md in full during bootstrap and verify its prerequisites before the first Phase B iteration.
  • A pre-authored .compozy/tasks/<slug>/_spec.md. Without it, bootstrap stops with a blocker.

Helper scripts

Bundled under .agents/skills/cy-loop-tasks/scripts/ — stdlib-only Python 3.11+, no network, no model calls. Invoke by the explicit repo-root paths shown in the workflow steps.

ScriptRolePhase
_state_io.pyprivate strict state codec (imported, not invoked)all state helpers
init-state.pybootstrap (mutating once)0
detect-phase.pyread-onlyevery iteration
update-state.pymutatingevery iteration
commit-checkpoint.pymutating (git commit)B, D
test_scripts.pyread-only self-testskill maintenance only

Herdr delegation lanes

Two lanes dispatch work to herdr worker TUIs. Before any dispatch, read references/herdr-delegation.md in full and activate the herdr-orchestration skill it builds on.

  • Frontend lane (Phase B) — active only when state.frontend_agent is set. While active, every frontend task or slice is dispatched to the selected worker (claude → Claude Code Opus at xhigh effort, cursorcursor-agent --yolo --model grok-4.5); the orchestrator session stays in orchestration mode and never implements frontend work itself.
  • QA-report lane (Phase C) — always active. qa_report is produced by a Claude Fable 5 worker (claude --permission-mode auto --model claude-fable-5), launched direct — never plan-first. The orchestrator runs qa_execution itself.

Workflow

Each iteration is one detect → phase action → memory → state → summary cycle. After a completed (non-blocked) summary that is not Phase E, continue at Step 1 in the same turn — do not end the session between rounds.

If any command, gate, worker, or artifact check fails during a phase action, read references/recovery-loop.md in full immediately and run its repair loop. Do not write final iteration state or print the summary for an intermediate failure.

Step 1 — Detect.

  1. Print pwd and confirm the working directory is the repo root (the directory containing .compozy/tasks/). On mismatch, locate that root, change into it, and confirm again; block only when the task tree is absent.
  2. Activate cy-workflow-memory so its protocol is loaded for later use (once per session is enough; re-activate only if context was dropped).
  3. Run python3 .agents/skills/cy-loop-tasks/scripts/detect-phase.py <slug>. The printed line decides the whole iteration; the output catalog and entry/exit conditions are in references/phase-transitions.md.

Done when: detect-phase emitted exactly one supported phase/action line and the matching branch below is selected.

Step 2 — Run exactly one phase branch.

Phase 0 — Bootstrap

  1. Confirm .compozy/tasks/<slug>/_spec.md exists. Missing → scaffold memory/MEMORY.md from references/memory-protocol.md, record the blocker under ## Open Risks, print the iteration summary with outcome=blocked, and stop (state.yaml does not exist yet, so there is no update-state call).
  2. Run python3 .agents/skills/cy-loop-tasks/scripts/init-state.py <slug> --goal "<goal_text>", adding --frontend <claude|cursor> and/or --stacked when the invocation text carries the parameter (for --stacked, first read references/stacked-prs.md in full and verify its prerequisites). Mode auto-detects: tasks when _tasks.md plus at least one task_*.md exist, else free.
  3. Activate cy-spec-preflight for the phase the next iteration enters (tasks, or task-body when a single concrete file is next).
  4. Scaffold .compozy/tasks/<slug>/memory/MEMORY.md with the canonical sections from references/memory-protocol.md.
  5. Run python3 .agents/skills/cy-loop-tasks/scripts/update-state.py <slug> --phase 0 --action "bootstrap (mode=<mode>)" --outcome completed --memory-written "memory/MEMORY.md".

Done when: state.yaml exists and memory/MEMORY.md has the canonical sections.

Phase B mode=tasks — execute one task

  1. Take the task printed by detect-phase (task=<stem>). Read .compozy/tasks/<slug>/<stem>.md and confirm frontmatter status: is pending or in_progress. Frontmatter wins — on drift, reconcile with update-state.py <slug> --task-completed <stem> for already-finished tasks or --reconcile-tasks for a late-authored graph, then re-run detect-phase.
  2. Mark the task active: flip its frontmatter status: to in_progress, then run python3 .agents/skills/cy-loop-tasks/scripts/update-state.py <slug> --task-current <stem> (a marker call — it records no iteration; --task-completed clears it automatically at step 8).
  3. Activate cy-spec-preflight in task-body mode for the picked file.
  4. Resolve the shared and current memory paths from references/memory-protocol.md and pass them into the lane that executes the work.
  5. Frontend lane — when detect-phase printed lane=frontend agent=<x>: dispatch the task to that worker per references/herdr-delegation.md. The worker owns implementation, memory updates, focused validation, and cy-final-verify evidence. It never commits. Skip step 6.
  6. Local lane — activate cy-execute-task on the picked file with auto-commit disabled. Run the task's focused validation — the commands the task file names plus scoped tests for touched packages; no project-wide gate here (gate map: Critical Rules). Run the task's ## Shippable Outcome verification tier and record its evidence in the task memory: gate is already covered by focused validation; probe runs its named CLI/HTTP/UDS command; smoke opens the surface through its real entry path and captures the touched Visual Contract sections. Then cy-final-verify with the narrow per-task claim. Per-task peer-review requests stay deferred to Phase D and full QA cycles stay in Phase C — flag docs/qa/scenarios/ per the diff and move on.
  7. Confirm memory is updated (written locally, or verified from the worker) and that cy-final-verify evidence is PASS before any state flip. For the frontend lane, verify the worker's evidence instead of re-running verify.
  8. Run python3 .agents/skills/cy-loop-tasks/scripts/update-state.py <slug> --phase B --task-completed <stem> --action "executed <stem>" --outcome completed --memory-written "memory/<stem>.md,memory/MEMORY.md" --verify-pass.
  9. Run python3 .agents/skills/cy-loop-tasks/scripts/commit-checkpoint.py <slug> --task <stem>. Stdout starts with a commit SHA or SKIP: no changes; copy it into the iteration summary (in stacked mode a stack: submitted line follows — the script owns the layer branch and PR submission, see references/stacked-prs.md). On exit 1, enter the repair loop and retry the normal checkpoint after its root cause is fixed. Never bypass the hook with --no-verify.

Done when: task frontmatter, memory, state.yaml, and the checkpoint result all reflect the same completed task.

Phase B mode=free — execute one slice

  1. Re-read _spec.md deliverables and acceptance in full; compare against state.progress.checklist[].
  2. Pick the smallest coherent slice (≤ ~4 hours) that advances at least one acceptance criterion; capture its text exactly.
  3. Run python3 .agents/skills/cy-loop-tasks/scripts/update-state.py <slug> --add-progress "<slice text>" --action "slice picked" --outcome completed.
  4. Re-read state.yaml; the current memory file is memory/free-iter-<NNN>.md, <NNN> = the new checklist entry's iteration, zero-padded to three digits.
  5. Frontend lane — when state.frontend_agent is set AND the slice's owned paths are exclusively frontend surfaces (classification in references/herdr-delegation.md): dispatch per that reference. The worker owns implementation, memory updates, focused validation, and cy-final-verify evidence; it never commits. Skip step 6.
  6. Local lane — implement the slice, record decisions and learnings in the current memory file, run the slice's focused validation (slice-named commands + scoped tests for touched packages; no project-wide gate) — for a slice that touches UI, include a smoke pass through the surface's real entry path — then cy-final-verify with the narrow per-slice claim.
  7. Confirm memory is updated and cy-final-verify evidence is PASS. For the frontend lane, verify the worker's evidence instead of re-running verify.
  8. Acceptance self-check: when every spec criterion has a completed checklist entry, add --deliverables-complete to the step 9 call.
  9. Run python3 .agents/skills/cy-loop-tasks/scripts/update-state.py <slug> --phase B --complete-progress "<slice text>" [--deliverables-complete] --action "slice <text>" --outcome completed --memory-written "memory/free-iter-<NNN>.md,memory/MEMORY.md" --verify-pass.
  10. Run python3 .agents/skills/cy-loop-tasks/scripts/commit-checkpoint.py <slug> --slice "<slice text>" with the exact step 3 text — same SKIP / exit-1 semantics as mode=tasks step 8.

Done when: the slice's checklist entry is completed and the checkpoint result is recorded.

Phase C — QA

Run only the printed action.

qa_report — dispatched, never authored locally:

  1. Run the B→C boundary gate: one make gate, repaired to green through the recovery loop before any QA action — cross-task drift surfaces here, not inside a QA cycle.
  2. When release-grade runtime scope needs a lab and no active bootstrap-manifest.json exists, activate the project's QA bootstrap skill first (e.g. eng-qa-bootstrap in Compozy) when installed.
  3. Dispatch the Fable 5 worker per references/herdr-delegation.md (QA-report lane). The worker activates qa-report with qa-docs-path=docs/qa and updates journey flows, docs/qa/scenarios/ files, and cycle charters.
  4. Verify the worker evidence (each reported artifact exists, no worker commit), then run python3 .agents/skills/cy-loop-tasks/scripts/update-state.py <slug> --phase C --qa-report-done --action "qa-report produced" --outcome completed --memory-written "memory/qa-report.md,memory/MEMORY.md".

qa_execution — local:

  1. Activate qa-execution with qa-docs-path=docs/qa; it writes the dated run report at docs/qa/reports/<YYYY-MM-DD>-<slug>.md and updates scenario-file verdicts.
  2. When the report is "not ready" or a Blocks-Completion/Data-Loss bug is open, keep the Phase C action open: repair every in-scope bug, rerun the affected QA, and repeat qa-execution through the recovery loop. Do not set --qa-execution-done on an intermediate report.
  3. Once the report is ready, run python3 .agents/skills/cy-loop-tasks/scripts/update-state.py <slug> --phase C --qa-execution-done --action "qa-execution produced" --outcome completed --memory-written "memory/qa-execution.md,memory/MEMORY.md" --verify-pass.

mode=tasks addition: when the printed QA action corresponds to the pending QA task file, flip that task's frontmatter status: to completed and add --task-completed <stem> to the same update-state call so tasks.pending drains.

Done when: the printed QA artifact exists on disk and its flag is recorded in state.yaml.

Phase D — peer-review rounds until SHIP

One round per iteration; detect-phase re-emits peer_review until the verdict is SHIP on a verify-PASS tree. Enter this phase only after every Phase B task or slice is complete and both QA flags are true.

  1. Activate deep-review for the round number printed by detect-phase, scoped to the loop's full diff: --base = the ref the loop started from when known (default main), --spec .compozy/tasks/<slug> (contract conformance), --subagent codex (cross-LLM reviewer lane — the implementing model never solely reviews its own work). Later rounds ride deep-review's incremental state; never pass --full mid-loop.
  2. The loop is the deciding authority over the round: remediate every confirmed finding and every nitpick from the round's review.md in this same iteration, then re-run the project's scoped gate (PR CI is Phase E's). The round's verdict is the SHIP/FIX_BEFORE_SHIP/REWORK value in review.md/state.json.
  3. Update memory/peer-review.md (a ## Round <N> section per round), then run python3 .agents/skills/cy-loop-tasks/scripts/update-state.py <slug> --phase D --review-round-done <SHIP|FIX_BEFORE_SHIP|REWORK> --action "peer-review round <N> (<verdict>)" --outcome completed --memory-written "memory/peer-review.md,memory/MEMORY.md" --verify-pass. The call uses --verify-pass: a failed post-remediation gate stays inside the repair loop, and a SHIP verdict on a failing tree is void.
  4. Run python3 .agents/skills/cy-loop-tasks/scripts/commit-checkpoint.py <slug> --review-round <N> — same SKIP / exit-1 semantics as Phase B.

Done when: the round's review.md exists with a verdict, every confirmed finding and nitpick from it is remediated (or the verdict was SHIP), and state.yaml records the round.

Phase E — done

  1. Run make gate and a final cy-final-verify for the local pre-push claim, then confirm state.verify.last_status=PASS.
  2. Push the current head and create or update its draft PR. In stacked mode, resubmit the stack and include every open layer; otherwise use the current branch PR. Record pending evidence with update-state.py <slug> --phase E --action "await exact-head PR CI" --outcome partial --ci-pending --pr-url <url> --head-sha <sha>; repeat the paired URL/SHA flags in stack order.
  3. Watch every PR's checks to terminal state (gh pr checks --watch --interval 20). A pending or red check keeps Phase E open; diagnose, repair, rerun the affected local gate, checkpoint, push, and watch the new head. Only green required checks at the recorded head pass. Then record fresh terminal evidence with update-state.py <slug> --phase E --action "exact-head PR CI passed" --outcome completed --ci-pass --pr-url <url> --head-sha <sha> --ci-check <name> (repeat paired PR and check flags as needed). The script rejects stale heads and empty check sets.
  4. Walk the Phase E section of references/checklist.md; every box must pass.
  5. Print the iteration summary block from assets/iteration-summary.template.md with phase_out=E and checkpoint field n/a (phase != B/D), followed by every entry from memory/MEMORY.md ## Open Questions — the decisions defaulted mid-loop surface to the user here, in one batch.
  6. Print the literal contents of assets/done-signature.txt on its own line — the codex-loop goal-check confirmation scans for it.
  7. Stop — Phase E is the only successful terminal.

Done when: the local gate and exact-head PR CI are green, the Phase E checklist passes, and the done-signature is the final output line.

Step 3 — Self-audit, summarize, then continue.

  1. Walk references/checklist.md for the phase just executed; every box must pass before summarizing.
  2. Print the iteration summary block from assets/iteration-summary.template.md (Phase E already printed it and adds only the done-signature line).
  3. Continue gate: stop only when phase_out=E or the external-blocker criteria in references/recovery-loop.md are proven and outcome=blocked. Otherwise re-enter Step 1 immediately — the summary marks the round; it does not end the session.

Done when: the phase checklist passes, its summary is printed, and control either returned to Step 1 or stopped at a permitted terminal.

Memory protocol

Memory goes through the cy-workflow-memory skill — the exact paths per phase are in references/memory-protocol.md. Update memory before flipping any tracking field.

Goal-mode integration

The canonical [[CODEX_LOOP ...]] header, the manual invocation text, and --frontend syntax live in references/goal-header-template.md.

Critical Rules

  • One phase action per iteration; repair failures inside that action, then continue at detect until Phase E or a proven external blocker — never idle between rounds waiting for a restart or re-invocation.
  • The loop never stops to ask. Any decision — orchestrator included — resolves autonomously via cy-execute-task's Authority ladder; record the pick and any user-facing question under memory/MEMORY.md ## Open Questions and continue. Questions reach the user in one batch in the Phase E summary.
  • state.yaml mutates only through init-state.py and update-state.py; hand-edits void resume guarantees. There is no top-level current_phasedetect-phase.py derives it from durable state and filesystem truth every run.
  • goal_signature — and the [[CODEX_LOOP]] goal text it mirrors — is write-once at bootstrap: no rewording, no re-init, no deleting state.yaml. Mid-loop scope changes land in memory.
  • Frontmatter status: on task_NN.md is the source of truth; reconcile state.yaml when they disagree.
  • Memory updates precede status flips. Always.
  • Gate map — Phase B runs focused validation then cy-final-verify before each checkpoint; make gate runs at the Phase C boundary, after Phase D remediation, and once before the final push. The PR's parallel CI run owns the full gate at Phase E. A FAIL opens the repair loop; only exact-head CI PASS closes the phase action.
  • Peer review (deep-review) runs only in Phase D. Per-task peer-review instructions inside task files or specs are superseded by this loop's phase machine — note "deferred to Phase D" in the task memory and move on.
  • Full QA cycles (journeys, charters, dated reports) run only in Phase C. Phase B owns each task's proportional verification — the ## Shippable Outcome tier (gate | probe | smoke with Visual Contract capture) with evidence in the task memory — plus scenario flagging: add/reset docs/qa/scenarios/ files per the task's diff, note "full walk deferred to Phase C" in the task memory, and move on. A UI slice's smoke evidence is Phase B work; relocating it to a later phase is the gate relocation this rule exists to prevent.
  • Checkpoint commits (Phases B and D) belong to the orchestrator: cy-execute-task runs with auto-commit disabled, and every worker packet forbids committing. The checkpoint captures code, memory, task frontmatter, the master tasks file, and the advanced state.yaml in one atomic, restorable snapshot. When state.stacked=true, the checkpoint script also owns the stack layer and PR submission (references/stacked-prs.md); the loop never merges the stack.
  • Checkpoint commits capture the whole tree (git add -A is the script's contract): files this loop did not author ride into the snapshot by design — the untouched-files rule forbids reverting them, not committing them. Never pause to triage a dirty tree.
  • Phase E requires qa.report_done=true, qa.execution_done=true, review.ship=true, and verify.last_status=PASS.
  • Do not regenerate the loop's input graph with cy-create-tasks, cy-create-spec, cy-tasks-tail-qa-pair, or cy-web-docs-impact.

Error Handling

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
3k
Forks
177
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
cy-loop-tasks
Source
github.com/compozy/compozy