Loops
Loops let the agent execute an arbitrary task as a structured execution path — an ordered set of named steps that the agent traverses, deciding when to loop back, advance, or stop based on outcomes.
Unlike a fixed pipeline, loops are agent-driven: the agent calls tools to jump between steps, swap agents mid-flow, and stop when done. This makes them a better way to execute repeatable workflows like read → build → test → review → report where the agent may need to loop back (build → test → build → test → review → stop).
Enable
Loops is a builtin plugin, disabled by default. Enable it in your config:
{
"builtin": { "loops": { "enabled": true } }
}
The server also exposes endpoints: GET /builtin, POST /builtin/:name/enable, POST /builtin/:name/disable.
Configuration
{
"loops": {
"compaction_threshold": 0.5,
"compaction_model": "anthropic/claude-opus-4-8",
"definitions": {
"fix-bug": {
"description": "Read, build, test, review, report",
"steps": [
{
"name": "read",
"agent": "plan",
"prompt": "Read and understand the task."
},
{ "name": "build", "prompt": "Implement the change." },
{
"name": "test",
"prompt": "Run the tests. If failing, call loop_next({ step: 'build' }) with the reason."
},
{
"name": "review",
"review": true,
"prompt": "Review the change for correctness and security."
},
{
"name": "report",
"agent": "TF Engineer",
"prompt": "Report the outcome."
}
]
}
},
"auto": ["fix-bug"]
}
}
Top-level
| Field | Default | Description |
|---|---|---|
compaction_threshold | 0.5 | Compact between steps when context usage exceeds this ratio (0–1). |
compaction_model | — | Model for compaction (defaults to the session's active model). |
max_step_repeats | 3 | Max times a single step can be visited before the loop pauses (doom-loop guard). 0 disables. |
max_transitions | 20 | Hard cap on total step transitions. The loop pauses when exceeded. 0 disables. |
definitions | — | Named loop workflows keyed by id. |
auto | — | Loop ids to auto-start on non-interactive sessions (requires --auto-loops). |
Step
| Field | Description |
|---|---|
name | Unique step id the agent references in loop_next. |
prompt | Task prompt for this step. |
agent | Agent for this step (build, plan, TF Engineer, …). |
skill | Skill/command name whose content is inlined into this step's prompt. |
review | Nudges the agent to call the reviewer tool during this step. |
model | (phase 2) Swap to this model for this step. |
Tools
When a loop is active, two tools are registered:
loop_next
Jump to any named step (forward or backward). Optionally swap to a different agent for the next step — enabling multi-agent workflows.
loop_next({ step: "build" })
loop_next({ step: "review", agent: "TF Engineer", reason: "needs security review" })
If the agent does not call loop_next, the loop auto-advances to the next step in order.
loop_done
Stop the loop early when the goal is satisfied.
loop_done({ reason: "all tests pass and review approved" })
When the last step completes with no loop_next, the loop finishes automatically.
Multi-agent workflows
Each transition can hand off to a different agent. There are two ways to control which agent runs a step:
- Static — set
agenton the step definition. - Dynamic — pass
agenttoloop_nextat runtime to override the step's configured agent.
This lets the agent decide mid-flow which agent is best for the next step.
Backward jumps
The agent can jump back to any earlier step when it discovers a root-cause issue. For example, at step test the agent might realize the plan from read was incorrect:
loop_next({ step: "read", reason: "plan was incorrect — need to re-read the spec" })
The system prompt guides the agent to:
- Jump back and fix the root cause rather than patching around it in the current step.
- Provide a
reasonexplaining why it's jumping back (for audit history).
Doom-loop prevention
If a step keeps failing and the agent loops back repeatedly, the loop auto-pauses to prevent infinite cycles. Two configurable guards:
max_step_repeats(default3) — if a single step is visited more than this many times, the loop pauses with a doom-loop message.max_transitions(default20) — if total transitions across all steps exceed this, the loop pauses.
Both can be set to 0 to disable the guard entirely (not recommended).
When a doom loop is detected:
- The loop pauses (not stops) — the state is preserved.
/loops statusshows which step triggered the pause and how many times it was visited./loops resumerestarts the loop from the paused step. The agent should try a different approach.- The
loop_nexttool returns a warning when a step is approaching its visit limit, nudging the agent to try a different approach or callloop_doneif stuck.
The system prompt also instructs the agent to call loop_done with a reason if it's stuck, and to use the reviewer tool for a fresh perspective on why a step keeps failing.
Reviewer, model_swap, and skills
Within any step, the agent can use:
- reviewer — get a second opinion from a stronger model (architecture, security, performance, correctness).
- model_swap — switch to a different model mid-step when the task calls for different capabilities or cost.
- skill — load any available guided workflow at runtime.
The review step field nudges the agent to call the reviewer. The skill step field inlines a skill's content into the step prompt.
Compaction
Between steps, if context usage exceeds compaction_threshold (default 50%), the loop automatically compacts the session to preserve context. This keeps long loops running without hitting context limits.
Commands
| Command | Description |
|---|---|
/loops run <name> | Start a loop workflow |
/loops status | Show current loop state and history |
/loops list | List available loops from config |
/loops pause | Pause the active loop |
/loops resume | Resume a paused loop |
/loops clear | Stop and remove the active loop |
Auto-start
To auto-start a loop on non-interactive sessions (e.g. tfcode run), add loop ids to auto and pass --auto-loops:
tfcode run --auto-loops "Process the queue"
Or set the environment variable:
export OPENCODE_AUTO_LOOPS=true
Auto-start never applies to interactive TUI sessions — use /loops run <name> there. State is persisted to ~/.tfcode/loops-plugin/state.json and recovered as paused on restart.
Skill
Loops ships with a loops skill that documents the loop_next/loop_done contract and transition patterns. The agent can invoke it via the skill tool, or you can reference it in a step with "skill": "loops".