Skip to content
Guides · Agent cookbook

Give an Agent a Bigger Sandbox Mid-Task Without Losing Its Work

Updated October 27, 2026 .md

Short answer: Yes, if the work is on disk. Stop the sandbox, then sbx resume --type with a bigger size. In our test that took about 6 seconds, and files came back while processes and memory did not (memoryRestored false, resumeReason resized). Have the agent checkpoint to disk so it can continue after the cold boot.

This page is about the agent's side of a resize: what its task needs to look like so a bigger machine is a short pause, not a restart from zero. For diagnosing exit code 137 or a full disk, see fix exit code 137 or a full disk. For telling a cold boot from a memory resume, see detect a cold boot after resume.

What survives a resize#

We ran all of this on prod on 2026-10-27: a small sandbox, a task killed halfway for lack of memory, then a stop and sbx resume --type default.

After sbx resume --type default
Files in your home directory (the checkpoint, the code) Kept
Packages you installed, the disk's contents Kept, and the disk grows to the new size (df showed 56G, 51G free)
Running processes (the task, a python3 -m http.server we left running) Gone. Nothing listened on port 8000 after the resume
Anything only in memory: variables, caches, the agent's in-process state Gone
Files in /tmp Gone
Sandbox id, subdomain, URL Kept (smooth-simple-tapir before and after)
memoryRestored / resumeReason false / "resized"
Step Time (one run each)
sbx stop --wait 2.2 s
sbx resume --type default (until it answers commands) 3.4 s
sbx fork --type default --wait of the stopped sandbox 3.4 s
The whole grow-and-continue loop below, including about 10 s of the task's own work 18.6 s

A resize is a stop and a cold boot. There's no way to add memory to a running sandbox, so the task has to survive losing its process.

Make the task checkpoint to disk#

The rule: after each unit of work, write what you've done to a file in the home directory, and on start, skip anything already recorded. Write the checkpoint atomically, so a kill in the middle of a write leaves the old file or the new one, never half of one. Here is the test task. Its embed step holds 5 GB at once, more than a small sandbox's 4 GB:

# ~/task/task.py: a multi-step job that checkpoints after every step.
import json, os, sys, time

STATE = os.path.expanduser("~/task/state.json")
STEPS = ["fetch", "parse", "index", "embed", "report"]

def load():
    try:
        with open(STATE) as f:
            return json.load(f)
    except FileNotFoundError:
        return {"done": [], "results": {}}

def save(state):
    tmp = STATE + ".tmp"
    with open(tmp, "w") as f:
        json.dump(state, f)
        f.flush()
        os.fsync(f.fileno())
    os.replace(tmp, STATE)  # atomic: a crash leaves the old or the new file, never half of one

def run(step):
    if step == "embed":  # the heavy step: holds 5 GB at once
        blocks = [bytearray(256 * 1024 * 1024) for _ in range(20)]
        return f"{len(blocks) * 256} MB"
    time.sleep(2)  # stands in for real work
    return "ok"

state = load()
for step in STEPS:
    if step in state["done"]:
        print(f"skip {step} (checkpointed)", flush=True)
        continue
    print(f"run  {step}", flush=True)
    state["results"][step] = run(step)
    state["done"].append(step)
    save(state)
print("all steps done", flush=True)

On the small sandbox, the kernel killed it at the heavy step. The three finished steps were already on disk:

sbx exec $id "python3 ~/task/task.py; echo exit=\$?; cat ~/task/state.json"
run  fetch
run  parse
run  index
run  embed
exit=137
{"done": ["fetch", "parse", "index"], "results": {"fetch": "ok", "parse": "ok", "index": "ok"}}

For a coding agent, the same idea means: commit or save work to files as you go, keep the plan and a progress log in a file (for example ~/task/PROGRESS.md), and put long-lived services in enabled systemd units so the cold boot starts them (services that should always run). The agent's conversation lives in your orchestrator, outside the sandbox, so it isn't affected. Only what the agent kept in the sandbox's memory is lost.

Let the orchestrator grow the sandbox and continue#

sbx exec returns the command's exit code, so the loop that drives the agent can react to 137 by moving up one size and running the task again:

#!/usr/bin/env bash
# grow.sh <sandbox-id>: run the task; if the kernel kills it for memory, move up one size and continue.
id=$1
bigger() { case $1 in small) echo default ;; default) echo large ;; large) echo xlarge ;; esac; }

while true; do
  sbx exec "$id" --timeout 600 "python3 ~/task/task.py"
  code=$?
  [ "$code" -eq 137 ] || exit "$code"          # 0 = done; anything else is not a memory problem

  size=$(sbx info "$id" --json | jq -r .sandbox.type)
  to=$(bigger "$size")
  [ -n "$to" ] || { echo "already at the largest size"; exit 137; }
  echo "OOM-killed on $size; moving to $to"

  sbx stop "$id" --wait >/dev/null
  sbx resume "$id" --type "$to" >/dev/null
  sbx info "$id" --json | jq -c '.sandbox | {type, memoryGB, memoryRestored, resumeReason}'
done

Run on a fresh small sandbox with the task copied in:

time ./grow.sh $id
run  fetch
run  parse
run  index
run  embed
OOM-killed on small; moving to default
{"type":"default","memoryGB":8,"memoryRestored":false,"resumeReason":"resized"}
skip fetch (checkpointed)
skip parse (checkpointed)
skip index (checkpointed)
run  embed
run  report
all steps done

real	0m18.605s

