Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/coleam00/Archon/llms.txt

Use this file to discover all available pages before exploring further.

Loop nodes let a single DAG node run an AI prompt repeatedly until a completion condition is met. Each iteration is a full AI agent session that can read files, write code, run commands, and produce output—giving you autonomous multi-step execution that adapts based on what it finds on disk. This page covers every configuration field, completion signal formats, the $LOOP_PREV_OUTPUT and $LOOP_USER_INPUT variables, and the patterns used in Archon’s own bundled workflows.

Quick start

.archon/workflows/iterate-until-done.yaml
name: iterate-until-done
description: Implement stories from a PRD one at a time

nodes:
  - id: setup
    bash: |
      echo "Branch: $(git branch --show-current)"
      cat .archon/prd.md

  - id: implement
    depends_on: [setup]
    loop:
      prompt: |
        You are in a FRESH session — no memory of previous iterations.

        Setup context:
        $setup.output

        User request: $USER_MESSAGE

        Read the PRD tracking file to find the next unfinished story.
        Implement it, validate, commit, update the tracking file.

        When all stories are done: <promise>COMPLETE</promise>
      until: COMPLETE
      max_iterations: 15
      fresh_context: true

  - id: report
    depends_on: [implement]
    prompt: "Summarize what was implemented: $implement.output"

How it works

A loop node iterates until one of these conditions is met:
  1. LLM completion signal — the AI outputs <promise>SIGNAL</promise> where SIGNAL matches the until value
  2. Deterministic bash check — an optional until_bash script exits with code 0
  3. Max iterations reached — the node fails with a clear error
Between iterations, the executor checks for workflow cancellation. A loop node’s $nodeId.output is the last iteration’s output only—not a concatenation across all iterations.

Configuration fields

- id: my-loop
  loop:
    prompt: "..."            # Required. The prompt sent each iteration.
    until: COMPLETE          # Required. Completion signal string.
    max_iterations: 10       # Required. Hard limit — node fails if exceeded.
    fresh_context: true      # Optional. Default: false.
    until_bash: "bun test"   # Optional. Bash exit 0 = complete.
    interactive: true        # Optional. Pause for user input after each iteration.
    gate_message: "..."      # Required when interactive: true.

prompt

The prompt sent to the AI each iteration. Supports all standard variable substitution plus loop-specific variables:
VariableValue
$ARGUMENTS / $USER_MESSAGEOriginal user message
$ARTIFACTS_DIRWorkflow artifacts directory
$BASE_BRANCHRepository base branch
$WORKFLOW_IDCurrent workflow run ID
$nodeId.outputOutput from upstream (non-loop) nodes
$LOOP_USER_INPUTUser feedback from an interactive gate pause
$LOOP_PREV_OUTPUTCleaned output of the previous loop iteration (empty on first iteration)
$LOOP_PREV_OUTPUT is particularly useful for fresh_context: true loops—the agent has no memory of prior iterations, so injecting the previous iteration’s output lets it focus on what failed and why without carrying the full session history.

until

The completion signal string. The executor checks each iteration’s output for:
  1. Tag format (recommended): <promise>COMPLETE</promise> — case-insensitive, whitespace-tolerant. Prevents false positives from the AI mentioning the signal word in prose.
  2. Plain signal (fallback): The signal at the very end of output (trailing whitespace and punctuation tolerated) or on its own line.
<promise> tags are automatically stripped from output sent to the user and to downstream nodes.

max_iterations

Hard safety limit. If the loop reaches this count without a completion signal, the node fails (not succeeds). Choose based on work scope:
Work typeSuggested range
Simple refinement / fix loop3–5
Multi-story implementation10–15
Long-running autonomous agent15–20

fresh_context

Controls session continuity between iterations:
ValueBehaviorUse when
trueEach iteration starts a fresh AI session. No memory of prior iterations.Work state lives on disk. Prevents context window exhaustion on long loops.
false (default)Sessions thread — each iteration resumes the prior conversation.Iterative refinement where the agent needs to remember what it tried before.
The first iteration is always fresh regardless of this setting.

until_bash

Optional bash script executed after each AI iteration. If it exits with code 0, the loop completes—even if the AI didn’t emit the completion signal:
loop:
  prompt: "Fix the failing tests"
  until: ALL_PASS
  max_iterations: 5
  until_bash: "bun run test"   # Loop ends when tests pass
Useful for deterministic completion criteria: test suites, lint checks, build success. Supports the same variable substitution as prompt.

