Skip to main content

Sandbox Providers

The provider decides where the agent’s commands run. Everything else — the policy, the workspace bridge, the record of each command, your credentials — stays in your process and works the same with every provider. By the end of this page you will have picked one, set it up, and know what it enforces.
What the sandbox is (network, image, working directory) is the sandbox_manifest, the same for every provider; the Sandboxes and execution page has a first run and the manifest in full.
Every output on this page is what the code printed when it was run: Docker on Linux, and free E2B and Daytona accounts. Modal and Vercel were not run for this page; what is said about them comes from their adapters’ code.

Choose a provider

  • Start with docker. It is free, local, and the strictest by default.
  • Hosted (e2b, daytona, modal, vercel) when the agent runs where there is no Docker, or you want the sandbox off your machine.
  • http for anything without an adapter: your own sandbox service.
  • local only where the machine itself is the boundary: a CI job, a throwaway VM, an evaluation container.
Credentials are read by the provider’s SDK from your process’s environment (or passed as options); they are never put inside a sandbox.

Network: what each provider enforces

A manifest’s network_policy is {"default": "deny"} unless you say otherwise. What each provider can keep: denied_hosts is passed on to an http service, which must keep it or refuse the session. No other built-in provider can block named hosts, so there it is refused when the agent is built. To reach only some hosts, use "default": "deny" with allowed_hosts on a provider that keeps them.
Hosted “no network” is checked, and free accounts fail the check. E2B and Daytona both accept a request for no internet and report it back — and on the free accounts this page was run with, both handed back sandboxes that reached the internet. The adapter tries one outbound connection from inside each new sandbox that must have no network; a sandbox that connects is destroyed and refused:
A promise of isolation the provider does not keep is worse than none: a policy may allow the work only because it is isolated. On such an account, either allow the network in the manifest (the policy asks a person, as below) or set "verify_network_isolation": False and accept an unchecked sandbox. The check needs python in the image; an image without it is refused too.

Docker

One container per run, removed when the run ends. It has no network unless the manifest allows it, a read-only root filesystem, an unprivileged user, all Linux capabilities dropped, no privilege escalation, a process limit, and a working directory and /tmp kept in memory. The Docker socket, system directories and credential folders (~/.ssh, ~/.aws, …) are never mounted. The first run pulls the image; later runs start in seconds. The default image has Python and its standard library and nothing else, and with no network a command cannot pip install. Build an image with what your tasks need and name it in the options or the manifest. A run on Docker, end to end, is on Sandboxes and execution. A container left behind by a process that was killed is removed when its run is resumed, run again with the same run ID, or abandoned (abandon_run): each container carries its run’s ID in the label omnicoreagent.run. To remove one run’s leftovers yourself, await DockerSandboxRuntime().cleanup_orphans(run_id=...) (from omnicoreagent.sandbox.docker). Without run_id it removes every container labelled omnicoreagent.sandbox, including those of agents still running on the same Docker host.

E2B

On a free account the no-network check fails (above), so this agent asks for the network, and the policy asks a person first:
A new E2B sandbox took about 12 seconds to start here. The sandbox is killed when the run ends.

Daytona

Each run gets an ephemeral sandbox, deleted when the run ends. Measured here: the default image (python:3.12-slim) gave Debian 13 and Python 3.12.14, commands ran as root, and a sandbox took 48 to 84 seconds to start. Daytona returns a command’s output as one stream: stdout holds everything and stderr is empty. allowed_hosts is refused when the agent is built: Daytona’s allow list takes IP ranges, not host names. Use "deny" or "allow" on Daytona. (In 0.4.1 it was accepted and the session then failed to start.)
Modal is the built-in provider that keeps a host allowlist: the hosts are passed as Modal’s outbound_domain_allowlist. Each allowed host is its own sandbox.network.configure question, so a policy can allow some hosts and ask about the rest. Sandboxes run in a Modal app named omnicoreagent-sandbox (created if missing). There is no from-inside network check for Modal.

Vercel

The network is deny-all or allow-all; a host allowlist is refused. There is no from-inside network check for Vercel.

HTTP: your own sandbox service

