Skip to content

Sandboxes

A sandbox runs shell commands inside a workspace: repo.setup, the test command, benchmarks and the environment's run action.

LocalSandbox (default)

Runs commands with subprocess on the host. The environment is scrubbed to an allowlist (PATH, HOME, LANG, PYTHONPATH, VIRTUAL_ENV, toolchain homes, ...) so API keys in your shell never reach agent-controlled commands. python is made to resolve to the interpreter running repogym unless a setup step creates its own environment.

from repogym import LocalSandbox
sandbox = LocalSandbox(extra_env={"MY_FLAG": "1"})
sandbox = LocalSandbox(inherit_env=True)   # pass everything through (not recommended)

Warning

LocalSandbox is not a security boundary. A task's setup or test command runs with your privileges. Use Docker for tasks you did not author.

DockerSandbox

Each command runs in a fresh container with the workspace bind-mounted at /workspace, the network disabled and resource limits applied.

repogym validate tasks --sandbox docker:python:3.12-slim
repogym run tasks -k 'bugfix-node-*' --agent golden --sandbox docker:node:22-slim
from repogym import DockerSandbox
sandbox = DockerSandbox(image="python:3.12-slim", network="none", memory="2g", cpus="2")
env = RepoEnv(task, sandbox=sandbox)

Because the network is off, dependencies must be installed in the image or by a setup step run with network="bridge". A common pattern is a per-task image built from the repository's own Dockerfile and referenced in metadata.

Writing a sandbox

class MySandbox:
    name = "remote"
    def available(self) -> bool: ...
    def run(self, command, cwd, timeout=300, env=None, max_output=200_000) -> CommandResult: ...

Anything with that shape (Modal, E2B, Firecracker, SSH) can be passed wherever a sandbox is accepted; the workspace directory must be reachable from it.