On Runtime, the machine the loop acts on has limits of its own that the loop cannot lift: idle pause, a spending cap and network rules enforced on the host. The loop also costs little while it waits on the model. A 2 vCPU, 4 GiB sandbox bills $0.03125 an hour when its CPUs are idle (pricing).
Where the term comes from
Anthropic's guide to building agents, published 19 December 2024, separates workflows from agents. Workflows are "systems where LLMs and tools are orchestrated through predefined code paths". Agents are systems where "LLMs dynamically direct their own processes and tool usage". The guide says agents "are typically just LLMs using tools based on environmental feedback in a loop". It says they commonly include stopping conditions, "such as a maximum number of iterations". Each turn of the loop is one tool call and its result.
The parts of a loop
| Part | What it is | On Runtime |
|---|---|---|
| Environment | What the actions change and observe | One sandbox per task: a Linux machine with its own kernel |
| Actions | Commands, file edits, clicks | exec, files, spawn, the desktop, the code interpreter |
| Feedback | What goes back to the model | Exit code, output, truncation flags, screenshots |
| Step limit | A cap on iterations, in your code | Yours to set |
| Time limit | A wall-clock bound that survives a crash | An optional time limit: timeoutSeconds, onLeaseEnd |
| Money limit | A ceiling the agent cannot raise | Daily limit per key; maxTotalCostMicros per sandbox |
| Safe retries | Repeating a step without doing it twice | An idempotency key on every write |
A minimal loop
The model is yours. The loop gives it a sandbox, runs each command it picks, and stops on "done", on the step limit, or when its time limit ends.
TypeScriptimport { Sandbox } from "withruntime";type Step = { command: string[] } | { done: string };type Model = (history: string[]) => Promise<Step>; // your LLM callexport async function solve(model: Model, maxSteps = 20) { await using sbx = await Sandbox.create({ timeoutSeconds: 1200, onLeaseEnd: "stop" }); const history: string[] = []; for (let step = 0; step < maxSteps; step++) { const next = await model(history); if ("done" in next) return next.done; const run = await sbx.exec(next.command, { timeoutMs: 120_000 }); history.push(`$ ${next.command.join(" ")}\nexit ${run.exitCode}\n${run.stdout}${run.stderr}`); } return "step limit reached";}The array form of exec runs the program with no shell. Arguments the model
wrote cannot add a second command. await using deletes the sandbox when the
function returns or throws.
Long and interrupted loops
A loop that spans hours or waits for a person can pause between turns.
idlePauseSeconds pauses the sandbox when no request arrives. It keeps memory and
running processes. Sandbox.getOrCreate(name) finds the same machine again from a
new process (sandboxes by name). To try
several next steps from one point, fork the sandbox into
up to 100 running copies.
Related
- A sandbox for a coding agent
- What is tool calling?
- What is an agent sandbox?
- Agent evals and SWE-bench
Sources
- Anthropic, Building effective agents, 19 December 2024, checked 25 October 2026
Facts on this page were checked on 25 October 2026.