Skip to main content

microsandbox

Lightweight VM sandboxes for Python applications that need hardware-level isolation for AI agents, tools, tests, and untrusted code.

The microsandbox Python package provides async Python bindings to the microsandbox runtime. It creates microVM-backed sandboxes from OCI images or other rootfs sources, then exposes command execution, guest filesystem access, networking, secrets, volumes, metrics, logs, snapshots, and SSH/SFTP through Python-friendly classes and dataclasses.

For the full API reference and longer guides, use the docs site:

A complete runtime in the configured home (MSB_HOME, or ~/.microsandbox by default) takes precedence over wheel binaries. Explicit binary paths still win. A partial home installation errors instead of falling back to the wheel. This also applies to the packaged CLI entry points.

Features

  • Hardware VM isolation with a guest Linux kernel
  • Async sandbox lifecycle, execution, filesystem, metrics, and logs APIs
  • OCI image, bind-rootfs, disk-image, and snapshot-based sandboxes
  • Named volumes, bind mounts, tmpfs mounts, and disk-image mounts
  • Network policies, DNS filtering, TLS interception, secrets, and port publishing
  • Rootfs patches before boot
  • Detached sandboxes that can outlive the Python process
  • Typed Python surface with StrEnums, frozen dataclasses, event objects, .pyi stubs, and py.typed

Requirements

  • Python 3.10+
  • Linux with KVM, macOS with Apple Silicon, or Windows 11 with WHP enabled
  • Windows support is currently preview; see the Windows troubleshooting guide for WHP and runtime setup notes.

Supported Platforms

Platform Architecture Notes
macOS ARM64 / Apple Silicon Wheel bundles msb and libkrunfw
Linux x86_64 Wheel bundles msb and libkrunfw
Linux ARM64 Wheel bundles msb and libkrunfw
Windows x86_64, ARM64 Preview; requires WHP

Python wheels bundle the matching msb runtime and libkrunfw library. Source checkouts and unreleased local builds can override runtime paths with MSB_PATH, MSB_LIBKRUNFW_PATH, or microsandbox.set_libkrunfw_path(...).

Installation

pip install microsandbox

Quick Start

import asyncio

from microsandbox import Sandbox


async def main() -> None:
    async with await Sandbox.create("python-readme", image="alpine", replace=True) as sandbox:
        output = await sandbox.shell("echo 'Hello from microsandbox!'")
        print(output.stdout_text.strip())


asyncio.run(main())

async with stops and removes the sandbox when the block exits. Use Sandbox.create(...) without a context manager when you want to control stop(), kill(), or remove() yourself.

Reusable Lifecycle Convergence

Use connect_or_create when a stable name should converge on one persisted sandbox. Existing configuration wins; creation arguments are used only if creation is necessary. Handles retain a stable id, so lifecycle calls on stale receivers refuse to act on a replacement that reused the name.

from microsandbox import SandboxStatus

sandbox = await Sandbox.connect_or_create("worker", image="python", memory=1024)

print(f"{await sandbox.name}: {await sandbox.id}")
running = await (await Sandbox.get("worker")).connect_or_start()
await running.request_stop()
stopped = await running.wait_for_status(SandboxStatus.STOPPED)
restarted = await stopped.restart()
await restarted.destroy()

Common Examples

These snippets assume you already have a live sandbox: Sandbox.

Command Execution

import sys

from microsandbox import ExecEventType

output = await sandbox.exec("python3", ["-c", "print(1 + 1)"])
print(output.stdout_text)
print(output.exit_code)

output = await sandbox.shell("echo hello && pwd")
print(output.stdout_text)

output = await sandbox.exec(
    "python3",
    ["script.py"],
    cwd="/app",
    env={"PYTHONPATH": "/app/lib"},
    timeout=30.0,
)

handle = await sandbox.exec_stream("tail", ["-f", "/var/log/app.log"])
async for event in handle:
    match event.event_type:
        case ExecEventType.STDOUT:
            sys.stdout.buffer.write(event.data)
        case ExecEventType.STDERR:
            sys.stderr.buffer.write(event.data)
        case ExecEventType.EXITED:
            break

Filesystem Operations

fs = sandbox.fs

await fs.write("/tmp/config.json", b'{"debug": true}')
print(await fs.read_text("/tmp/config.json"))

for entry in await fs.list("/etc"):
    print(f"{entry.path} ({entry.kind})")

await fs.copy_from_host("./local-file.txt", "/tmp/file.txt")
await fs.copy_to_host("/tmp/output.txt", "./output.txt")

if await fs.exists("/tmp/config.json"):
    meta = await fs.stat("/tmp/config.json")
    print(f"size: {meta.size}, kind: {meta.kind}")

Named Volumes

from microsandbox import Sandbox, Volume

