pyex is a Python 3 interpreter written in Elixir, compiled to WebAssembly GC — built for running LLM-generated code. No processes, no ambient authority: effects are capabilities you hand in, execution is step-budgeted and deterministic, and every run returns an OpenTelemetry trace of what it did.
sandboxed by construction
Isolation isn't a wrapper around the interpreter — it's the shape of the interpreter. There is no path to the host that you didn't hand in as a value.
Files, network, storage, and clocks exist only if the host passes them in — attenuate them, or swap in copy-on-write overlays that stage every effect for review before a commit.
Steps, memory, and output are metered. A runaway while True dies with a clean Python error — never a hung host, never an OOM.
Seeded runs are byte-for-byte reproducible. The run you previewed is the run that commits — no time-of-check/time-of-use gap.
Every run returns a resource footprint and OpenTelemetry spans — including spans your Python emits itself with tracer.start_as_current_span.
one interpreter, three homes
One codebase, compiled two ways. The wasm running in this page's Cloudflare Worker is the same artifact the playground runs in your browser.
# Elixir — the source of truth (hex.pm/packages/pyex) {:ok, result, ctx} = Pyex.run(code, filesystem: fs, limits: [max_steps: 5_000_000]) # HTTP — Python at the edge, JSON out; spans + footprint ride along curl -s https://pyex.dev/api/run \ -H 'content-type: application/json' \ -d '{"code": "print(sum(range(101)))", "files": {"/data.json": "[1,2,3]"}}' {"ok":true,"ms":0,"stdout":"5050\n","footprint":{":steps":1,…},"files":{…},"spans":[…]}