Skip to content
Runtime

What is an agent loop?

An agent loop repeats one cycle. The model picks an action, your code runs it, and the result goes back to the model. The loop ends when the task is done.

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.

Sources

Facts on this page were checked on 25 October 2026.

100 free hoursin your first 30 days.

of a 1 GB machine

  • No credit card
  • Four sandboxes at once, 2 vCPU and 4 GiB each
  • Then prepaid credit from $10, no plan fee
Start free, no card
Start free, no card