For anything without an adapter — Cloudflare’s Sandbox SDK behind a Worker, a sandbox service inside your own network — run a small service and point the agent at it:
The service answers five requests, each with Authorization: Bearer <token> when a token is set: network carries default, allowed_hosts and denied_hosts. The service is responsible for the isolation it promises: one that cannot keep the network policy must refuse the session. Only the plain environment is sent.

Local: this machine, not a sandbox

local runs each command as a process on the machine the agent runs on, with nothing in between: a command can reach the network, read and change any file your user can, and what it changes stays changed. Use it only where the machine is already the boundary. The built-in profiles never allow host commands on their own (permissive-dev and strict-production deny them; interactive-dev asks a person for each one). To let an agent run them without asking, start from a profile, drop the asks that stand in the way, and allow host commands with a rule of your own. The manifest’s working_dir must already exist, so create it first (here app/, next to the script: mkdir app, or the os.makedirs line below); otherwise the first command fails, saying the working directory does not exist:
A command pwd; echo "LLM_API_KEY=${LLM_API_KEY:-unset}" in that agent came back as:
Dropping ask_high_risk stops the profile asking about every other high-risk action on the host too; keep it if the agent has other tools that should still ask. A deny rule always wins over an allow, so this cannot be done from permissive-dev. What it refuses. A manifest must ask for what local really gives: network allow and filesystem allow, with no host or path lists. A manifest that leaves the network at its default (none), or no manifest at all, is refused when the agent is built, as are an image, a workspace mount, CPU, memory or GPU limits, a sandbox lifetime, and secret references. What it enforces. Each command’s time limit (the command and everything it started are killed); the output cap; the host environment is not passed, only PATH, HOME, USER, LOGNAME, LANG, LC_ALL, TERM, TMPDIR and TZ plus the manifest’s plain environment. Files are another matter: a command can read whatever your user can, including credential files. Workspace files are not copied in or out — point working_dir at the workspace to have commands work in it directly. The model is told the truth too: its execute tool says it runs on this machine and is not isolated, and every command is recorded with execution_surface: host.

none and local_test

"provider": "none" gives the agent a policy but no sandbox: there is no execute tool, and a policy rule that requires a sandbox (sandbox_required) is never satisfied. local_test runs Python handlers you register instead of commands, for tests of your own agent. Pass the runtime itself, and say that a test runtime may stand in for a sandbox:
With a stand-in model that called execute with pytest -q, the tool returned:
Without allow_test_sandbox_runtime, the agent gets no execute tool.

Bring your own provider

register_sandbox_provider("name", factory) adds a provider; it then works anywhere a provider name does. The factory is called with the options dict and a telemetry recorder, and returns a SandboxRuntime:
A runtime implements create, execute, read_file, write_file, set_network_policy, snapshot and terminate, and sets supports_execution = True and supports_required_sandbox = True when it isolates commands.

When things go wrong

The hosted sandbox was asked for no network and has one (see the warning above). Allow the network in the manifest, use a plan or provider that enforces isolation, or set "verify_network_isolation": False.
A misspelled provider, or one of yours not registered before the agent is built:
Options are checked per provider; the network belongs in the manifest:
Use "sandbox_manifest": {"network_policy": {"default": "allow"}}.
allowed_hosts on docker, e2b, daytona, vercel or local:
The same check refuses denied_hosts on any built-in provider but http (“does not enforce blocking named hosts”), and environment.secret_refs on every built-in provider (“does not enforce delivering secrets”).
local with no sandbox_manifest, or one that leaves the network at its default (deny). Building the agent fails with:
Give it the manifest shown above.
The provider’s extra is not installed, e.g. pip install "omnicoreagent[e2b]".
Without the docker extra, nothing fails when the agent is built: the run’s first execute call fails with The Docker sandbox needs the Docker SDK: pip install omnicoreagent[docker]. Install it: pip install "omnicoreagent[docker]".

Next

Sandboxes and execution

The execute tool, files in and out, the network, the record of a command.

Policies

Allow, ask or deny commands, images and network access.

Approvals

The person who says yes to the network.

Budgets

Cap sandbox seconds, and everything else a run spends.

Security model

What each boundary does and does not protect.

Guardrails

Prompt injection in what the agent reads.