Some notes from the runs:

  • Read the new size from type and memoryGB. In our run on October 27, 2026, stats briefly still held the sample from before the stop (memoryTotalMb: 3914, the small figure); since a fix later that day, list views no longer show that stale sample after a resize.
  • Exit code 137 means SIGKILL, and memory is the usual cause, not the only one. If you want to be sure before paying for a bigger size, check dmesg | grep -i 'out of memory' first (the 137 guide covers this).
  • The free trial runs small and default only, and xlarge needs the $100 plan or higher (machines), so cap bigger at the sizes you can use.
  • Give the sbx exec a --timeout longer than the task. The default is 30 seconds. For tasks longer than a few minutes, use sbx exec --detach and poll, as in run a long job.

Resize in place, or fork a bigger copy#

A resize is one-way. Moving to a smaller size isn't supported yet: to go smaller, create a new sandbox of that size and copy your files. If you're not sure the agent should stay big, fork instead. A fork copies the disk into a new sandbox at the size you ask for, and leaves the original as it was.

We forked the stopped small sandbox (with its three-step checkpoint) to default:

sbx fork $id --type default --ttl 1800 --wait --json | tail -1 \
  | jq -c '{event, id, type: .sandbox.type, memoryGB: .sandbox.memoryGB, memoryRestored: .sandbox.memoryRestored}'
sbx info $id --json | jq -c '.sandbox | {state, type}'
{"event":"ready","id":"sb_dz2cxig1dv","type":"default","memoryGB":8,"memoryRestored":null}
{"state":"archived","type":"small"}

The fork had the checkpoint, ran embed and report, and finished. The original stayed stopped at small. A fork's memoryRestored is null because a fork never carries memory. It took the source's name with (fork) appended; CLI builds from October 27, 2026 on accept sbx fork --name <name> to name it yourself.

Resize in place (resume --type) Fork a bigger copy (fork --type)
Keeps the sandbox id and URL Yes No: new id, new subdomain, new SSH host keys
Can go back to the old size No Yes: the original is untouched
Results end up In the same sandbox In the fork. Copy back what you need (see move files in and out)
Auto-stop Keeps the sandbox's setting unless you pass --ttl Default one hour unless you pass --ttl
Cleanup None Delete whichever copy you don't need: both count toward your plan's included storage while stopped

Use the fork when the bigger size is an experiment, or when only one step needs it and you want the rest of the task to go back to the cheaper size. Use the resize when the agent will need the memory for the rest of the task anyway.

What the bigger size costs#

Billing is per second while a sandbox runs, at the size it is running at, and a stopped sandbox costs nothing (billing). From the price list:

Size RAM Per hour 10 minutes 2 hours
small 4 GB $0.018 $0.003 $0.036
default 8 GB $0.036 $0.006 $0.072
large 16 GB $0.072 $0.012 $0.144

Each step up doubles the rate. Take an agent that runs 2 hours, where only a 10-minute step needs 8 GB. Running all 2 hours on default costs $0.072. Running on small and resizing to default when the heavy step starts at the 1-hour mark costs $0.018 for the first hour plus $0.036 for the second, $0.054 in total, because everything after the resize runs at the doubled rate. Forking a default copy for just the 10-minute step, then deleting it, keeps the rest at small: $0.033 for the 110 small minutes plus $0.006 for the fork, $0.039 in total. The roughly 6 seconds of stop and resume are not a meaningful cost.

FAQ#

Can I add memory without stopping the sandbox?#

No. The size changes only on resume or fork, and a resume at a new size always boots from disk. Plan for the task's process to end, and checkpoint to disk.

Can I use --require-memory to keep processes during a resize?#

No. --require-memory can't be combined with a size change, and the API answers 400 invalid_require_memory. The memory image belongs to the old size, so a resized sandbox always cold-boots.

Can the agent resize its own sandbox from inside?#

Not in one step, because stopping the sandbox ends the agent's process. The stop and resume have to come from something outside it, such as your orchestrator. Have the agent exit with a clear code or write a request to a file, and let the orchestrator do the resize.

Will the agent's open files and tmux sessions come back?#

No. Files on disk come back. Open file handles, shells, tmux panes and anything else in memory don't. /tmp was empty after our resize, so don't keep checkpoints there.

More guides

Top AI sandbox platforms for code execution in 2026, ranked

For running AI-written code we rank Sandboxer, Freestyle and E2B first: each gives code its own VM with an API or SDK and can pause with memory. Pick Daytona for Windows or GPUs, Modal or Northflank for GPUs at scale, E2B or Northflank to run in your own cloud, and Vercel Sandbox if your app lives on Vercel.

Read the guide
Best sandboxes for running coding agents (Claude Code, Codex, Gemini CLI) in 2026, ranked

For coding agents we rank Sandboxer first: a full Ubuntu VM with Claude Code and Codex preinstalled, Docker, and stop-and-resume that keeps the agent's session in memory. Freestyle and Amp Orbs also keep memory across pauses. Pick E2B for prebuilt agent templates on open source, Docker Sandboxes for free local runs, and Codespaces if you live in GitHub.

Read the guide
Best Daytona sandbox alternatives in 2026, ranked

The best Daytona alternatives depend on why you're switching. For a full Linux microVM on every sandbox with memory-saving stop and Docker, we rank Sandboxer first. E2B suits open source and self-hosting, Modal massive short-job fleets, Northflank bring-your-own-cloud with GPUs, and Vercel Sandbox apps on Vercel.

Read the guide
Best E2B alternatives in 2026, ranked

If you're leaving E2B for longer sessions or a fuller machine, we rank Sandboxer first, then Freestyle: both give each sandbox a full Linux VM that keeps memory across pauses, with Docker and no short session cap. Pick Daytona for Windows or GPUs, Northflank for bring-your-own-cloud, and stay on E2B if you need open source.

Read the guide