fabro/docs/tutorials/branch-loop.mdx
Bryan Helmkamp 131b71aea9 Update docs tutorials, examples, and add sub-workflow tutorial
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 10:01:53 -05:00

130 lines
4.5 KiB
Text

---
title: "Branch & Loop"
description: "Conditionals, test validation loops, and max_visits"
---
This tutorial builds an implement-test-fix loop — the agent writes code, runs tests, and if they fail, fixes the code and tries again. No human intervention needed.
## The workflow
<Frame>
<img src="/images/tutorial-branch-loop.svg" alt="Branch-Loop workflow: Start → Plan → Implement → Validate → Tests passing? → Pass to Exit or Fix back to Implement" />
</Frame>
```dot title="branch-loop.dot"
digraph BranchLoop {
graph [goal="Create a Python script that passes its test suite"]
rankdir=LR
start [shape=Mdiamond, label="Start"]
exit [shape=Msquare, label="Exit"]
plan [label="Plan", prompt="Plan a small Python script (fizzbuzz.py) and a test file (test_fizzbuzz.py) using pytest. Describe what you will create.", shape=tab, reasoning_effort="low"]
implement [label="Implement", prompt="Create fizzbuzz.py and test_fizzbuzz.py as planned. Write the files to disk."]
validate [label="Validate", shape=parallelogram, script="python3 -m pytest test_fizzbuzz.py -v 2>&1 || true"]
gate [shape=diamond, label="Tests passing?"]
start -> plan -> implement -> validate -> gate
gate -> exit [label="Pass", condition="outcome=success"]
gate -> implement [label="Fix"]
}
```
```bash
arc run start demo/05-branch-loop.dot
```
## Command nodes
The `validate` node has `shape=parallelogram`, making it a **command node**. It runs a shell script and captures the output:
```dot
validate [label="Validate", shape=parallelogram, script="python3 -m pytest test_fizzbuzz.py -v 2>&1 || true"]
```
The `|| true` ensures the command always exits successfully — this way the node itself doesn't fail even when tests fail. The test output is captured as `command.output` in the [run context](/execution/context) for downstream nodes to use.
## Conditional branching
The `gate` node has `shape=diamond`, making it a **conditional node**. It evaluates outgoing edge conditions against the current run context:
```dot
gate [shape=diamond, label="Tests passing?"]
gate -> exit [label="Pass", condition="outcome=success"]
gate -> implement [label="Fix"]
```
- If the previous stage (`validate`) succeeded → take the "Pass" edge to `exit`
- Otherwise → take the unconditional "Fix" edge back to `implement`
The `condition="outcome=success"` checks the status of the most recently completed stage. An edge without a `condition` acts as the default fallback.
### Condition expressions
Conditions support more than just equality checks:
```dot
// Numeric comparisons
gate -> fast [condition="context.score > 80"]
// Substring matching
gate -> alert [condition="context.log contains error"]
// Boolean logic
gate -> deploy [condition="outcome=success && context.tests_passed=true"]
// Negation
gate -> retry [condition="!outcome=success"]
```
See [Transitions](/workflows/transitions) for the full condition grammar.
## The fix loop
When tests fail, execution loops back to `implement`. The agent receives context about what happened — the test output and failure details — so it can fix the issues:
```
start → plan → implement → validate → gate → [Fix] → implement → validate → gate → [Pass] → exit
```
Each time `implement` runs, it sees the previous test output in its preamble, guiding the fix.
## Preventing infinite loops
This workflow has no explicit loop limit, but in production you should add one. Use `max_visits` to cap how many times a node can execute:
```dot
implement [label="Implement", max_visits=3, prompt="..."]
```
After 3 visits, Arc terminates the run rather than looping forever. You can also set a graph-level limit:
```dot
graph [max_node_visits="20"]
```
## Node type summary
This workflow uses four node types:
| Node | Shape | What it does |
|---|---|---|
| `plan` | `tab` | Single LLM call, no tools |
| `implement` | `box` (default) | Agent with tool access |
| `validate` | `parallelogram` | Runs a shell script |
| `gate` | `diamond` | Routes based on conditions |
## What you've learned
- **Command nodes** (`shape=parallelogram`) run shell scripts and capture output
- **Conditional nodes** (`shape=diamond`) route execution based on edge conditions
- **Loops** are just edges that point backward — the agent receives prior context on each visit
- **`max_visits`** prevents infinite loops
- Unconditional edges act as default fallbacks
## Next
<Card title="Parallel Review" icon="arrow-right" href="/tutorials/parallel-review">
Fan out to concurrent branches and merge the results.
</Card>