Skip to main content

sandboxio

One secure Python API for running AI-agent code in any sandbox. Swap Docker ↔ E2B with one line; no network by default; test your agent tools offline with the built-in fake.

PyPI CI Python 3.11+ License: MIT OpenSSF Scorecard Coverage

Why this exists

Every sandbox provider ships its own SDK with its own shape, so agent code that runs on one is rewritten for the next. The framework layers each solve it captively — LangChain's backends only help inside LangChain. sandboxio is the framework-agnostic substrate underneath, with the security posture that agent execution actually needs.

  • Security is the headline, not an add-on. Deny-by-default egress, mandatory timeouts, isolation-tier reporting and audit hooks are all in v0.1 — not a later hardening pass.
  • No lowest common denominator. One-backend features stay reachable through Capability flags and .native instead of being sanded off.
  • Tiny, auditable core. anyio and typing-extensions only; every backend SDK sits behind an extra and is imported lazily.
  • Offline-testable. FakeBackend and a pytest fixture, so your agent's tools have tests that need no Docker, no network and no provider account.
  • Usable without writing Python. The same sandbox and the same defaults are served over MCP, so a client like Claude Desktop or Cursor gets code execution it cannot reconfigure at runtime.
  • Provider churn is absorbed publicly. Upstream breaking changes are tracked, absorbed and written down.

Quickstart

Every Python block below is executed by CI exactly as written (tests/test_readme_examples.py); a copied example that does not run is a P0 bug. The Docker-backed lines run against the built-in fake in CI, so they are the same code you would run — only the backend differs.

The commands below are what v0.1 will install. Today the name on PyPI holds a 0.0.0 placeholder that carries no code, so uv add sandboxio does not yet get you a library. uvx sandboxio demo is the documented entry point — never the sbx alias, which resolves to an unrelated PyPI package (ADR-0014).

uv add "sandboxio[docker]"     # from v0.1
uvx sandboxio demo             # create, run, stream, prove egress is denied, tear down
sandboxio doctor               # what is installed, reachable and missing — no secrets printed

Run code in a sandbox. create() with no arguments is local Docker; nothing leaves the sandbox unless you say so.

import sandboxio

async with await sandboxio.create() as sb:              # zero-config, local Docker
    res = await sb.run_code("print('hello')")
    print(res.stdout)                                    # hello
    res = await sb.run(["python", "--version"], timeout=30)
    print(res.exit_code, res.stdout.strip())

Swap the backend with one line. The code that uses the sandbox does not change.

import sandboxio

async def summarise(sb: sandboxio.protocols.AsyncSandbox) -> str:
    await sb.files.write("/work/input.txt", "3 4\n")
    res = await sb.run_code("a, b = open('/work/input.txt').read().split(); print(int(a) * int(b))")
    res.raise_for_status()                               # ExecutionError on a non-zero exit
    return res.stdout.strip()

async with await sandboxio.create("docker://python:3.12-slim") as sb:
    print(await summarise(sb))
async with await sandboxio.create("e2b://code-interpreter-v1") as sb:   # needs E2B_API_KEY
    print(await summarise(sb))

Stream output while a long command runs, and rely on the timeout: a sandbox timeout is sandboxio.SandboxTimeout, never the builtin TimeoutError.

import sandboxio

async with await sandboxio.create() as sb:
    async with sb.stream(["sh", "-c", "echo start; sleep 1; echo done"], timeout=30) as proc:
        async for chunk in proc:
            print(chunk.stream, chunk.data.decode(), end="")
        res = await proc.wait()
    try:
        await sb.run(["sleep", "999"], timeout=1)
    except sandboxio.SandboxTimeout as exc:
        print(exc.code)                                  # SBX_E1302 — stable, documented

Sync code gets the same surface through create_sync(). One sandbox is one portal thread; use the async API for heavy concurrency.

import sandboxio

with sandboxio.create_sync("docker://python:3.12-slim", timeout=60) as sb:
    print(sb.run_code("print(6 * 7)").stdout)

