Using bounded loops

Use a loop step when a fixed sequence needs to repeat against shared Flow variables until a verdict passes. Common examples are draft → review → revise, generate → validate → repair, and retrieve → assess → refine.

A bounded loop has do-while semantics: Runtype runs the body once, evaluates until after the body, and repeats only while the expression is false. maxIterations is always a hard backstop and must be between 1 and 10.

1{
2 "type": "loop",
3 "name": "Review and revise",
4 "config": {
5 "steps": [
6 {
7 "type": "prompt",
8 "name": "Independent review",
9 "config": {
10 "model": "claude-sonnet-4-6",
11 "userPrompt": "Review {{draft}}. Return JSON with verdict and directives.",
12 "responseFormat": "json",
13 "outputVariable": "review"
14 }
15 },
16 {
17 "type": "prompt",
18 "name": "Surgical revision",
19 "config": {
20 "model": "claude-sonnet-4-6",
21 "userPrompt": "Revise {{draft}} using {{review.directives}}.",
22 "outputVariable": "draft"
23 }
24 }
25 ],
26 "until": "review.verdict === 'pass'",
27 "maxIterations": 3,
28 "iterationVariable": "reviewRound"
29 }
30}

The body reads and writes the same Flow-level variable scope on every round. In this example, each revision replaces draft, and the next review reads the revised value. When iterationVariable is set, Runtype writes the current 1-based round before running the body.

Build a loop with the TypeScript SDK

Both TypeScript Flow builders expose .loop():

1const flow = new FlowBuilder()
2 .createFlow({ name: 'Bounded review' })
3 .loop({
4 name: 'Review and revise',
5 steps: reviewAndReviseSteps,
6 until: "review.verdict === 'pass'",
7 maxIterations: 3,
8 iterationVariable: 'reviewRound',
9 })
10 .build()

MCP flow tools accept the same type: "loop" step shape in inline, create, and update requests.

Design safe loop bodies

  • Make every round move one shared working variable toward a measurable verdict. Avoid repeatedly redrafting from the original input.
  • Keep until deterministic. Have a review or validation step write a boolean or compact verdict, then test that value.
  • Choose the smallest useful bound. Reaching maxIterations completes the loop and continues the Flow; it does not imply that the verdict passed, so add a conditional after the loop when exhaustion needs a separate path.
  • Nested loop steps are rejected. Put the inner work in the same body, call a separate Flow, or use a conditional inside the body.

Next steps