Python Runtime
The Python runtime is powered by the Rivet Secure Exec project, which embeds Pyodide — CPython 3.13 compiled to WebAssembly — inside the same isolate that runs guest JavaScript. Guest Python is fully sandboxed from the host: every file read, network connection, and subprocess goes through the kernel, never a real host API.
Why Pyodide, not a native WASM build
Section titled “Why Pyodide, not a native WASM build”Most agentOS software (coreutils, ripgrep, jq, …) ships as unmodified upstream binaries compiled to wasm32-wasip1 against a custom libc and a patched Rust std/sysroot. The portability work lives in that shared libc/std layer, so the programs themselves are not forked or rewritten per‑WASM.
Python is the deliberate exception. CPython is a large C runtime that dynamically loads C extension modules (numpy, pandas, and most of the scientific stack are native code) and leans on OS facilities like threads and signals — none of which map cleanly onto the wasip1 + custom‑libc model that suits self‑contained Rust/C CLIs. Porting CPython and its extension ecosystem to that toolchain would be a huge, duplicative maintenance burden.
Pyodide already solves exactly this: it is the upstream CPython‑on‑WebAssembly project, shipping a full interpreter plus a precompiled package ecosystem on the emscripten target, and it runs in the same V8 isolate as guest JavaScript. agentOS embeds it rather than maintaining its own CPython port — which is also why the runtime targets emscripten (not wasip1) and carries the behavioral differences listed below.
Running Python
Section titled “Running Python”python (and the python3 alias) is a first-class command, resolved by the runtime exactly like node — no install step, no node_modules/venv. Run it through the normal command API:
await vm.execArgv("python", ["-c", "print(1 + 1)"]); // inline codeawait vm.exec('python /workspace/main.py alpha beta'); // script + sys.argvawait vm.execArgv("python", ["-m", "json.tool"]); // module (-m)await vm.execArgv("python", ["-"], { stdin: "print('hi')\n" }); // program on stdinSupported invocation forms: -c CODE, a script path, -m MODULE (via runpy), - / piped stdin programs, and a bare interactive REPL (PS1/PS2, EOF to exit). Each form sets sys.argv the way CPython does.
Packages and native modules
Section titled “Packages and native modules”- Bundled, offline:
numpyandpandasship with the runtime and import with no network access. They are real native (C/Fortran) libraries — compiled ahead of time to WebAssembly by Pyodide. pip/micropip:pip install <pkg>(andpython -m pip ...) installs wheels through Pyodide’smicropip. This covers pure-Python wheels and packages that already have a Pyodide/emscripten WASM wheel. Wheel downloads go through the kernel network adapter, so egress obeys the VM’s network policy (default-deny + allowlist) — never an ambient host fetch.requestsis shimmed to route HTTP through the kernel bridge, so common HTTP code works under the same network policy.
Differences from a normal CPython install
Section titled “Differences from a normal CPython install”The runtime targets practical parity for agent workloads, but it is Pyodide/WASM, not a host CPython. Know these gaps:
- Ephemeral per-process state. Every
python(orpip) invocation is a fresh interpreter. Apip installin one command does not persist to a later, separate command — there is no sharedsite-packageson disk. Install a package and use it within the same program. - Filesystem scope. Only
/workspaceis bridged into the Python filesystem. Scripts you run and files you open with Python must live under/workspace; paths like/tmpare not visible to the interpreter (even though guest shell commands can see them). - No
/bin/pythononPATH.pythonis a runtime command intercepted at exec time (the same model asnode, which also has no/bin/node).vm.exec/execArgv/spawnroute it directly; a literalwhich pythonorsh -c "python …"PATH-file lookup inside the guest shell will not find it. - Native extensions need a WASM wheel. Arbitrary C/Rust extension modules cannot be compiled at install time. A package only works if it is pure Python or ships a Pyodide/emscripten wheel; the bundled set is
numpy+pandas. - Single-threaded, no real processes. Pyodide is single-threaded WASM: no OS threads, no
os.fork, nomultiprocessing.subprocess.runis shimmed to dispatch through the kernel (so you can launch other runtime commands likenode), but it does not acceptinput=and is not a full POSIXfork/exec. - Networking is brokered. Sockets and HTTP go through the kernel network adapter under the VM’s policy;
requests,pyodide.http, andmicropipare wired to it. Low-level/raw socket use is limited to what the bridge supports. - Bounded by default. Python runs in the shared isolate model — heap, CPU time, and captured output are bounded, and a runaway execution terminates its isolate rather than the host (see Limits & Observability).
For the underlying runtime internals, see the Secure Exec project at secureexec.dev.