Test your agent's tools offline. sbx_fake is a pytest fixture installed with the package; it executes nothing, records everything, and passes the same contract suite as the real backends.

import pytest
from sandboxio import ExecResult


@pytest.mark.anyio
async def test_my_tool_reads_the_pandas_version(sbx_fake):
    sbx_fake.on_run_code(match="import pandas", returns=ExecResult(0, "2.2.1\n", ""))
    res = await sbx_fake.sandbox.run_code("import pandas; print(pandas.__version__)")
    assert "2.2.1" in res.stdout
    assert sbx_fake.calls[0].network.egress == "deny"     # the default, recorded

Full surface, including capability discovery, require_isolation, audit sinks and spans: docs/quickstart.md and the normative docs/spec/03-public-api.md.

Backends

Backend Status Isolation tier
Docker shipped in v0.1 CONTAINER — containers share the host kernel
E2B shipped in v0.1 MICROVM — Firecracker microVM, its own kernel
FakeBackend shipped in v0.1 n/a — in-process, for tests
Modal planned for v0.1.1 GVISOR — containerised and virtualised using gVisor

Every tier above is the mechanism the provider documents for itself, read on 2026-09-20. None of those three pages carries its own revision date, so that is the date it was read, not a date the provider published; re-verification is a quarterly item. What the tiers mean — and why GVISOR is defence in depth rather than VM equivalence — is in docs/explanation/isolation-tiers.md.

Third-party adapters are first-class: the adapter contract is specified and enforced by a shared contract suite.

Integrations

  • LangGraph / LangChain — sandboxio.integrations.langgraph.make_code_tool() returns a native BaseTool (sandboxio[langgraph]).
  • OpenAI Agents SDK — sandboxio.integrations.openai_agents.make_code_tool() returns a native FunctionTool (sandboxio[openai-agents]).
  • MCP — python -m sandboxio.mcp --backend docker://python:3.12-slim serves run_python, run_command, file tools and sandbox_info (sandboxio[mcp]), also as a container image.

Documentation

docs.sandboxio.dev — the Markdown under docs/ is its source and stays the source, so nothing below moves. Read it here or there:

Security

Isolation tiers are reported, not assumed: CONTAINER is not a security boundary against hostile code, and sandboxio says so rather than implying otherwise.

Report vulnerabilities privately — see SECURITY.md. A report that a declared control did not apply is the highest-severity class this project has.

The project's own supply-chain posture is scored weekly by OpenSSF Scorecard and published — the badge above links to the run that produced it.

Contributing

Read CONTRIBUTING.md. Contributions need a DCO Signed-off-by line; there is no CLA.

License

Code is MIT. Prose in docs/ is CC BY 4.0; code samples inside those documents are MIT (ADR-0026).

Metadata

Release files for sandboxio 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sandboxio 0.1.0
File Size Uploaded
sandboxio-0.1.0.tar.gz 336.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sandboxio 0.1.0
File Interpreter ABI Platform
sandboxio-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 403.1 kB

Release files / sandboxio-0.1.0.tar.gz

Download URL sandboxio-0.1.0.tar.gz
Size 336.0 kB
Tags Source
SHA-256 checksum
How to use checksums
abc5884d74ee22d4407463751beb2e71924848a1a8452aa70b665902d9b5628f
BLAKE2b-256 checksum
How to use checksums
d623a2d44dcc88ec2addf9a8aa0a6de225ef018d08aedc29e4770b689234affe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release files / sandboxio-0.1.0-py3-none-any.whl

Download URL sandboxio-0.1.0-py3-none-any.whl
Size 67.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7bee9312d3d21d4af475782c1eca56d8447f398d92994caa316fc9d606db36ad
BLAKE2b-256 checksum
How to use checksums
525a59bd294b2729dc89366780c0db59d5dbc82a0a3ae4961522425117bef1a3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

0.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page