Sandboxes get persistent volumes, plus a new region in France
orkestr sandboxes can now mount a persistent volume that survives termination, choose which EU region it lives in, and move it later. The fleet also just picked up a third region: Roubaix, France.
Two things shipped this week that change how you’d design a longer-running agent. Sandboxes can now keep a disk around after they die, and there’s a new region to run them in - and as of right after launch, that disk knows which region it lives in too.
Persistent volumes
Until now, a sandbox’s filesystem died with the sandbox. Terminate it and /workspace was gone - fine for a one-shot exec, annoying if your agent spends ten minutes cloning a repo and installing dependencies every single run.
A volume is a named disk you mount at /persist. It survives terminate and reattaches to whatever sandbox asks for it next:
from orkestr import Sandbox
with Sandbox.create(volume="agent-workspace") as sbx:
sbx.exec("pip install -r requirements.txt")
# work happens, sandbox terminates, the venv on /persist stays put
with Sandbox.create(volume="agent-workspace") as sbx:
sbx.exec("python run.py") # dependencies are already there
First call to volume= creates it if the name doesn’t exist yet. You can also manage volumes directly - create_volume, list_volumes, delete_volume, move_volume - from the Python SDK, the JS SDK, or as MCP tools if your agent is driving itself.
A few things worth knowing before you build around this:
- One writer at a time. A volume can only be attached to a single non-terminated sandbox. Reattach it to a second sandbox while the first is still alive and you’ll get an error, not silent corruption.
- 10 GB by default, 100 GB max per volume. Free gets one volume up to 10 GB. Pay-as-you-go gets ten, up to 200 GB each. Enterprise gets fifty, up to 2 TB total.
- Billed on what you provision, not what you use. A 50 GB volume costs the same whether it’s empty or full - size it for what you need, not a ceiling to leave headroom under.
- It’s not a database. It’s a disk. Good for a cloned repo, a virtualenv, a model cache, a scratch directory an agent keeps coming back to.
- This is exactly what makes the 24-hour session limit livable. Pay-as-you-go sandboxes can run for up to 24 hours before they’re terminated automatically - plenty for a single agent run, not enough if the same agent picks up the next day. Point it at the same volume and it doesn’t start over.
Under the hood a volume lives on a sandbox host’s own disk, with a checkpoint pushed to EU object storage. If that host ever goes down, the volume can be rehydrated onto a different one from the checkpoint - that’s a durability guarantee, not a feature you reach for on purpose. Where it lands, and whether it moves, is something you control - more on that below.
A third region: Roubaix, France
The sandbox fleet now runs in three places instead of two: Falkenstein, Germany and Helsinki, Finland, plus a new box in Roubaix, France. Same isolation, same network controls, same pricing - just another place to put the box closer to wherever your workload actually runs.
Pick a region at create time the same way you already do:
Sandbox.create(template="python-3.12", region="rbx")
Leave region off and you get the default. Don’t hardcode the three names above, though - the list of valid regions comes from whatever’s actually live in the fleet, and it’ll grow. Read it off Sandbox.limits() (or the MCP/console equivalent) rather than baking fsn1 / hel1 / rbx into your code.
Volumes are now region-aware too
A volume now picks up a region too - either pinned explicitly at creation, or inherited from the first sandbox that attaches it:
from orkestr import Volume
# pin it up front
Volume.create("agent-workspace", region="rbx")
# or leave region off and let the first attach decide
with Sandbox.create(template="python-3.12", region="rbx", volume="agent-workspace") as sbx:
... # the volume is now homed in rbx
Once a volume has a region - pinned or inherited - it’s a hard constraint, not a suggestion: a sandbox asking for a conflicting region gets rejected up front, rather than either side silently winning. If you need to actually relocate a volume, there’s a move_volume call for that:
Volume.move("agent-workspace", region="fsn1")
Moving takes a fresh checkpoint of the volume before touching anything, so a failed move leaves the original untouched rather than half-migrated. It also only runs against a volume that isn’t currently attached - terminate the sandbox holding it first. The data itself doesn’t physically fly across the network on move; it rehydrates from that checkpoint the next time a sandbox attaches in the new region, so the first attach after a move is where the migration actually completes. It doesn’t touch your bill either - a moved volume costs the same as one that’s never left, size is still the only thing you’re charged for.
There’s no cross-region attach - a sandbox in one region can’t reach out and mount a volume that lives in another. move_volume is the only way to get a volume from one region to the next.
If you’d rather not write code for any of this, it’s in the console too - the “New volume” dialog now has a region dropdown under the size slider, defaulting to “Follow my first sandbox”:
More regions are worth adding as demand shows up in specific places - if there’s a spot you’d want a sandbox to boot in, tell us.
Volumes, region picking, and move_volume are live now on every sandbox plan, including free. Full limits are on the pricing page.