data = await Volume.create("python-readme-data", quota_mib=100)

writer = await Sandbox.create(
    "python-readme-writer",
    image="alpine",
    volumes={"/data": Volume.named(data.name)},
    replace=True,
)
await writer.shell("echo 'hello' > /data/message.txt")
await writer.stop()

reader = await Sandbox.create(
    "python-readme-reader",
    image="alpine",
    volumes={"/data": Volume.named(data.name, readonly=True)},
    replace=True,
)
output = await reader.shell("cat /data/message.txt")
print(output.stdout_text.strip())
await reader.stop()

Network, DNS, and Ports

from microsandbox import Network, NetworkProfile, Sandbox
from microsandbox.types import DnsConfig

isolated = await Sandbox.create(
    "python-readme-isolated",
    image="alpine",
    network=Network.none(),
    replace=True,
)

filtered = await Sandbox.create(
    "python-readme-filtered",
    image="alpine",
    network=Network(
        deny_domains=("blocked.example.com",),
        deny_domain_suffixes=(".evil.com",),
        dns=DnsConfig(nameservers=("1.1.1.1:53",)),
    ),
    replace=True,
)

web = await Sandbox.create(
    "python-readme-web",
    image="python",
    ports={8080: 80},
    network=Network.from_profiles(NetworkProfile.PUBLIC),
    replace=True,
)

Secrets

Secrets use placeholder substitution. The real value stays on the host and is substituted only for allowed network destinations.

import os

from microsandbox import Sandbox, Secret

sandbox = await Sandbox.create(
    "python-readme-agent",
    image="python",
    secrets=[
        Secret.env(
            "OPENAI_API_KEY",
            value=os.environ["OPENAI_API_KEY"],
            allow=["api.openai.com"],
        ),
    ],
    replace=True,
)

Rootfs Patches

from microsandbox import Patch, Sandbox

sandbox = await Sandbox.create(
    "python-readme-patched",
    image="alpine",
    patches=[
        Patch.text("/etc/greeting.txt", "Hello!\n"),
        Patch.mkdir("/app", mode=0o755),
        Patch.text("/app/config.json", '{"debug": true}', mode=0o644),
        Patch.append("/etc/hosts", "127.0.0.1 myapp.local\n"),
    ],
    replace=True,
)

Detached Mode

sandbox = await Sandbox.create(
    "python-readme-background",
    image="python",
    detached=True,
    replace=True,
)

handle = await Sandbox.get("python-readme-background")
reconnected = await handle.connect()
output = await reconnected.shell("echo reconnected")
print(output.stdout_text.strip())

TLS Interception

from microsandbox import (
    Network,
    Sandbox,
    ScopedUpstreamCACert,
    ScopedVerifyUpstream,
    TlsConfig,
)

sandbox = await Sandbox.create(
    "tls-inspect",
    image="python",
    network=Network(
        tls=TlsConfig(
            bypass=("*.googleapis.com",),
            verify_upstream=True,
            intercepted_ports=(443,),
            upstream_ca_certs=("/etc/ssl/corp-root.pem",),
            scoped_upstream_ca_certs=(
                ScopedUpstreamCACert("api.internal", "./certs/api-ca.pem"),
            ),
            scoped_verify_upstream=(
                ScopedVerifyUpstream("*.preview.internal", False),
            ),
        ),
    ),
)

Metrics

from microsandbox import MiB, all_sandbox_metrics

metrics = await sandbox.metrics()
print(f"CPU: {metrics.cpu_percent:.1f}%")
print(f"Memory: {metrics.memory_bytes // MiB} MiB")

async for sample in sandbox.metrics_stream(interval=1.0):
    print(f"CPU: {sample.cpu_percent:.1f}%")
    break

for name, sample in (await all_sandbox_metrics()).items():
    print(f"{name}: {sample.cpu_percent:.1f}%")

Typed Errors

Python exports typed errors for the common SDK categories and falls back to MicrosandboxError for unmapped runtime variants. Catch specific errors when you need category-specific handling, and catch MicrosandboxError as the broad SDK base class.

from microsandbox import MicrosandboxError, Sandbox, SandboxAlreadyExistsError

try:
    await Sandbox.create("worker", image="alpine")
except SandboxAlreadyExistsError:
    print("already exists; resume it or pass replace=True")
except MicrosandboxError as exc:
    print(f"microsandbox error: {exc}")

Runtime Setup

Installed wheels bundle the runtime files. The setup helpers are useful for source checkouts, shared runtime installs, and surfacing setup failures at process startup.

from microsandbox import ensure_runtime

runtime = await ensure_runtime()
print(runtime.msb_path, runtime.libkrunfw_path)

More Documentation

Development

From sdk/python:

