loop.md
August 22, 2026 ยท View on GitHub
Objective or action:
$ARGUMENTS
Run a manual, resumable engineering loop for work with mechanical validation. This command does not schedule recurring runs or turn the task into unattended automation.
Verifiable invariants
approval_gate: explicit_before_writes
max_iterations_per_invocation: 3
planned_iteration_budget: task_specific_1_to_6
hard_safety_ceiling: 6
completion_authority: reviewer_only
canonical_review_policy: code-review-and-quality/references/review-policy.md
final_review_authority: reviewer
canonical_state_path: .opencode/loops/<slug>.json
history_path: .opencode/loops/<slug>.history.jsonl
lock_path: .opencode/loops/<slug>.lock
human_view_path: .opencode/loops/<slug>.md
worktree_mode: explicit_opt_in
The three-iteration value limits one invocation. The persisted
planned_iteration_budget (planned_iterations in canonical state) is the total budget for the mission and may not
exceed the hard ceiling of six; current_iteration may never exceed that
budget. Once the total budget is exhausted, the loop must stop as blocked or
completed rather than injecting another continuation.
The durable handoff_packet (.opencode/handoffs/<slug>.md with
approval_status) persists human approval to survive session restarts. /loop
keeps .opencode/loops/<slug>.json as canonical state,
.opencode/loops/<slug>.history.jsonl as append-only history, and
.opencode/loops/<slug>.md as the human view. See
docs/ai/harness/agents.md section "Durable /loop state".
Each iteration follows:
developer -> reviewer -> developer (state sync)
Interface
/loop <objective>designs a new loop./loop resume <slug>inspects canonical state before the gate and acquires the durable lock only after explicit approval.- Enable a worktree only when the user explicitly includes
worktreein the arguments or requests it at the approval gate. Otherwise work sequentially in the current checkout. - Every invocation, including a resume, opens a new block of at most three iterations.
Phase 1: preflight and Loop Contract
Before any write or handoff to developer:
- Read
AGENTS.md,PROJECT_CONTEXT.md, ordocs/ai/project-context.mdwhen present, plus git state and the minimum relevant repository documentation. - For resume, run only
node scripts/loop-state.mjs inspectand read the requested Markdown. If state is missing or corrupt, stop; do not silently repair or replace it.inspectis read-only and does not acquire the lock. - Identify pre-existing local changes and mark them protected. If the loop must touch an already modified path, stop and request a human decision.
- Load
autonomous-loopsto design bounds andverification-loopto define evidence, usingdocs/ai/harness/skill_registry.mdwhen present. - Present a
Loop Contractcontaining:- slug and one-sentence objective;
- observable success criteria;
- scope and non-goals;
- allowed areas and protected pre-existing changes;
- validation commands and any necessary baseline result;
- risks, denylist, and escalation triggers;
current_checkoutorworktree_explicitexecution mode;- the three-iteration limit and stop conditions.
- Request explicit human approval of the contract and end the turn waiting for
the response. Do not write state, invoke
developer, or modify files before receiving that approval.
If the user rejects or changes the contract, revise the design or finish without
writes. Approval of the original objective is not approval of the concrete
Loop Contract.
Phase 2: initialize state
After approval, delegate only:
- for a new loop, creation or update of
.opencode/loops/<slug>.md, followed bynode scripts/loop-state.mjs initwith git baseline, session, and a uniqueaction_id; - for an approved resume,
node scripts/loop-state.mjs resumewith slug, contract, session, and a newaction_id.
Do not edit those files as lead.
The readable Markdown state must include:
status:approved,running,completed,paused, orblocked;- objective, success criteria, scope, non-goals, and denylist;
- execution mode and git baseline;
- protected pre-existing changes;
- validation commands;
- block number, current iteration, and maximum of three;
- per-iteration change, files, commands, results, and evidence;
- latest reviewer verdict and next action;
- human decisions and termination reason.
The project may version or ignore the state according to its own rules. Do not
modify .gitignore unless explicitly requested.
JSON is the source of truth for schema version, approved contract hash, git
baseline, session, approval, lease, status, iteration, last completed step,
blocking cause, and last action ID. Record every transition with
node scripts/loop-state.mjs record. Repeating identical content with the same
action_id is idempotent; reusing it for different content is an error.
Transitions from the same session are serialized inside the durable lock. A
retry succeeds only when journal, snapshot, and locks prove a complete commit;
otherwise it returns recovery_required.
Phase 3: bounded cycle
For each available iteration:
- Send
developera self-contained handoff with the approved contract, state, protected changes, one next action, and expected validation. developermakes one focused change, runs reasonable validation, and records evidence in state. It cannot expand scope or declare the objective complete.- Send the diff, contract, and Verification Envelope to
reviewer. reviewerreturnsreview_stage: finaland exactlypass,pass_with_observations,needs_changes, orblocked, with causality, evidence, and an assessment of every success criterion.- Delegate only verdict/state synchronization back to
developer. This administrative write does not consume an iteration and cannot include implementation changes. It updates the Markdown view and records the canonical transition with a newaction_id. - On
needs_changes, make the blocking findings the only next action. Onblocked, pause immediately. - Mark
completedonly when every criterion passes andreviewerreturnspassorpass_with_observations. If runtime state requires historicalAPPROVE, record it only as a translation of either successful canonical verdict. Adevelopercompletion claim is never sufficient.
Stop conditions
Stop, synchronize state, and provide a human handoff when any condition occurs:
- objective completed with final
passorpass_with_observations; - three iterations consumed in the invocation;
- two consecutive iterations without observable progress;
- approved scope must expand;
- required validation cannot be run or interpreted;
- overlap with pre-existing local changes;
- a third attempt on the same failure;
- any change to
.env, secrets, credentials, authentication, authorization, payments, billing, PII, migrations, Terraform, Kubernetes, or production.
For sensitive paths use blocked or paused; never create a silent exception.
First-version boundaries
- No auto-merge.
- No schedules or recurring cadence.
- No write-enabled MCP connectors.
- No parallel execution.
- No implicit worktree creation.
- No new dependencies, agents, or skills.
Recovery and repair
- An interrupted write can leave the journal ahead of the snapshot. Run
node scripts/loop-state.mjs repairto rebuild JSON from the latest complete event. - Repair validates continuity of slug, contract, baseline, approval, iteration,
and lease before trusting
state_after. --truncate-tailremoves only an incomplete final JSON line; middle corruption is rejected.repairrefuses an active lock unless--release-lockexplicitly authorizes releasing an abandoned lock. There is no automatic timeout unlock.migrateconverts schema v0 or Markdown-only state to schema v1 only with--approval-status approved; old approval is never inherited.- On pause or closure, run
releasewith the owning session and a newaction_id.
Closure
Always report the slug, JSON/JSONL/Markdown paths, status, iterations used,
changes, validation, latest verdict, stop reason, risks, and next human
decision. Distinguish pass, fail, and not_run; never present not_run as
success.