Zippy Interpreter for Polyglot Programming
A portable polyglot runtime: one fast virtual machine for many languages, starting with JavaScript and Python.
Website · Playground · Download · Embed · Docs · Journal
ZIPP compiles every language it supports into one shared bytecode and runs it on one virtual machine, written in Rust. A JavaScript library and a Python script run on the same engine, with the same sandbox, the same limits and the same embedding API, wherever that engine goes: a native command line on Windows and Linux, a Rust library, or WebAssembly in browsers, Node.js, Deno and Bun.
Languages today: JavaScript and Python.
- JavaScript is complete and modern: ES2025, passing 99.999% of test262: 96,229 / 96,230 executions of the official conformance suite, unmodified.
- Python is an experimental subset, compiled straight to ZIPP bytecode (no
CPython inside), with a bundled
torchsubset for tensors, autograd and training. Its 196-program test corpus prints exactly what CPython 3.13 prints.
The virtual machine is built to take more languages: each one is a frontend that compiles to the shared bytecode and inherits everything below it (how a language plugs in).
| One VM, many languages | JavaScript and Python share one runtime, one object model and one garbage collector. Write the part that suits each language in that language. |
| Fast | A register VM with inline caches and, on x86-64, a native JIT. In its 0.0.26 capture ZIPP runs the 30 benchmark rows in 0.63× Node's time (the 13 everyday rows in 0.54×), starts in 7.1 ms median process launch, and as a pure interpreter takes 0.72× the time of Bellard's QuickJS. Performance |
| Correct | 99.999% of the pinned test262 corpus, unmodified; the one failure is a documented upstream expectation. Correctness |
| Sandboxed by default | Embedded programs reach nothing you have not allowed: no storage, files, network or host functions until you grant each one, with step and time limits. |
| Portable | Windows (x86-64), Linux (x86-64, arm64, armv7), and WebAssembly for every browser and server runtime. One .wasm file per engine. |
Every release publishes plain
files, checksummed in its SHA256SUMS:
| File | What it is |
|---|---|
zipp-0.0.27-windows-x86_64-portable.exe |
Windows command line. Run it from anywhere. |
zipp-0.0.27-windows-x86_64-installer.msi |
The same, installed for your user and added to PATH (no administrator rights needed). |
zipp-0.0.27-linux-x86_64, -linux-arm64, -linux-armv7 |
Linux command line for x86-64, 64-bit Arm and 32-bit Arm (hard float), built against glibc 2.35. |
zipp-0.0.27-javascript.wasm |
The JavaScript engine for browsers and server runtimes. |
zipp-0.0.27-javascript-lite.wasm |
The same without Intl and Temporal, built for size. |
zipp-0.0.27-javascript-python.wasm |
JavaScript and Python, with torch built in. |
zipp-0.0.27-javascript-python-base.wasm + zipp-0.0.27-torch-package.wasm |
JavaScript and Python, with torch as a separate add-on. |
zipp-0.0.27-<engine>.wasm.br |
Each of those .wasm files compressed with Brotli: about a quarter of the size. Serve it with Content-Encoding: br (the browser decodes it); the plain .wasm is the default. |
zipp-0.0.27-wasm-embed-kit.zip |
zipp.mjs, the one file that loads and sandboxes any of the .wasm engines, with types, examples and docs. |
Windows (PowerShell):
$version = '0.0.27'
Invoke-WebRequest "https://github.com/f2i-com/zipp.org/releases/download/v$version/zipp-$version-windows-x86_64-portable.exe" -OutFile zipp.exe
.\zipp.exe js .\app.jsOr download and open zipp-0.0.27-windows-x86_64-installer.msi, then use
zipp in a new terminal.
Linux:
version=0.0.27
arch=x86_64 # or arm64, armv7
curl -fL -o zipp "https://github.com/f2i-com/zipp.org/releases/download/v$version/zipp-$version-linux-$arch"
chmod +x zipp
./zipp js app.jszipp js app.js # a JavaScript script
zipp mjs app.mjs # a JavaScript module (import/export, top-level await)
zipp py main.py # a Python program (experimental), with the files beside it as its project
zipp --helpThe native command line uses its JIT on x86-64 and runs the program as
trusted code. To run code you do not trust natively, build the separate
hardened runner, zipp-sandbox: no JIT, no
unsafe code, and enforced instruction, heap, output and wall-clock limits.
You need two files from the release:
-
One engine
.wasm. Pick the smallest that runs your language:You need Download JavaScript, smallest (no Intl, noTemporal)zipp-0.0.27-javascript-lite.wasmJavaScript, complete zipp-0.0.27-javascript.wasmJavaScript and Python zipp-0.0.27-javascript-python-base.wasmJavaScript and Python with torch zipp-0.0.27-javascript-python.wasm, or the-baseengine pluszipp-0.0.27-torch-package.wasmwhen only some pages need torch -
zipp.mjs, the loader, fromzipp-0.0.27-wasm-embed-kit.zip. It loads any of the engines.
Put both next to your page, serve the folder over HTTP (python -m http.server
or npx serve; a page opened as file:// cannot load modules), and start
with nothing allowed:
import { loadZipp } from "./zipp.mjs";
const zipp = await loadZipp("./zipp-0.0.27-javascript.wasm");
const sandbox = await zipp.createSandbox(); // nothing is permitted
try {
const { output } = await sandbox.run('console.log("Hello from ZIPP")');
console.log(output); // ["Hello from ZIPP"]
} finally {
await sandbox.close();
}For Python, load a -python engine and pass { language: "python" } to
createSandbox. Then grant only what the program needs, one permission at a
time:
const sandbox = await zipp.createSandbox({
limits: { instructions: 50_000_000, timeoutMs: 5000 },
permissions: { network: ["https://api.example.com/"] }, // fetch() may reach this origin only
});What a sandbox does.
- Each sandbox is one program in its own engine and its own Worker (a
worker thread in Node). The program cannot see your page, its DOM,
localStorageor cookies, or Node'sprocess,requireand file system. - Everything outside it is denied until you grant it. JavaScript
programs can be given private storage (
storage), a map of files (files),fetchto listed URLs (network) and functions you choose (host). Python programs, in this release, can be given onlyfiles, which become their importable modules. - Three kinds of limit, enforced in different places. The step budget
(
limits.instructions, 50 million by default) is counted inside the engine and stops runaway computation anywhere. The time limit (limits.timeoutMs, 30 seconds by default) is enforced from outside by ending the Worker, so it needs the default isolation: withisolate: falsethe program runs on your thread, and only the step budget can stop a loop. Memory, string, output and nesting ceilings are fixed in the engine (zipp.profile.limitslists them). - Network access is an allowlist. List origins
(
"https://api.example.com") or URL prefixes ("https://example.com/data/");network: trueallows any http(s) URL. Either way, requests carry no cookies or credentials, the Fetch standard's forbidden headers are dropped, a redirect fails unless you allow redirects (and then only to listed URLs), and each request has a time and size limit. zipp.run(code)is not a sandbox. It runs the program on the calling thread with nothing permitted and the default step budget, but with no Worker and no time limit: use it for trusted code and quick checks, andcreateSandbox()for anything else.
This is layered protection, not a guarantee: WebAssembly's memory isolation,
an engine built without unsafe code or a JIT, default-deny capabilities, a
Worker per program, and limits. Keep your page's Content-Security-Policy (the
loader needs script-src 'self' blob: 'wasm-unsafe-eval' and
worker-src 'self' blob:), and read SECURITY.md for the
threat model. The embed kit guide has
every option, the WebAssembly engine reference
the engine's full API, and embedding the Rust
API.
The Python frontend runs folders of modules, a bundled torch subset (eager
CPU tensors, autograd, training) and, experimentally, torch.compile onto the
browser's WebGPU or WebGL2, WebAssembly SIMD kernels, or a native GPU through
wgpu. Try it in the playground; the
GPU guide, running Python,
Python frontend and
torch compatibility pages have the
detail.
Ratios are ZIPP's time over the other engine's, so lower is faster. From the
canonical capture at engine commit f1739644 (the 0.0.26 engine as a
profile-guided build; every engine with its production JIT, 15
counterbalanced repetitions, 18 October 2026):
| JIT against JIT | ZIPP / Node |
|---|---|
| All 30 rows | 0.634× |
| 13 everyday rows (JSON, regex, maps, classes, promises, parsing...) | 0.542×, faster on every one |
| 17 hostile stress rows | 0.715× |
ZIPP has 24 of 30 Node point wins: all 13 everyday rows and 11 of the 17 hostile ones. Node v24.19.0 · Bun 1.3.14 · Deno 2.6.10 · ZIPP 0.0.26 canonical PGO.
Measured the same day:
| Comparison | Ratio |
|---|---|
Interpreter against interpreter: ZIPP with ZIPP_NOJIT=1 / Bellard's QuickJS, 30 rows |
0.720× |
| ZIPP's interpreter / QuickJS-NG, 30 rows | 0.410× |
| ZIPP Python / CPython 3.13.14, 36 programs, in-process work time | 1.057× (0.966× on the micro kernels) |
| The published release build / the PGO build, 13 everyday rows | 1.11× |
The full tables, confidence intervals and the remaining gaps are in Performance and on zipp.org.
flowchart LR
JS[JavaScript] --> B[Shared register bytecode]
PY[Python] --> B
MORE[More languages] -.-> B
B --> VM[Interpreter]
VM --> JIT[Native JIT: x86-64, arm64]
VM <--> RT[One runtime: objects, GC, inline caches]
VM --> E[CLI · Rust library · WebAssembly]
| Path | What it holds |
|---|---|
crates/zipp-vm |
The VM: parser, compiler, bytecode, interpreter, GC, JITs, and the languages under src/lang/. |
crates/zipp-cli |
The zipp command line. |
crates/zipp-wasm |
The WebAssembly engines and the embed kit. |
crates/zipp-sandbox |
The hardened native runner for untrusted code. |
crates/zipp-gpu |
Native GPU execution for Python graphs. |
crates/regress-fork |
The regular-expression engine. |
How ZIPP works follows a program from source to machine code.
git clone https://github.com/f2i-com/zipp.org.git zipp
cd zipp
cargo build --locked --release
./target/release/zipp js app.jsYou need stable Rust (releases build with 1.92) and a C toolchain (the MSVC Build
Tools on Windows). Development covers the tests,
benchmarks and the WebAssembly build; crates/zipp-wasm/embed-kit/build-release.sh
builds every WebAssembly release file locally.
| Docs index | Everything, in one list |
| Reference | Architecture, language support, embedding, the CLI |
| Execution profiles | Which build to use for trusted and untrusted code |
| Security | The threat model and how to report a problem |
| Release notes | What changed in each version |
| Archive | History, including the previous README |
Bug reports with a small example, the expected output and your ZIPP version are the most useful contribution. Browse the issues or the performance roadmap, and see Development before changing the engine: keep output exact, measure every optimization, and report what did not work too.