| name | executing-plans |
| description | Executes an approved epic one wave at a time, dispatching a worker per task and stopping at a checkpoint after each wave. Use when an approved epic contract and native wave plan exist in the current root session, when resuming work after a previous checkpoint, or when iteratively building a feature and execution learnings require a later wave. User phrases like "continue the plan", "next wave", "resume where we left off", "pick up the epic". |
Codex Backend
This skill is assembled for Codex. Before following the workflow, read
references/codex-backend.md completely. Its operation mappings are binding:
SessionPlanRead reads the root session's native wave plan, SessionPlanWrite
mutates it only through update_plan, and SessionContextRead reads the same
root transcript. One native plan step is one Gambit wave; parallel workers are
subagent threads inside that single step. These are backend operations, not
literal shell commands.
Executing Plans
Freedom: LOW — load epic, execute one wave, checkpoint, STOP.
Overview
Execute an epic in cycles with mandatory checkpoints. Load the approved root-session contract and wave plan → run one wave with one or more workers → create the durable checkpoint → STOP. User reviews, then invokes again to continue.
Core principle: Epic requirements are immutable. Worker briefs and later waves adapt to reality. STOP after each wave for human oversight — no exceptions. Running a second wave without stopping is the batching that's forbidden.
Announce at start: "I'm using gambit:executing-plans to implement this wave."
Execution and continuation
Each invocation runs one cycle — execute the ready work, verify, run the quality gate, commit, present the checkpoint — then STOPs (ends the turn). The skill never loops across cycles within a single turn.
STOP does not mean the epic halts; it means this turn ends and the next cycle begins on the next invocation. Two things can trigger that next invocation:
- A human re-running
$gambit:executing-plans — the default.
- A goal Stop-hook that re-invokes the skill automatically — the ONLY sanctioned way to run cycle-after-cycle without a human pause.
Continuous, no-human-pause execution is therefore authorized only by a goal Stop-hook — never self-granted. An in-session "just keep going, don't stop for me" does NOT authorize it: if the user wants unattended execution they set a goal; surface that in the checkpoint rather than batching cycles yourself. Every safeguard — quality gate, commit, checkpoint summary, and this re-invocation — runs on every cycle regardless; the goal changes only who triggers the next one, never what happens inside a cycle.
Quick Reference
| Step | Action | Critical Rule |
|---|
| 0. Check State | SessionPlanRead | Wave state tells you where to resume — never ask |
| 1. Load Contract + Enter Worktree | SessionContextRead in this root session; enter/re-enter the epic worktree | Requirements are IMMUTABLE; never execute on main |
| 2. Execute the Wave | Replace the complete plan to mark one wave in progress → dispatch worker(s) → verify → integrate → report readiness while leaving the wave in progress | Explicit worker role, TDD cycle, worktree-isolate a ≥2 wave |
| 3. Create Next Wave | Prepare complete worker briefs for the checkpoint; defer plan mutation | As wide as pluckability allows; disjoint file sets; reflect reality |
| 4. Durable Checkpoint | Commit → present full checkpoint and next-wave briefs → replace the complete plan to complete this wave | STOP — no exceptions |
Iron Law: One wave → Checkpoint → STOP → Next cycle. No batching (no second wave this cycle). No "just one more." The STOP always happens; whether a human or a goal Stop-hook triggers the next cycle is the only thing that varies (see Execution and continuation).
When to Use
- The same root session contains an approved epic contract, complete worker briefs, and native wave plan ready to execute
- Resuming implementation after a previous checkpoint
- Need to implement features iteratively with human oversight
- After
gambit:brainstorming records the approved contract, first-wave briefs, and native plan in this root session
Don't use when:
- No epic exists → use
gambit:brainstorming
- Debugging a bug → use
gambit:debugging
- Single quick fix → just do it
The Process
0. Resumption Check (Every Invocation)
Run SessionPlanRead and analyze the wave steps:
- Fresh start: Every wave is pending, none is in progress → Step 1
- Resume in-progress: One wave has status
in_progress → Step 2
- Start next: Previous wave completed and the next wave is pending → Step 1 then 2
- All done: Every wave step is completed → Step 5 (final validation)
Do NOT ask "where did we leave off?" — the root session's wave state tells you exactly where to resume.
If native plan state is absent, use SessionContextRead to recover only from this root session's approved contract and latest checkpoint, then reconstruct the complete ordered wave list with SessionPlanWrite. If same-session context is insufficient, or native plan mutation is unavailable, fail closed and ask the user; never recover orchestration state from the repository, another session, a goal, or legacy state.
1. Load Epic Context and Enter the Worktree
Before executing ANY wave, use SessionContextRead to reread the complete approved epic contract from this root transcript.
Extract and keep in mind:
- Requirements (IMMUTABLE — never water these down)
- Success criteria (validation checklist)
- Anti-patterns (FORBIDDEN shortcuts)
- Approaches Considered (what was already REJECTED and why)
- Delivery Constraints (non-convergence and repair circuit breakers)
- Validation Strategy (focused worker command, wave/component gate, release acceptance, freshness, and declared acceptance budget)
Why: Requirements prevent rationalizing shortcuts when implementation gets hard.
For a legacy epic that lacks Delivery Constraints or Validation Strategy, do not guess silently. Before implementation, propose the conservative defaults from this skill — the two-checkpoint convergence circuit breaker, the repair ladder ending in terminal escalation attempts repeated with updated evidence, focused and wave/component commands from repository policy, and one fresh release acceptance run after architecture/scope preflight — then obtain explicit user approval. This records delivery policy without changing immutable product requirements.
Enter the epic worktree. All epic work happens in a worktree — never directly on main. Working on main risks orphaned commits and a corrupted mainline while waves land.
On a fresh start (Step 0 found all wave steps pending):
- Repo convention first. If the repo provides its own worktree setup (an existing
.worktrees/ or worktrees/ directory, a AGENTS.md worktree preference, or project tooling like a just worktree target), follow it: git worktree add <dir>/<epic-slug> -b <branch> and work there.
- Otherwise use standard Git: choose the base revision from the approved epic context, then run
git worktree add <dir>/<epic-slug> -b <branch> <base-ref> and enter that path. Do not assume a backend-owned worktree directory or hook setting.
Then prepare it: run the project's dependency setup (match the tooling — npm install, cargo build, direnv allow/devenv, etc.), and run the declared wave/component gate once to pin the baseline. Report baseline failures before dispatching any wave — you can't distinguish new breakage from inherited breakage without this. Do not spend release acceptance merely to establish a baseline unless the approved Validation Strategy explicitly budgets that run.
On resume: if the session is already in the epic's worktree, continue. Otherwise locate the existing path with git worktree list and enter it directly; if it no longer exists, recreate it through the repository convention or git worktree add. Never dispatch a wave from main.
The transient per-worker worktrees of a ≥2 wave (references/wave-dispatch.md) fork off THIS worktree's HEAD — they are orchestrator-managed and separate from the epic workspace.
2. Execute the Wave
Find and claim the wave:
SessionPlanRead → identify the next pending wave step. Its workers have pairwise-disjoint file sets and no cross-dependency — usually one worker, sometimes several. Overlapping or dependent work waits for a later wave.
SessionContextRead → load every worker's complete self-contained brief from this root transcript or latest checkpoint. Individual worker state comes from native subagent threads and checkpoint results, never plan records.
SessionPlanWrite → replace the complete ordered plan, preserving every other step and marking only that single wave in_progress. At most one wave may be in progress.
Investigate first if needed — reach for a scout. Before constructing the worker brief, if you need to locate code, confirm an interface, or gather cross-task context, dispatch the read-only scout class — don't read around inline or spawn a bare generic agent. This is optional per task; skip it when the brief is already clear.
Glob **/codex-contracts/scout.md, dispatch the scout role using explorer, and prompt it to Read codex-contracts/scout.md first, then ask the bounded question.
The scout returns file:line evidence or NOT FOUND — never a guess.
Settle architecture before dispatching. A worker implements; it does not decide cross-file design. If a task carries an unresolved architectural question, resolve it first — scout it, record the decision in the brief, or decompose the task — then dispatch. A design question tangled into an implementation task is what produces same-pass-TDD drift.
Apply the declared validation ladder. The focused worker command proves the worker-owned behavior during TDD. The wave/component gate proves the integrated wave once. Release acceptance proves the final system claim on fresh artifacts within the approved budget. Release acceptance is not a per-worker or per-wave default; run it early only when the contract budgets a diagnostic run that answers a named system-level question.
Answer the user before you dispatch. When the user asks a direct question mid-epic, answer it in prose before or alongside your next action. A dispatch, a task update, or a checkpoint summary is never a substitute for the answer. Deferring a question to "keep the loop moving" is the drift, not the discipline; if you can't answer, say so plainly rather than fabricating (e.g. per-worker token cost isn't surfaced to you — point the user at the session telemetry, don't guess a number).
Dispatch the wave to workers:
The ready work is a wave — one or more ready tasks whose file sets are pairwise disjoint and that have no semantic dependency on each other (a task needing another's output belongs in a later wave). One cycle dispatches one wave. The orchestrator does not write implementation code in the main context — it dispatches a fresh default worker per task and stays a coordinator: it plans, verifies, integrates, and checkpoints while a cheaper, faster model does the mechanical work. Every worker is governed by the shared codex-contracts/worker.md — blast-radius confinement, TDD with RED/GREEN evidence, fail-fast Stop Triggers, and a 4-state return.
- Single-task wave → dispatch one worker; it works directly in the epic's working tree.
- Wave of ≥2 → run each worker in its OWN isolated worktree so their tests, lints, and builds cannot interfere; give every brief exact
## Files owned, ## Hidden shared surfaces, and ## Neighbors allowlists; then use scripts/integrate_wave.py for commit-based atomic integration and one combined wave/component gate. Never let two workers edit the same working tree. Full mechanics: references/wave-dispatch.md — read it whenever a wave has ≥2 tasks.
Resolve the contract path once. Glob **/codex-contracts/worker.md at the start of the epic to get its absolute path and pass that path to the worker — do NOT Read worker.md into your own context, and do NOT hardcode or reuse a stale absolute path from an earlier session (plugin store paths change; re-Glob). The worker reads it in its fresh context (exactly as the review skill passes reviewers/*.md by path); reading it yourself loads ~1.4k tokens into the long-lived orchestrator context on every epic, for nothing. The worker re-reads it on every dispatch, including retries — keep worker.md lean.
-
Resolve the worker role — use worker; for a reasoning escalation use default or an installed escalation profile. See codex-contracts/models.md. Never pin a concrete model in the skill.
-
Dispatch the wave — every worker in a single message (so a ≥2 wave runs concurrently):
SpawnAgent agent_type="worker" task_name="implement_task_subject" fork_turns="none" # Profile-aware: requires hide_spawn_agent_metadata = false and a non-reserved tool_namespace.
message="Read <abs>/codex-contracts/worker.md — that file is your binding worker contract; your FIRST action must be to Read it, then follow it exactly.
## Task
<constructed from the task's Goal + Implementation + Success Criteria, exact values verbatim — never paste session history>
## Files owned
<exact repository-relative path allowlist, including every new/untracked/binary artifact, deletion, mode change, and symlink>
## Hidden shared surfaces
<lockfiles, generated indexes, registries, snapshots, and other implicit collision surfaces checked; `None` only after checking>
## Context
<where this task fits + any cross-task interfaces/decisions the brief can't know>
## Neighbors
<for each concurrent task: its subject + exact Files owned allowlist, all off-limits; or `None (single-task wave)`>
Test command: <the task's focused worker command>.
Workspace: <the worker's own worktree path> on branch <branch>; baseline is <the wave's fork-point SHA — the prior task's commit for a single-task wave, or the shared wave-start HEAD for a ≥2 wave>."
Pass the contract by path and the task as constructed text — never paste your session history into the worker prompt. Optional project briefs: gambit ships no per-language briefs. If a project provides a codex-contracts/<lang>.md for the task's language, add a line telling the worker to read it too — optional, never required; dispatch is fully functional with worker.md alone.
-
Route on the worker's returned status (the contract defines four) through this fixed four-rung worker ladder. Do not skip or reorder a rung; only rung 4 repeats:
- Initial implementation — worker. Use the
worker SpawnAgent dispatch above.
SpawnAgent agent_type="worker" task_name="implement_task_subject" fork_turns="none" # Profile-aware: requires hide_spawn_agent_metadata = false and a non-reserved tool_namespace.
message="<absolute worker contract path directive and complete worker brief>"
- Informed repair — same worker. Give exactly one informed repair turn to the same worker thread and agent configuration with
followup_task. The message MUST add the missing values, cited defect, failing command output, or other actionable evidence; an unchanged retry is forbidden. Require the worker to reread the same contract, repair the existing tree in scope, rerun its focused command, and return exactly one four-state status.
followup_task
target: "<worker task name returned by the initial SpawnAgent>"
message: "Reread <abs>/codex-contracts/worker.md and perform the one informed repair. <new actionable evidence and exact remaining defect>"
- Reasoning escalation — fresh escalation worker. If rung 2 does not produce a verified, quality-clean result, dispatch one fresh
escalation worker in the same worktree. Pass the same contract path and complete original brief plus both prior results and the exact remaining evidence.
SpawnAgent agent_type="escalation" task_name="escalate_task_subject" fork_turns="none" # Profile-aware: requires hide_spawn_agent_metadata = false and a non-reserved tool_namespace.
message="Read <abs>/codex-contracts/worker.md first, then implement the complete original brief in <same worktree>. Prior attempt: <result>. Informed repair: <result>. Remaining evidence: <exact defect or failing output>."
- Terminal escalation — repeated maximum-reasoning workers. If rung 3 does not produce a verified, quality-clean result, dispatch a fresh
escalation-final worker in the same worktree, carrying the bounded history of every prior attempt and the updated remaining evidence. Repeat this rung — never with unchanged evidence — until the result verifies clean.
SpawnAgent agent_type="escalation-final" task_name="escalate_terminal_task_subject" fork_turns="none" # Profile-aware: requires hide_spawn_agent_metadata = false and a non-reserved tool_namespace.
message="Read <abs>/codex-contracts/worker.md first, then implement the complete original brief in <same worktree>. Prior attempts: <bounded summaries with cited excerpts>. Remaining evidence: <exact defect or failing output>."
Route each terminal result within that ladder:
- DONE → verify with FRESH evidence, then run the Checkpoint quality gate below. A verification or quality defect consumes the next unused repair rung.
- DONE_WITH_CONCERNS → accept only a benign observation after verification. Correctness or scope concerns consume the next unused repair rung unless they prove the brief or architecture is wrong. A "bigger behavior change than the brief implied" flag usually means the brief was wrong, not the worker — reread the cited requirement before repairing.
- NEEDS_CONTEXT → add the missing values or decision as the actionable evidence for the next unused repair rung.
- BLOCKED → missing context or insufficient reasoning consumes the next unused repair rung; a brief that is too large is split into later complete worker briefs, while a wrong plan/brief or unsettled architecture STOPs for user input. Do NOT water down requirements.
A defect recurring at a later checkpoint re-enters rung 4 with its recurrence as the new evidence. There is no human rung; the ladder ends only in a verified, quality-clean result. The epic-level negative-convergence circuit breaker still applies.
One of the four statuses is the ONLY signal that advances a task — silence is not one of them. A worker that has not returned DONE / DONE_WITH_CONCERNS / NEEDS_CONTEXT / BLOCKED is still working, even when it looks otherwise. A worker spends a long opening stretch reading, grepping, and reasoning before it writes a single byte — so a flat git status, an unchanged diff across several checks, and an unanswered status ping are indistinguishable from a dead worker but are not one. Worker↔orchestrator messaging also lags: a worker deep in work often does not read its inbox for a while, and its replies can arrive minutes after you'd expect (sometimes crossing your own next message). Do not presume a silent worker is dead, and above all do not spawn a replacement on silence alone — re-dispatching a still-live worker onto its own task and tree manufactures a file collision (two workers editing the same files), the single most expensive and recurrent orchestration mistake. If you genuinely must probe, send one status ping framed as informational ("not a stand-down — where are you?") and wait a full cycle; only a returned BLOCKED/failure, or a process you have confirmed dead by other means, justifies re-dispatch. When a collision does happen anyway, workers detect it (## Neighbors / blast-radius) and stand down cleanly — so before integrating a tree two workers may have touched, confirm it has been stable across a couple of checks (no files changing under you) and rerun its worker-scoped verification. Invoke the manifest's combined wave/component gate only after every tree is stable and accepted. Patience here is not idleness; it is the cheapest thing you will do all epic.
-
Integrate the wave atomically — you are the sole committer. Workers edit; you judge each complete diff before integration. Single-task wave → gate the diff, run its focused worker command, then run the declared wave/component gate once on the integrated epic HEAD and commit at the checkpoint (Step 4a). Wave of ≥2 → after every per-worker quality verdict is clean, create the ordered JSON manifest and run scripts/integrate_wave.py as specified in references/wave-dispatch.md, using the declared wave/component gate as its combined gate. Workers never commit. While a wave runs, scout and brief the next wave rather than idling.
The ≥2-wave transaction is ordered and indivisible:
- Validate inputs. Reject overlapping exact allowlists, verify the epic and all workers at the shared base, and build each complete worker tree through a temporary index without changing the worker's real staged or unstaged state.
- Combine ordered commits. Create one distinct commit object per worker, then cherry-pick them in manifest order on the detached integration worktree.
- Run one combined gate. Run the declared wave/component gate exactly once on the combined detached HEAD and require its worktree to remain fully clean.
- Fast-forward the exact tested head. Revalidate the epic and every worker after the gate, then fast-forward the epic only to that exact passing combined HEAD.
- Clean up only after success. Remove transient worker and integration worktrees only after the exact-head fast-forward succeeds. Validation, conflict, gate, revalidation, or fast-forward failure leaves epic HEAD unmoved and retains every worktree and artifact for inspection.
What you do yourself vs dispatch. Two kinds of task the orchestrator executes directly; everything else is dispatched to a worker:
- Non-code tasks (pure docs, task bookkeeping) — there's no implementation to delegate.
- Aesthetic-judgment tasks (visual design, layout, typography, art direction — success is does it look right, not a functional spec) — the ONE code exception to dispatch, because visual taste is the orchestrator's strength and a worker's weakness. Exact-spec mechanical markup is NOT this exception — dispatch that normally.
Everything else is worker work — including operational work: live-run debugging, timeout/retry tuning, incident chasing, and log-driven fixes are code changes; dispatch them (a reproducing test first — the worker's TDD loop, or gambit:debugging), never absorb them into your own context because "you're already in the logs." Read-only investigation (tailing logs, a scout, forming a hypothesis) is fine; the moment you edit source to fix it, that's a worker's job.
Verify visual work by looking. However the code was produced — self-implemented or dispatched — an aesthetic or visual task is not done until you have seen it rendered: build → screenshot at desktop + mobile widths (+ reduced-motion where it matters) → judge the pixels against the brief. Reading the diff cannot tell you whether it looks right. Full loop: references/visual-verification.md.
Execute the steps in the task description:
For a delegated task the worker runs this loop in its own context under codex-contracts/worker.md; for a non-code task you run it directly. Commits happen only at the checkpoint (Step 4a) — the worker never commits. For each step:
- Follow the TDD cycle: write test → watch it FAIL → write minimal code → watch it PASS → refactor
- Iron law: no production code without a failing test first. Wrote code before the test? Delete it. Start over. Don't keep it as "reference."
- If test passes immediately, STOP — test doesn't catch the new behavior. Fix the test.
- GREEN means minimal: no features the test doesn't exercise, no error handling it doesn't check.
- Run verifications exactly as specified
Pre-completion verification (FRESH evidence required):
- All steps in description completed?
- Tests passing? Run each worker's complete focused command. Then run the declared wave/component gate exactly once on the integrated wave; for a wave of ≥2 that is the manifest gate, never a per-worker rerun.
- Read complete output, check pass/fail counts and exit code
- Changes committed?
- State claim WITH evidence: "Tests pass. [Ran: X, Output: Y/Y passed, exit 0]"
Checkpoint quality gate (judge the diff, not just the tests)
A green test is necessary but NOT sufficient. Before marking the task complete, read the worker's complete change set — NUL-safe git status, staged and unstaged diffs, and every untracked/binary artifact named in Files owned — and judge it. Ordinary git diff alone is incomplete. The integrator later exposes a staged --binary --full-index diff for the durable record. The orchestrator does this ITSELF in the common case (no dispatch): it is the most capable model in the loop and is reviewing a worker's code, not its own.
Judge the diff against six sources:
- The epic's Quality Bar (
SessionContextRead the epic) — gambit's fixed maximal standard for good code, carried verbatim in every epic.
- The epic's Anti-Patterns — none present in the diff.
- The worker quality policy (
codex-contracts/worker.md) — no linter/type suppression pragmas (noqa, ts-ignore, nolint, disabled rules), no weakened or tautological tests, no dead or commented-out code left behind, errors handled at the call site.
- Blast radius — the diff touches only what the task required; no scope creep, no "while I was here" edits. (Exception: mechanical fallout of a correct change that breaks the shared gate — regenerated fixtures/goldens, a cross-package test that must update — is in-scope to repair; the worker reports it, you authorize it, and it is not scope creep.)