A vpod is a lightweight, portable sandbox that gives an untrusted process an instant Linux environment. It uses a RISC‑V architecture and runs entirely inside WebAssembly.
- Fast startup : Boot in under a second.
- Portable : Runs anywhere without any setup required.
- Isolated : All execution state stays inside the WASM sandboxes.
A vpod runs a RISC‑V virtual machine compiled to WebAssembly, implementing the RV64GC specification. When you start a vpod, it boots from a snapshot, a saved VM state ready in under a second.
The WASM component communicates with the host through WASI 0.2, providing controlled access to filesystem, networking, and standard I/O while keeping all execution state (CPU registers, memory, filesystem) isolated inside the sandbox.
G (General-purpose extensions)
- I : Base 64-bit integer instruction set.
- M : Hardware multiply and divide, useful for hashing and cryptography.
- A : Atomic operations for thread-safe programs.
- F/D : Single and double-precision floating-point, suited for scientific computing and ML inference.
C (Compressed instructions) Reduces code size by 30%, improving instruction fetch speed and memory efficiency. This matters when running a full Linux userspace inside our memory-constrained WASM environment.
Note
The V (vector) extension is not implemented. RVV instructions would execute as emulated RISC-V; there is no SIMD passthrough to the host CPU. Adding V would increase emulation overhead without any performance benefit for vectorized workloads.
curl -fsSL https://install.vpod.sh | shOr install via PowerShell (windows)
irm https://install.vpod.sh | iex
Or install via cargo
cargo install vpod
# Pull a snapshot
vpod pull alpine:latest
# Start an interactive shell
vpodpip install vpodfrom vpod import Sandbox
# Run a command
sandbox = Sandbox.create()
result = sandbox.commands.run("whoami")
print(result.stdout) # root
sandbox.close()
# Persistent session — state preserved across calls
with Sandbox.create() as sandbox:
sandbox.commands.run("export API_KEY=secret")
result = sandbox.commands.run("echo $API_KEY")
print(result.stdout) # secret
# Python REPL — variables persist
with Sandbox.create() as sandbox:
sandbox.code.run("import requests")
sandbox.code.run("data = [1, 2, 3]")
result = sandbox.code.run("print(sum(data))")
print(result.text) # 6Important
The first call to Sandbox.create() downloads the default snapshot (alpine) and caches it locally if not already present.
Full reference for the CLI and Python SDK.
| Command | Description |
|---|---|
vpod |
Start an interactive shell with default snapshot |
vpod <snapshot> |
Start an interactive shell with a specific snapshot |
vpod pull <snapshot> |
Pull a snapshot |
vpod list |
List available snapshots |
Create a link between your host and your sandbox by mounting a directory. You can configure read-only or read-write permissions for better access control.
vpod --mount workspace:/workspace # read only
vpod --mount workspace:/workspace:rw # read and write| Method | Description |
|---|---|
Sandbox.create() |
Create a new sandbox |
sandbox.commands.run(cmd) |
Run a command |
sandbox.code.run(code) |
Run Python code |
from vpod import Sandbox
with Sandbox.create() as sandbox:
sandbox.commands.run("echo 'from shell' > /tmp/shared.txt")
sandbox.code.run("print(open('/tmp/shared.txt').read().strip())")sandbox = Sandbox.create(snapshot="alpine")sandbox = Sandbox.create(mounts={"workspace": "/workspace:rw", "docs": "/docs" })| Name | tag | Description | Memory Limit (RAM) |
|---|---|---|---|
alpine |
3.23.0 | Minimal Alpine Linux snapshot. | 256 MB |
vsnap-base |
0.1.0 | Alpine-based snapshot with Python pre-installed. | 256 MB |
vsnap-data |
0.1.0 | Alpine-based snapshot with numpy, pandas, and scipy pre‑installed. |
512 MB |
with Sandbox.create(snapshot="vsnap-data") as sandbox:
sandbox.code.run("import pandas as pd; import numpy as np")
r = sandbox.code.run("s = pd.Series([1, 2, 3, 4, 5]); print(s.sum(), s.mean())")
print(r.text)| Method | Description | Return type |
|---|---|---|
snapshots.fetch_registry() |
Fetch available snapshots | list[dict] |
snapshots.pull(name) |
Pull a snapshot | str |
from vpod import snapshots
for snap in snapshots.fetch_registry():
print(snap["name"], snap["tag"])
snapshots.pull("vsnap-data")- Emulation overhead: No hardware acceleration in the WASM component. CPU-intensive workloads may run slower than native.
- No GPU access: CUDA, Metal, and hardware ML accelerators are not yet available. Support may be added in the future with wasi-nn.
- Env vars don't cross between shell and Python:
sandbox.commands.run("export FOO=bar")is not visible insandbox.code.run(...). Use the filesystem to share data between the two.
Prerequisites
- Rust (latest stable)
- Python 3.10+
Development setup
# Build WASM component
./scripts/build-wasm.sh
# Install CLI
cargo install --path crates/vpod
# Install Python SDK in dev mode
pip install -e sdks/python[dev]
# Run tests
cargo test # Rust tests
pytest sdks/python/tests/ -v -m integration # Integration tests (requires WASM build)Building snapshots
The project uses pre-built Alpine snapshots from registry.vpod.sh. To build a custom snapshot:
./scripts/build-default-snapshot.shThis creates dist/alpine-3.23.0-256mb.snap.
Important
To use it locally, uncomment lines in resolve_snapshot() in crates/vpod/src/main.rs.
This project is licensed under the Apache License 2.0. See the LICENSE file for details.
