What is a vpod ?
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.
How it works
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.
RV64GC Specification
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.
Getting started
CLI
curl -fsSL https://install.vpod.sh | shOr install via PowerShell (windows)
irm https://install.vpod.sh | iex
Or install via cargo
# Pull a snapshot vpod pull alpine:latest # Start an interactive shell vpod
Python SDK
from 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) # 6
Important
The first call to Sandbox.create() downloads the default snapshot (alpine) and caches it locally if not already present.
Documentation
Full reference for the CLI and Python SDK.
CLI
| 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 |
Options
--mount or -m
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
Python SDK
| 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.create() parameters
snapshot
sandbox = Sandbox.create(snapshot="alpine")
mounts
sandbox = Sandbox.create(mounts={"workspace": "/workspace:rw", "docs": "/docs" })
Snapshots
| Name | tag | Description | Memory Limit (RAM) |
|---|---|---|---|
alpine |
3.23.0 | Minimal Alpine Linux snapshot. | 256 MB |
vsnap-base |
1.0.0 | Alpine-based snapshot with Python pre-installed. | 256 MB |
vsnap-data |
1.0.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)
Snapshot API
| Method | Description | Return type |
|---|---|---|
snapshots.catalog() |
Fetch available snapshots | list[dict] |
snapshots.pull(name) |
Pull a snapshot | str |
from vpod import snapshots for snap in snapshots.catalog(): print(snap["name"], snap["tag"]) snapshots.pull("vsnap-data")
Limitations
- 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.
Contributing
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.sh
This creates dist/alpine-3.23.0-256mb.snap.
Important
To use it locally, uncomment lines in resolve_snapshot() in crates/vpod/src/main.rs.
License
This project is licensed under the Apache License 2.0. See the LICENSE file for details.