uv sync --group dev
uv run maturin develop --release
uv run pytest tests
uv run ruff check .

From the repository root, run an example against the SDK project:

uv run --project sdk/python python examples/python/root-oci/main.py

Runtime integration tests require local virtualization support and runtime artifacts:

cd sdk/python
uv run pytest integration/test_create_kwargs.py integration/test_exec.py

License

Apache-2.0

Release files for microsandbox 0.7.0

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

Built distributions (wheels)

Table of built distributions (wheels) for microsandbox 0.7.0
File
microsandbox-0.7.0-cp310-abi3-win_arm64.whl CPython 3.10 abi3 Windows ARM64 Details
microsandbox-0.7.0-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details
microsandbox-0.7.0-cp310-abi3-manylinux_2_28_x86_64.whl CPython 3.10 abi3 Linux glibc 2.28+ x86-64 Details
microsandbox-0.7.0-cp310-abi3-manylinux_2_28_aarch64.whl CPython 3.10 abi3 Linux glibc 2.28+ ARM64 Details
microsandbox-0.7.0-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details

Total release size: 214.9 MB

Release files / microsandbox-0.7.0-cp310-abi3-win_arm64.whl

Download URL microsandbox-0.7.0-cp310-abi3-win_arm64.whl
Size 43.0 MB
Tags CPython 3.10 Windows ARM64 abi3
SHA-256 checksum
How to use checksums
9cdba1738e5b390215705a2a9c75a2f3373f85dd4f8eb28786fc1977623004a1
BLAKE2b-256 checksum
How to use checksums
756ac4c84187dae9e15b7d9343b77158efadf3dcf8db9d5792adb160e22bf867
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / microsandbox-0.7.0-cp310-abi3-win_amd64.whl

Download URL microsandbox-0.7.0-cp310-abi3-win_amd64.whl
Size 40.2 MB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
5938228af467530175fc8d29c9b13f11baa533214a1265313b67dc32b06b4b55
BLAKE2b-256 checksum
How to use checksums
475c4d539df71f50e38be7ae347291691003974ca2a7ef5785c5c4f4e1218cd4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / microsandbox-0.7.0-cp310-abi3-manylinux_2_28_x86_64.whl

Download URL microsandbox-0.7.0-cp310-abi3-manylinux_2_28_x86_64.whl
Size 43.1 MB
Tags CPython 3.10 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
848eab6e23b3bc168934b3093baafe26b086348d2914ae710900884e7bb74470
BLAKE2b-256 checksum
How to use checksums
ec7851ac81b69b8d24977a4d949b82f362032a594343c13eeb98d9cf1d18deb7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / microsandbox-0.7.0-cp310-abi3-manylinux_2_28_aarch64.whl

Download URL microsandbox-0.7.0-cp310-abi3-manylinux_2_28_aarch64.whl
Size 45.5 MB
Tags CPython 3.10 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
e4238849c6337107502c7c3694a0ece7e948267cc04e3aca96a08fa58958ef73
BLAKE2b-256 checksum
How to use checksums
520612dd1ac51481bacf874217f2c2a7ce9d63206d40c507bbc70354ff4cb94a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / microsandbox-0.7.0-cp310-abi3-macosx_11_0_arm64.whl

Download URL microsandbox-0.7.0-cp310-abi3-macosx_11_0_arm64.whl
Size 43.1 MB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
64dc76fd3189b690eec9bb31fc27388dfe30bbefdfb893fba300697a0862286f
BLAKE2b-256 checksum
How to use checksums
88946f534be296f4dcabf7f64aecd9673d7d7dcd0c2a036d2f403c8b25c30dda
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

0.7.3

5 release files

0.7.2

5 release files

0.7.1

5 release files

This release

0.7.0 This release

5 release files

0.6.16

5 release files

0.6.15

5 release files

0.6.14

5 release files

0.6.13

5 release files

0.6.12

5 release files

0.6.11

5 release files

0.6.10

5 release files

0.6.9

5 release files

0.6.8

5 release files

0.6.7

5 release files

0.6.6

5 release files

0.6.5

5 release files

0.6.4

5 release files

0.6.3

5 release files

0.6.2

5 release files

0.6.1

5 release files

0.6.0

5 release files

0.5.10

3 release files

0.5.8

3 release files

0.5.7

3 release files

0.5.6

3 release files

0.5.5

3 release files

0.5.4

3 release files

0.5.3

3 release files

0.5.2

3 release files

0.5.1

3 release files

0.5.0

3 release files

0.4.6

3 release files

0.4.5

3 release files

0.4.4

3 release files

0.4.3

3 release files

0.4.2

3 release files

0.4.1

3 release files

0.4.0

3 release files

0.3.14

3 release files

0.3.13

3 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.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