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.

Fork a Live Sandbox

Forking copies a running or paused local sandbox's disk and execution state into an independent child. Memory uses copy-on-write automatically. The source keeps its previous running or paused state. Host resources require explicit bindings; see forking and resource bindings.

child = await sandbox.fork("experiment")
await child.stop()

Use await sandbox.fork_many(["alice", "bob"]) to capture once for several children. Inspect every returned outcome: one child's startup failure does not remove successful siblings. See the fork API reference.

Restoring starts from a saved snapshot instead. Use cow_memory=True to request copy-on-write memory for a full-snapshot restore. A generation describes snapshot-history progression; a branch describes a distinct path through that history. The former live branch APIs and old CoW restore names remain deprecated aliases. See restore migration notes for the old-to-new names and language-specific deprecation notices.

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}%")

Storage Usage and Runtime Cache Cleanup

Storage.usage() reports the selected local backend's aggregate storage. Sandbox and snapshot handles also provide storage_usage() for their managed files. Reports contain raw integer byte counts; None means unknown. Logical sizes and allocated-block observations do not measure exclusive physical ownership on filesystems that share copy-on-write blocks.

from microsandbox import Storage

usage = await Storage.usage()
print(usage.branch_memory.logical_bytes)

preview = await Storage.prune(dry_run=True, older_than_seconds=600)
for entry in preview.entries:
    print(entry.path, entry.state, entry.logical_bytes)

# Explicitly remove currently unused runtime RAM after rechecking ownership.
result = await Storage.prune(older_than_seconds=600)
print(result.logical_bytes_removed)

Pruning preserves durable snapshots, sandbox disks, named volumes, and stable lock files. Pending handoffs, live or paused VMs, and retained baselines protect their RAM. The report lists skipped entries and per-file errors, including partial success; physical_bytes_reclaimed remains None. Remote backend storage operations raise UnsupportedError. Static storage calls retain the backend selected when called, and handle methods retain the backend that created the handle.

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

Metadata

Release files for microsandbox 0.7.12

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.12
File Actions
microsandbox-0.7.12-cp310-abi3-win_arm64.whl CPython 3.10 abi3 Windows ARM64 Details for microsandbox-0.7.12-cp310-abi3-win_arm64.whl
microsandbox-0.7.12-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details for microsandbox-0.7.12-cp310-abi3-win_amd64.whl
microsandbox-0.7.12-cp310-abi3-manylinux_2_28_x86_64.whl CPython 3.10 abi3 Linux glibc 2.28+ x86-64 Details for microsandbox-0.7.12-cp310-abi3-manylinux_2_28_x86_64.whl
microsandbox-0.7.12-cp310-abi3-manylinux_2_28_aarch64.whl CPython 3.10 abi3 Linux glibc 2.28+ ARM64 Details for microsandbox-0.7.12-cp310-abi3-manylinux_2_28_aarch64.whl
microsandbox-0.7.12-cp310-abi3-macosx_14_0_arm64.whl CPython 3.10 abi3 macOS 14.0+ ARM64 Details for microsandbox-0.7.12-cp310-abi3-macosx_14_0_arm64.whl

Total release size: 240.8 MB

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

Download URL microsandbox-0.7.12-cp310-abi3-win_arm64.whl
Size 47.7 MB
Tags CPython 3.10 Windows ARM64 abi3
SHA-256 checksum
How to use checksums
7f3d51de9b59040f13e5809b6ab49689d1d463d4994481d34a23e514d32bfe3b
BLAKE2b-256 checksum
How to use checksums
a9416c6f467b4697b03d341243b74bebd0b4277b5881bc067823e0f232770d9b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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.12-cp310-abi3-win_amd64.whl

Download URL microsandbox-0.7.12-cp310-abi3-win_amd64.whl
Size 45.2 MB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
4ab74d8f7f23e6bcc86f3bdc372545cea42ed4a2f06ebc8ccb9977f7e4c8381a
BLAKE2b-256 checksum
How to use checksums
2f559e95cde06d4580d3ba6e460167e0505b901454a0f4504fd92415f335e707
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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.12-cp310-abi3-manylinux_2_28_x86_64.whl

Download URL microsandbox-0.7.12-cp310-abi3-manylinux_2_28_x86_64.whl
Size 49.1 MB
Tags CPython 3.10 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
532ebfd40d491a757fdbee4509cf05a367013116ae389143cd656074332fab3a
BLAKE2b-256 checksum
How to use checksums
485463bb702d06ca0032278db590342471c75ebcc08621fb2f4db928bbbd708d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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.12-cp310-abi3-manylinux_2_28_aarch64.whl

Download URL microsandbox-0.7.12-cp310-abi3-manylinux_2_28_aarch64.whl
Size 51.0 MB
Tags CPython 3.10 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
857fb2b077f38baaff0dbb678af009e296116db61ee644ba24f781814458c7b5
BLAKE2b-256 checksum
How to use checksums
132ae1c4f81829ebc62742eb7d1b15d7bdabb667c931ccb9b5fa58a606624679
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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.12-cp310-abi3-macosx_14_0_arm64.whl

Download URL microsandbox-0.7.12-cp310-abi3-macosx_14_0_arm64.whl
Size 47.8 MB
Tags CPython 3.10 abi3 macOS 14.0+ ARM64
SHA-256 checksum
How to use checksums
b157ebb43cf43c7ad0ade68202f97045cbd40bed38247223af2b9bc52b82a7b3
BLAKE2b-256 checksum
How to use checksums
873fa7be47657b89ed730ae3ef158a1ceefcceaf50059f241f2dd2187c819ec4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","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}

Security for microsandbox 0.7.12

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.7.12 This release

5 release files No provenance

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