# Explore many solutions in parallel with sandbox forks Fork one prepared sandbox into up to ten copies, run a different agent attempt in each, score them alike, keep the best. **On Runtime one `fork` call returns up to ten running copies of a prepared machine, memory and running processes included, and the snapshot it takes for itself costs nothing.** The source pauses for about a second while the fork is taken. Each copy is billed like a new sandbox of its size: $0.03125 an hour while the agent waits on its model at 2 vCPU and 4 GiB, at Runtime's rates as published on 25 September 2026 ([pricing](/docs/pricing)). ## Why explore in parallel A single agent run is one sample from a distribution. Ask again with another plan, another prompt or another model and you get a different answer,, and some of those answers are better than others. Scoring several attempts and keeping the best raises the odds that at least one succeeds, provided you can do two things cheaply: - **Give every attempt the same starting point.** Otherwise a better score may come from a luckier environment, not a better solution. - **Score every attempt the same objective way,** with tests, a benchmark, a type checker or a rubric, not by asking the agent whether it succeeded. A fork provides the first. Your scorer runs inside each copy for the second. ## Parallel exploration versus other patterns | Pattern | Branches from | Suits | Page | | --------------------- | -------------------- | --------------------------------------------- | ----------------------------------------------------------- | | Best of N (this page) | One prepared state | A task with a clear score: tests, speed, size | Here | | Tree search | Every promising step | Long tasks where early choices matter | [Tree search with forks](/use-cases/tree-search-with-forks) | | pass@k evaluation | A task image | Measuring a model, not shipping a fix | [Agent evals](/use-cases/agent-evals-and-swe-bench) | | Candidate filtering | An installed project | Keeping only generated artifacts that pass | [Test generation](/use-cases/test-generation) | ## The core loop The example asks an agent to make a slow function faster. Each copy gets a different strategy; the scorer runs the tests and a benchmark; the fastest correct copy wins. ```ts check import { Sandbox } from "withruntime"; const strategies = [ "Vectorise the inner loop with NumPy.", "Cache repeated lookups; change nothing else.", "Rewrite the parser as a single pass.", "Profile first, then fix the top hotspot only.", ]; // Your agent loop: sandbox tools bound to `copy`, the strategy in the prompt. async function runAgent(copy: Sandbox, strategy: string) { await copy.files.write("/workspace/strategy.txt", strategy); } await using base = await Sandbox.create({ diskMiB: 8192, timeoutSeconds: 3600 }); await base.exec("git clone --depth 1 https://github.com/your-org/your-lib.git repo", { check: true, timeoutMs: 300_000, }); await base.exec("cd repo && pip install -e . pytest", { check: true, timeoutMs: 600_000 }); const copies = await base.fork({ count: strategies.length, labels: { task: "speed-up-parse" } }); const scored = await Promise.all( copies.map(async (copy, i) => { await runAgent(copy, strategies[i]!); const tests = await copy.exec("python3 -m pytest -q", { cwd: "/workspace/repo", timeoutMs: 900_000, }); const bench = await copy.exec("python3 bench.py", { cwd: "/workspace/repo", timeoutMs: 300_000, }); const seconds = tests.exitCode === 0 ? Number(bench.stdout.trim()) : Infinity; return { copy, strategy: strategies[i]!, seconds }; }), ); scored.sort((a, b) => a.seconds - b.seconds); const best = scored[0]!; const diff = await best.copy.exec("git diff", { cwd: "/workspace/repo" }); console.log(best.strategy, best.seconds, diff.stdout.length); await Promise.all(scored.map((s) => s.copy.stop())); ``` ```python check from concurrent.futures import ThreadPoolExecutor from withruntime import Sandbox strategies = [ "Vectorise the inner loop with NumPy.", "Cache repeated lookups; change nothing else.", "Rewrite the parser as a single pass.", "Profile first, then fix the top hotspot only.", ] def run_agent(copy, strategy): """Your agent loop: sandbox tools bound to copy, the strategy in the prompt.""" copy.files.write("/workspace/strategy.txt", strategy) def attempt(pair): copy, strategy = pair run_agent(copy, strategy) tests = copy.exec("python3 -m pytest -q", cwd="/workspace/repo", timeout_ms=900_000) bench = copy.exec("python3 bench.py", cwd="/workspace/repo", timeout_ms=300_000) seconds = float(bench.stdout.strip()) if tests.exit_code == 0 else float("inf") return {"copy": copy, "strategy": strategy, "seconds": seconds} with Sandbox.create(disk_mib=8192, timeout_seconds=3600) as base: base.exec("git clone --depth 1 https://github.com/your-org/your-lib.git repo", check=True, timeout_ms=300_000) base.exec("cd repo && pip install -e . pytest", check=True, timeout_ms=600_000) copies = base.fork(count=len(strategies), labels={"task": "speed-up-parse"}) with ThreadPoolExecutor(max_workers=len(copies)) as pool: scored = sorted(pool.map(attempt, zip(copies, strategies)), key=lambda s: s["seconds"]) best = scored[0] print(best["strategy"], best["seconds"], len(best["copy"].exec("git diff", cwd="/workspace/repo").stdout)) for s in scored: s["copy"].stop() ``` Each copy runs its agent at the same time as the others, so the wall-clock time of the whole exploration is roughly that of the slowest attempt. ## What varies between attempts Anything your agent takes as input can be the axis: - **Plans**, as above: one strategy per copy, written by a person or proposed by a planning model. - **Models**: the same prompt to two or three providers, scored on equal terms. - **Temperatures or seeds**: the same model sampled several times. - **Tool budgets**: a short run and a long run, to learn whether more steps help this kind of task. Record the axis in the copy's labels. `runtime.sandboxes.list({ labels })` finds every copy of one exploration later, and lifecycle events for each are kept 14 days ([metrics and webhooks](/docs/observability)). ## Past ten copies `fork` makes 1 to 10 copies per call. For more, keep the prepared machine as a snapshot (`base.snapshot({ name, retentionDays })`) and create sandboxes from it with `snapshot: id`, as many as the account allows at once: 100 on a paid account to start, and creates beyond that wait for room. The free trial runs eight sandboxes at once, so there a fork of seven copies, plus the source, is the most that fits. A kept snapshot is billed as storage at $0.08 per decimal GB per 30-day month; the fork's own snapshot is deleted when the fork ends ([snapshots and forks](/docs/javascript#snapshots-and-forks)). ## What parallel exploration needs | Need | How Runtime covers it | | ------------------------------------ | --------------------------------------------------------------------- | | An identical start for every attempt | Forks copy files, memory and running processes | | Attempts that cannot interfere | Each copy is its own Firecracker microVM with its own kernel and disk | | Fast branching | About a second for a fresh sandbox; longer the more memory it holds | | Cheap waiting on models | Measured CPU: $0.03125 an hour idle at 2 vCPU, 4 GiB | | A copy that fails to start | `details.startedSandboxIds` names the ones that did; stop them | | Knowing which attempt was which | Labels on each copy; `runtime.sandboxes.list({ labels })` | ## What it costs Take 100 tasks a month, each explored with ten copies. Every copy runs for 15 minutes on 2 vCPUs and 4 GiB, and its builds, tests and benchmark use 180 CPU-seconds: ``` CPU: 1,000 × 180 s / 3,600 × $0.025 = $1.25 Memory: 1,000 × 900 s / 3,600 × 4 GiB × $0.0075 = $7.50 Total: $8.75 ``` About 9 cents a task for ten attempts, before the prepared base, which is one more sandbox per task ([pricing](/docs/pricing)). Model calls are billed separately, by your model provider. The trial's 50 hours are free and ask for no card. Related: [tree search with forks](/use-cases/tree-search-with-forks), [what a sandbox fork is](/glossary/sandbox-fork), [coding agent sandbox](/use-cases/coding-agent-sandbox), [dependency upgrades](/use-cases/dependency-upgrades), [RL environments](/use-cases/rl-environments). Facts on this page were checked on 25 September 2026.