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,.pyistubs, andpy.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.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| microsandbox-0.7.4-cp310-abi3-win_arm64.whl | CPython 3.10 | abi3 | Windows ARM64 | Details |
| microsandbox-0.7.4-cp310-abi3-win_amd64.whl | CPython 3.10 | abi3 | Windows x86-64 | Details |
| microsandbox-0.7.4-cp310-abi3-manylinux_2_28_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.28+ x86-64 | Details |
| microsandbox-0.7.4-cp310-abi3-manylinux_2_28_aarch64.whl | CPython 3.10 | abi3 | Linux glibc 2.28+ ARM64 | Details |
| microsandbox-0.7.4-cp310-abi3-macosx_11_0_arm64.whl | CPython 3.10 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 219.2 MB
Release files / microsandbox-0.7.4-cp310-abi3-win_arm64.whl
| Download URL | microsandbox-0.7.4-cp310-abi3-win_arm64.whl |
|---|---|
| Size | 43.7 MB |
| Tags | CPython 3.10 Windows ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
0350ad111ae4ca60f0b8a4edee601e651ddd2d1695430d78e4d7a0a464958ba4
|
|
BLAKE2b-256 checksum How to use checksums |
cdcc27c24dac50b92dddf5a19af879a4fe5649ce8e49b66a707dd4ffaaead539
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","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.4-cp310-abi3-win_amd64.whl
| Download URL | microsandbox-0.7.4-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 41.1 MB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
6a46c55a48f13a9a15c3f43b312de9fd2bf46291c29e78e801e860db30d216ee
|
|
BLAKE2b-256 checksum How to use checksums |
4fff1c19df8a2bb42b656c0eacd43b4a751e61012fbdd6f78886c113abc3c411
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","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.4-cp310-abi3-manylinux_2_28_x86_64.whl
| Download URL | microsandbox-0.7.4-cp310-abi3-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 44.0 MB |
| Tags | CPython 3.10 Linux glibc 2.28+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
9741bc902f56b5599b015e5570f579cab1d00cc975ce58ecde538a53496be9b1
|
|
BLAKE2b-256 checksum How to use checksums |
b0ed4f6647563a8e417d81e7b75d85f31b0568966f6216077ba8bc65ad6a4e51
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","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.4-cp310-abi3-manylinux_2_28_aarch64.whl
| Download URL | microsandbox-0.7.4-cp310-abi3-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 46.4 MB |
| Tags | CPython 3.10 Linux glibc 2.28+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
772480a584a2b9de4210cccb4849f6f415fcff85c4195c94cf5ce19ca1bed1ab
|
|
BLAKE2b-256 checksum How to use checksums |
a4d1c164ca1ca374546dbe6889479610d0c96f6da68af3909beb54b0387797c2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","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.4-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | microsandbox-0.7.4-cp310-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 43.9 MB |
| Tags | CPython 3.10 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
c104be33afb334a52ec1115e836e849f32df513cd5b30a064ae0a5428e38b638
|
|
BLAKE2b-256 checksum How to use checksums |
dc9afceee54a6cf8ef8c507612b74dc435f88ab4d8d7fa76d7dff0f066be1041
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","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}
|