| name | forge:loop |
| hidden | true |
| description | Use when work needs an explicit delivery contract, iterative repair, bounded autonomy, or resume-safe state |
Closed-Loop Delivery
Overview
Forge loop turns a request into a bounded engineering cycle with explicit state.
Core principle: a loop is not "keep trying". A loop has a contract, evidence,
budget, checkpoints, and stop conditions.
Loops are autonomous by default. They should keep moving unless an owner-only decision or a real external blocker makes safe continuation impossible.
When To Start A Loop
Start forge:loop when ANY are true:
- the task has 2+ steps, 2+ files, or cross-module effects
- success depends on multiple commands, reviews, or gates
- requirements need an explicit acceptance rubric
- verification may fail and require another pass
- subagents will be used for execution or review
- the user asks for end-to-end delivery, hardening, or best-practice implementation
Do not start a loop when ALL are true:
- trivial single-file wording or formatting change only
- one focused verification command is enough
- the user explicitly wants analysis or planning only
If unsure, start the loop and downgrade explicitly.
Loop Contract
Before execution, establish this contract in your working context and persist it with
forge-check for non-trivial work:
Goal: <user outcome>
Scope:
- <what this iteration may change>
Non-goals:
- <what this iteration will not change>
Rubric:
- [ ] <objective acceptance criterion>
- [ ] <constraint, risk gate, or non-goal>
Budget:
- max_fix_iterations: 3
- used_fix_iterations: 0
- remaining_fix_iterations: 3
Stop conditions: pass | blocked | budget_exhausted | owner_decision_required
Rubric items must be verifiable by command output, file evidence, reviewer verdicts,
screenshots, logs, or explicit owner approval.
When the loop contract is established, record forge-event event="forge.loop.started" with the goal, mode, and current stage. Keep full rubric details in forge-check, not in event metadata.
Forge Goal Compatibility
Forge may select an outer Goal route when the user requests bounded autonomous
advancement or the task's safe complexity warrants multiple milestones. Goal is
not a new OpenCode agent mode and must reuse this Loop contract:
- Persist
mode: loop and the existing current_stage values (discover, plan,
execute, verify, iterate, ship).
- Add optional
route: goal, autonomy_policy, and max_goal_steps fields to the
structured checkpoint details when the outer Goal policy must survive a resume.
- Keep
max_fix_iterations for verification repair; max_goal_steps bounds
milestone advancement and must never imply unbounded background execution.
- Do not write
mode: goal or current_stage: goal; those values are not part of
the OpenCode/Forge Loop checkpoint schema.
- Goal still uses the same Reviewer,
forge:verify, strategy-change, and stop
conditions defined below.
Approval-First Loop Entry
When the user asks for route selection, a loop contract, or approval before any modification:
- gather only the smallest evidence needed to justify the route and contract
- output the route, why not the lighter route when relevant, the loop contract, and one highest-priority owner decision
- stop and wait for approval
- defer full discovery, planning, dispatch, and execution until approval is granted, unless no user is available and
forge:ask rules allow autonomous continuation
This applies even when the truthful route is clearly Loop.
The Loop
- Goal — restate the requested outcome and boundary.
- Scope / non-goals — prevent scope creep up front.
- Rubric — define the acceptance gate before implementation.
- Discover — after contract approval, call
skill("forge:discovery") for non-trivial work, or record why it was skipped.
- Plan — call
skill("forge:plan") when multiple tasks or milestones exist.
- Execute — call
skill("forge:subagent"), skill("forge:tdd"), skill("forge:debug"), or direct work for trivial cases.
- Review — after every implementation task, dispatch
Reviewer subagent (and Guard for security work). Fix issues found. Re-review until clean. Self-review is NOT sufficient.
- Verify — call
skill("forge:verify"); verdict must be pass, fail, or blocked. Evidence from executed commands, not code inspection.
- Iterate or ship —
pass ships; fail creates the next iteration prompt; blocked asks or stops.
Stop Conditions (Exhaustive)
A loop stops ONLY when one of these is true. If none are true, the loop MUST auto-advance to the next task/milestone in the same turn.
| Condition | Action |
|---|
All rubric items pass (ship-ready) | Ship → report → merge → reflect |
Fix budget exhausted (used >= max) | Stop thrashing → forge:ask or budget_exhausted → reflect |
| External blocker (missing dep, permission, env) | forge:ask with concrete blocker + options |
| Irreversible owner-only decision required | forge:ask with the single highest-priority decision |
| User pressed Esc / aborted | Pause — wait for user direction |
NOT a stop condition:
- Task/milestone completed, next one exists → auto-advance
- Unverified items remain but no failure → state as residual risk, continue
- "Should I verify?" → just verify, don't ask
- "Should I start the next task?" → just start it
- Loop is long → budget handles this, not asking
If no user is available, all forge:ask stop conditions resolve to: pick the smallest safe in-scope option, record the assumption, and continue.
Failure Handling Rules
When verification fails:
- Increment
used_fix_iterations.
- Convert failed rubric items into the next implementation prompt.
- Preserve already-passing rubric items.
- Change at least one variable: prompt, context, task split, subagent, implementation strategy, or verification path.
- Record
forge-event event="forge.strategy.changed" with the changed variable and short reason.
- Record
forge-event event="forge.iteration.started" for the new pass.
- Re-run verification after the fix.
Do not repeat the same failed strategy with the same evidence.
If used_fix_iterations >= max_fix_iterations:
- do not keep thrashing
- use
forge:ask, downgrade scope, or stop with budget_exhausted
- invoke
forge:reflect when the loop closes
Brainstorm Boundary
- If open design space materially changes implementation direction, converge it through
forge:brainstorm before execute.
forge:ask is a decision protocol, not an automatic human-blocking pause. If no owner is available and the choice is reversible, in-scope, and low-risk, choose the smallest safe option, record it in the contract/checkpoint, and continue.
- Escalate to
owner_decision_required only for irreversible, high-risk, or out-of-scope decisions that cannot be safely auto-resolved.
- If requirements are already clear enough to define a truthful rubric, derive the rubric directly and keep the loop moving.
- Do not let pre-approval discovery grow into implementation-level analysis. Before approval, discovery only exists to support route truthfulness, contract truthfulness, and the immediate decision checkpoint.
Memory Checkpoints
forge-check is the durable loop memory. Use it at minimum for:
loop-start — when the contract is established
discovery-complete — after forge:discovery finishes (update current_stage: plan)
plan-complete — after forge:plan finishes (update current_stage: execute)
- every
verify-failed — with failure evidence and strategy change
- every major
iteration-N — with updated rubric statuses
ship-ready — when all rubric items pass
At the same stage transitions, emit concise forge-event entries: forge.loop.started, forge.iteration.started, forge.blocked, or forge.ship.ready. forge-check stores state; forge-event stores the timeline.
Critical: Always update current_stage in the checkpoint JSON when transitioning between discover → plan → execute → verify → ship. The TUI sidebar reads current_stage to show real-time progress. If you only write loop-start and never update current_stage, the sidebar will appear stuck at the initial stage even while work is progressing.
Checkpoint schema:
{
"stage": "loop-start | iteration-N | verify-failed | ship-ready",
"mode": "direct-downgraded | structured | loop",
"goal": "<user outcome>",
"scope": ["<allowed change area>"],
"non_goals": ["<not changing>"],
"rubric": [
{
"id": "R1",
"text": "<criterion>",
"status": "pending | pass | fail | blocked | out-of-scope",
"evidence": "<command/reviewer/file:line>"
}
],
"discovery": {
"depth": "D0 | D1 | D2",
"files": ["<path>"],
"impact_surface": ["<caller/contract/test/doc>"],
"risk": "low | medium | high"
},
"budget": {
"max_fix_iterations": 3,
"used_fix_iterations": 0,
"remaining_fix_iterations": 3
},
"current_stage": "discover | plan | execute | verify | iterate | ship",
"current_task": "<what is being done now>",
"next_action": "ship | iterate | ask | block | downgrade",
"last_failure": "<why the previous pass failed>",
"strategy_change": "<what changed this pass>",
"blockers": ["<reason>"],
"residual_risks": ["<risk>"]
}
Do not rely on chat memory for any field another session will need.
Project-Visible Trace (Loop Trace)
forge-check is the engine-internal state. The project-visible trace lives in
the plan file's ## Loop Trace section (see forge:plan's "Living Plan Document"
contract). Write one line to the plan file at every stage transition:
loop-start — when the loop contract is established (before any execution)
iteration-N — when a verify fails and a new strategy pass begins (include the
failure reason and the strategy change)
verify-failed — same as iteration-N if you prefer this label
ship-ready — when the rubric passes (include residual risks)
Format:
- <ISO-8601 timestamp> — <stage> — <one-line summary>
Why both forge-check and the plan trace:
forge-check (home dir, JSON) is for cross-session engine resume.
- Plan
## Loop Trace (project, markdown, committed) is for auditability and
forge:reflect.
If the plan file is missing or read-only, fall back to forge-check only and state
the gap in your report.
Resume Protocol
If the user asks to continue or resume:
- call
forge:resume
- reconstruct goal, rubric, budget, blockers, and next action from
forge-check
- continue from
next_action
- only re-run discovery or planning if the checkpoint is stale or missing required state
Iteration Prompt Pattern
Write iteration prompts from evidence, not vibes:
Continue the loop for <goal>.
Failed rubric items:
- <item> — evidence: <command/reviewer/file output>
Preserve:
- <already passing items>
Constraints:
- stay within <scope>
- do not expand beyond <non-goals>
Strategy change this pass:
- <what is different now>
Required verification:
- <commands/review checks>
Common Mistakes
| Mistake | Fix |
|---|
| Starting implementation without a rubric | Define the loop contract first |
| Treating tests as the whole gate | Include requirements, review, and risk criteria |
| Asking "should I continue?" after a fail | Iterate automatically unless blocked |
| Repeating the same fix attempt | Change strategy based on failure evidence |
| Keeping state only in chat | Write forge-check checkpoints |
| Letting the loop run forever | Enforce budget and stop conditions |
Relationship To Other Skills
- Before loop:
skill("forge:brainstorm") when requirements are ambiguous
- Inside loop:
skill("forge:discovery"), skill("forge:plan"), skill("forge:subagent"), skill("forge:tdd"), skill("forge:debug"), skill("forge:review"), skill("forge:parallel")
- Loop gate:
skill("forge:verify")
- After close:
skill("forge:report"), skill("forge:merge"), skill("forge:reflect")
If another skill has a stricter rule, follow the stricter rule.