interactive and gate_message

Set interactive: true to pause the loop between iterations and wait for human input. After each non-completing iteration, the executor:
  1. Sends the gate_message to the user along with the run ID and a /workflow approve command
  2. Pauses the workflow run
  3. Waits for the user to run /workflow approve <id> <feedback>
The user’s feedback is injected into the next iteration’s prompt via $LOOP_USER_INPUT.
Interactive loop nodes require interactive: true at the workflow level as well. If only the loop node has interactive: true, a loader warning is emitted and the workflow will not pause correctly in web background mode.
name: guided-refine
description: Refine output with human review between iterations
interactive: true           # Required at workflow level

nodes:
  - id: refine
    loop:
      prompt: |
        Review the current draft and improve it based on this feedback: $LOOP_USER_INPUT
        When the output is satisfactory: <promise>DONE</promise>
      until: DONE
      max_iterations: 5
      interactive: true
      gate_message: "Review the output above. Provide feedback or type DONE to finish."

Patterns

Stateless agent (Ralph pattern)

Each iteration reads state from disk, does one unit of work, writes state back. The prompt explicitly tells the agent it has no memory:
- id: implement
  depends_on: [setup]
  idle_timeout: 600000
  loop:
    prompt: |
      You are in a FRESH session — no memory of previous iterations.

      Project context:
      $setup.output

      Read the plan at `$ARTIFACTS_DIR/plan.md`.
      Read the progress tracking at `$ARTIFACTS_DIR/progress.txt`.

      Identify the next incomplete task. Implement it, validate with
      `bun run validate`, commit, update progress tracking.

      When ALL tasks are complete: <promise>COMPLETE</promise>
    until: COMPLETE
    max_iterations: 15
    fresh_context: true
When to use: Multi-story implementation, long-running tasks where context window exhaustion is a risk. The agent reads tracking files to know what’s done and what’s next.

Retry-on-failure with $LOOP_PREV_OUTPUT

When fresh_context: true is needed but the agent benefits from knowing what the previous pass said—typical of implement→validate or generate→review loops:
- id: implement-and-qa
  loop:
    prompt: |
      Implement the plan, then run `bun run validate`.
      Fix any failures.

      Previous iteration output (empty on first pass):
      $LOOP_PREV_OUTPUT

      Use the above to focus your fixes. When all checks pass:
      <promise>QA_PASS</promise>
    until: QA_PASS
    fresh_context: true
    max_iterations: 3
On the first iteration, $LOOP_PREV_OUTPUT is an empty string. Iterations 2+ receive the previous iteration’s cleaned output (with <promise> tags stripped).

Accumulating context

For iterative refinement where the agent needs to remember what it tried before:
- id: refine
  loop:
    prompt: |
      Review the current implementation and improve it.
      Run validation after each change.
      When validation passes with zero issues: <promise>DONE</promise>
    until: DONE
    max_iterations: 5
    fresh_context: false   # Sessions thread — agent remembers prior iterations
When to use: Fix-iterate cycles, design refinement, TDD cycles.

Deterministic exit with until_bash

Combine LLM work with a deterministic completion check to prevent false claims of completion:
- id: fix-tests
  loop:
    prompt: |
      Run the test suite. Read the failures. Fix them one at a time.
      If all tests pass: <promise>TESTS_PASS</promise>
    until: TESTS_PASS
    max_iterations: 8
    until_bash: "bun run test"   # Ends loop when tests actually pass
    fresh_context: false
The loop ends when either the AI signals completion or the bash check exits 0—whichever comes first.

Interactive PIV loop (from bundled archon-piv-loop)

The bundled archon-piv-loop workflow uses interactive loops for explore, plan refinement, and validation phases. Here is the explore phase:
.archon/workflows/defaults/archon-piv-loop.yaml
name: archon-piv-loop
interactive: true            # Required for interactive loops in web

