Single-pass SSA bytecode compiler and threaded-code stack VM for a sandboxed Python subset. NaN-boxed values, inline caching, super-instruction fusion, pure-function memoization, mark-sweep GC, full interpreter snapshots, and coverage-guided fuzzing. Runs in the browser as a WebAssembly module and natively inside the CLI.
- Secure by default. No file, network, or environment access, unless explicitly enabled by the host.
- Around 200 KB footprint. The full compiler and runtime ship as a single WASM binary.
- Compile-time imports. Every module resolves at parse time, no dynamic loading, no runtime surprises.
- No AST. Source compiles directly to bytecode in a single pass: O(n).
- Snapshots. Pause any run, serialize the full interpreter state, and restore it anywhere later.
- Docs (try Edge Python directly in your browser): edgepython.com
A Cargo workspace at the repo root holds the engine, abi and pdk. cli/, fuzz/ and each std/* package are standalone workspaces with their own build and test commands; the commands below run from the repo root.
├── abi
├── cli
│ └── src
│ ├── cmd
│ └── engine
├── docs
├── fuzz
├── host
├── pdk
├── runtime
├── src
│ ├── lexer
│ ├── native
│ │ └── builtins
│ ├── packages
│ ├── parser
│ ├── util
│ ├── value
│ ├── vm
│ │ ├── globals
│ │ ├── methods
│ │ └── opcodes
│ └── wasm
├── std
└── tests
└── cases
cargo wasm # local release .wasm (CI ships a further size-optimised build)
cargo build --release # host .rlib + cdylib for Rust embedders
cargo clippy --lib --features native # lint the native engine module
cargo test --release # run the compiler test suiteEach std/* package builds its own .wasm with cargo build --release --target wasm32-unknown-unknown run inside the package folder. The folder name is the package name, and Rust-keyword crates rename the artifact (struct builds edge_struct.wasm). std/test is pure Edge Python (src/entry.py) and needs no build. Each package's corpus is <name>/<name>.json, an array of {src, output} or {src, error} cases, and the shared runner prepends from <name> import * to each one:
deno test --allow-all std/harness/ # STDPKG=<name> narrows to one packageTo add a std package, create std/<name>/ with the crate (or src/entry.py for a script-only package) plus its corpus. No harness edits needed.
The host libraries in host/* are plain ESM, tested through headless Chromium. Their corpora add optional html, http_mocks, and ws_mocks fixtures per case:
deno run -A npm:playwright install --with-deps chromium # once
cd host && HOSTCAP=<dom|network|storage|time> deno test --allow-all tests/The browser runtime lints and tests with Deno too, deno lint runtime/ and deno test --allow-all runtime/tests/runtime.test.js.
Single-pass pipeline: source -> SSA bytecode chunk; stack interpreter with adaptive inline caching and pure-function memoization.
- Lexer (
src/lexer/) LUT-driven, offset-based tokens. - Parser (
src/parser/) Pratt precedence, SSA-versioned bytecode withPhiat joins, no AST. - Optimizer (
src/optimizer.rs) constant folding, Phi-noop elimination, dead-code compaction. - Values (
src/value/) NaN-boxed 64-bitVal, heap objects, and the mark-and-sweep arena the whole pipeline shares. - VM (
src/vm/) flat-match dispatch, scalar + instance-dunder inline caches, pure-function template memoization;opcodes/implements opcodes,globals/the global functions,methods/the builtin-type methods. - Resolver (
src/packages/) host-injected; native imports register forCallExterndispatch.
Full rationale, NaN-box patterns, IC thresholds, GC roots, and intentional omissions: Design. Lexer and parser internals: Lexical, Syntax.
Native modules ship via four delivery paths (CDN .wasm, native .so/.dylib plugin, host capability, JS host module), see Writing modules.
Download it to your machine (reference docs):
# Compatible with macOS, Linux and WSL
curl -fsSL https://cdn.edgepython.com/cli/install.sh | sh
# Or from source (any platform with Rust + Cargo)
cargo install --path cli
edge -h # List all commandsrun, repl and test execute in the built-in native engine; --web hosts the runtime in a headless Chromium instead, and install.sh downloads a pinned chrome-headless-shell into ~/.cache/edge unless a system Chrome/Chromium is already installed (EDGE_NO_BROWSER=1 skips it).
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script type="module" src="https://cdn.edgepython.com/runtime/src/element.js"></script>
</head>
<body>
<edge-python entry="./app/main.py" packages="./app/packages.json"></edge-python>
</body>
</html>The runtime spawns a Web Worker that pre-fetches imports, dispatches native calls, and streams print() output back.
Edge Python is a cdylib: a Rust host can instantiate compiler.wasm and call its exports directly, the same .wasm that ships to browsers; the host owns I/O. The crate fetches nothing at build time, so vendor the .wasm from a tagged release and pin it by checksum, see Consuming the release. To add native modules from your own crate, implement the Resolver trait, see Writing modules.
edge run, edge repl, and edge test execute in the CLI's in-process native engine by default (--web restores Chromium); tagged releases and the CDN's /native/ route carry each std package as a native plugin library (native engine).
# hello.py
async def greet(name):
await sleep(0.1)
print(f"hello {name}")
await greet("edge")$ edge run hello.py
hello edge
Imports, std packages, and the built-in time / network modules resolve without a browser:
# app.py
import json
from "./lib/helper.py" import double
data = json.loads('{"n": 21}')
await sleep(0.1)
print(json.dumps({"result": double(data["n"])}))$ edge run app.py
{"result":42}
Edge Python targets sandboxed execution, in the browser and in the CLI's native engine: a dynamic, multi-paradigm Python subset with classes, async/await, structural pattern matching, and compile-time module resolution. There is no bundled stdlib, modules are external artifacts.
Full language reference, scope, and what intentionally isn't supported: What Edge Python is.
Coverage-guided fuzzing of the lex -> parse -> VM pipeline lives in fuzz/, built on cargo-afl (AFL++) and running on stable Rust. Commands, the parallel/container campaigns, and crash triage: Fuzzing.
The docs in docs/ are a Nextra static export. Run npm install once, then npm run dev to work locally. In dev each page compiles on first visit (slower under WSL, where the repo sits on /mnt/c), then navigation is instant. npm run build pre-renders every page into out/, so production serves static HTML only.
Any python code block immediately followed by a text Output block becomes an interactive playground that runs the snippet in the real runtime, so an example and its stated output are always a verifiable pair.
One workflow .github/workflows/main.yml runs the complete CI/CD; each package's logic lives in a composite action under .github/actions/.
On pushes to main it deploys two Cloudflare Pages projects: edge-python-cdn (the bundled package artifacts) and edge-python-docs (served at edgepython.com).
Apache-2.0
- PyneSys, since May 2026