If you train a model with agentic reinforcement learning, every rollout needs somewhere to run code: install a package, run the tests, hit the network, write files. Thousands of those run at once. When the training job is preempted they all have to stop together and come back later. And when you want to explore one state several ways, you want copies of the environment as it is right now, memory included, not fresh ones from the image.
Hosted sandbox services cover part of this. We wanted all of it on our own machines, so we built OpenDsec and published it under the AGPL.
This is the first post in a series about it. Here: what it does, what it looks like to run, and where its limits are.
That is a real recording on one bare-metal server: the install script, then a short Python program that creates a Firecracker microVM, runs print(6*7) in it and forks it into four copies. The six minutes of building and installing are cut; everything after runs at real speed. The 0.16 s is the whole API call (placement, boot, the in-VM agent ready), measured from the client.
The program is the whole client side:
import asyncio, time
from opendsec import DSecClient, DSecRunArgs
async def main():
async with DSecClient() as client:
t = time.perf_counter()
sb = await client.run_sandbox(DSecRunArgs(backend="microvm", image="root/py:3.12"))
print(f"ready in {time.perf_counter() - t:.2f}s (whole API call: placement + boot)")
print((await sb.run_shell("python3 -c 'print(6*7)'")).stdout.strip())
t = time.perf_counter()
forks = await sb.fork(count=4) # copies with memory
print(f"forked 4 in {time.perf_counter() - t:.2f}s")
await asyncio.gather(*(s.stop() for s in [sb, *forks]))
asyncio.run(main())
DeepSeek described the sandbox platform behind their agentic RL training in DeepSeek Elastic Compute (DSec). OpenDsec follows that paper: a stateless apiserver, IAM with nested projects and quotas, a watcher that aggregates scheduling state, power-of-k placement where each node has the final say on admission, layered images loaded on demand, a default-deny network policy, and pausing a whole task at once.
Where the paper leaves things open, or where we chose differently, the decisions are ours: nftables and a DNS proxy instead of eBPF for the network policy, any shared file system (NFS, CephFS, JuiceFS) instead of 3FS for images, and Firecracker with memory snapshots as the main backend. The design document marks every point as either from the paper or our own.
OpenDsec is an independent project. It is not affiliated with DeepSeek and contains none of its code.
fork(count=N) s the source for about 10 ms and gives you N copies with the same processes, imports and open ports. On one node the copies share memory pages; on another node they pull the snapshot from the source node directly.E2B_API_URL, E2B_SANDBOX_URL, E2B_API_KEY). E2B's own Python and JS SDK checks pass.
All numbers are our own measurements on our bare-metal machines; the design document says how each was measured. Your hardware will give different ones. For example, the fork time depends on the file system under the sandbox state: 0.1 s on XFS, which copies memory files by reflink, and about 1 s on ext4, which has to copy them.
You need a Linux x86_64 machine with systemd and cgroup v2 (we test on Ubuntu 24.04). MicroVMs also need /dev/kvm, so use bare metal or a cloud VM with nested virtualization; without it you get containers only.
sudo -i
apt update && apt install -y make git python3-venv
curl -fsSL https://go.dev/dl/go1.27.3.linux-amd64.tar.gz | tar -C /usr/local -xz
git clone https://github.com/kernflux/opendsec && cd opendsec
deploy/quickstart.sh
The script checks the machine, builds everything, downloads Firecracker and the guest kernel (checked against pinned hashes), installs the components as systemd services with their own CA, imports python:3.12 from Docker Hub, and runs one container and one microVM as a check. Then:
python3 -m venv .venv && .venv/bin/pip install ./sdk/python
. /root/opendsec-ops/demo.env
.venv/bin/python sdk/python/examples/quickstart.py
deploy/quickstart.sh --uninstall removes all of it again.
The servers are AGPL-3.0. The Python SDK, the Go client and the API definitions are Apache-2.0, so programs that only call OpenDsec are not bound by the AGPL. A commercial license is available for closed modifications.
Firecracker, gVisor and containers compared for running AI-generated code: isolation, start time, memory and compatibility, with measurements.
The code is at github.com/Kernflux/opendsec, the docs at kernflux.github.io. Issues and questions are welcome there or in the comments.