nodes:
  - id: explore
    loop:
      prompt: |
        **User's request**: $ARGUMENTS
        **User's latest input**: $LOOP_USER_INPUT

        [Exploration instructions...]

        NEVER emit <promise>PLAN_READY</promise> unless the user's LATEST
        message contains an EXPLICIT phrase like "ready", "create the plan",
        "let's go", or "proceed".
      until: PLAN_READY
      max_iterations: 15
      interactive: true
      gate_message: |
        Answer the questions above, ask me to explore specific areas,
        or say "ready" when you're satisfied with the exploration.

  - id: create-plan
    model: sonnet
    depends_on: [explore]
    context: fresh
    prompt: |
      Create a structured implementation plan from the exploration.
      Final exploration summary: $explore.output
      [...]

  - id: refine-plan
    depends_on: [create-plan]
    loop:
      prompt: |
        **User's feedback**: $LOOP_USER_INPUT
        [Plan refinement instructions...]
        If user EXPLICITLY approved: <promise>PLAN_APPROVED</promise>
      until: PLAN_APPROVED
      max_iterations: 10
      interactive: true
      gate_message: |
        Review the plan. Provide feedback or say "approved" to begin implementation.

Implementation loop with $implement-setup.output

From the same PIV workflow, the implementation phase shows how to pass upstream bash node output into a fresh-context loop:
- id: implement-setup
  depends_on: [refine-plan]
  bash: |
    echo "BRANCH=$(git branch --show-current)"
    echo "PLAN_FILE=$ARTIFACTS_DIR/plan.md"
    cat "$ARTIFACTS_DIR/plan.md"

- id: implement
  depends_on: [implement-setup]
  idle_timeout: 600000
  model: claude-opus-4-6[1m]
  loop:
    prompt: |
      You are an autonomous coding agent in a FRESH session.
      Your job: Read the plan, implement ONE task, validate, commit, exit.

      Setup context:
      $implement-setup.output

      Re-read the plan file from disk (path is in the context above).
      Find the next incomplete task. Implement, validate, commit, update progress.

      When ALL tasks are complete: <promise>COMPLETE</promise>
    until: COMPLETE
    max_iterations: 15
    fresh_context: true

What is NOT supported on loop nodes

These fields are silently discarded at parse time with a loader warning. retry: is the exception—it causes a hard load error and the workflow will not load.
Unsupported fieldNotes
retryRejected at parse time — workflow fails to load
context: freshSilently ignored — use fresh_context inside the loop: config instead
hooksPer-node SDK hooks not passed through to iterations
mcpPer-node MCP server configs not loaded for loop iterations
skillsSkill preloading not applied to loop iterations
allowed_tools / denied_toolsTool restrictions not enforced on loop iterations
output_formatStructured JSON output not supported
provider and model are accepted and forwarded to the loop executor—they set the provider/model for each iteration. If you need hooks, MCP, skills, or tool restrictions, use a command: node that wraps the iterative logic in a command file.

Output and data flow

A loop node’s $nodeId.output is the last iteration’s output only—not a concatenation of all iterations. To accumulate results across iterations, write them to files in $ARTIFACTS_DIR and have the downstream node read from there:
- id: implement
  loop:
    prompt: |
      [...]
      After each task, append to `$ARTIFACTS_DIR/progress.txt`.
      When done: <promise>COMPLETE</promise>
    until: COMPLETE
    max_iterations: 15
    fresh_context: true

- id: summarize
  depends_on: [implement]
  bash: "cat $ARTIFACTS_DIR/progress.txt"  # Read accumulated results

Error handling

ScenarioBehavior
Iteration throws an errorNode fails immediately — no more iterations
Max iterations exceededNode fails with descriptive error
Workflow cancelledDetected between iterations — node stops cleanly
idle_timeout reached during iterationIteration completes with whatever output was collected; loop continues
retry: set on loop nodeWorkflow fails to load at parse time

Interactive loop vs approval with on_reject

Both primitives handle human-in-the-loop iteration. Choose based on your pattern:
Interactive loopApproval + on_reject
YAML keyloop.interactive: trueapproval.on_reject: { prompt }
User input variable$LOOP_USER_INPUT$REJECTION_REASON
Best forConversational iteration — explore, refine, review cyclesGate-then-fix — approve to proceed, or reject to trigger a specific corrective action
Completion signalAI detects user intent in outputUser explicitly approves or rejects via button/command
Rule of thumb: If the human and AI are having a conversation (exploring, refining, iterating), use an interactive loop. If the workflow should proceed unless the human objects, use an approval gate with on_reject.

Authoring Workflows

Full workflow YAML reference including DAG, conditions, and retry.

Approval Nodes

Human-in-the-loop gates with approve/reject and on_reject rework.

Variable Reference

Complete list including $LOOP_USER_INPUT, $LOOP_PREV_OUTPUT, and $REJECTION_REASON.

Workflow Schema

Full YAML schema including loopNodeConfigSchema.

Build docs developers (and LLMs) love