Polyglot Genes — Write Genes in Rust, AssemblyScript, Go, or C
The Rotifer IR layer is WASM-Native, Polyglot by Design. The CLI today ships a built-in TypeScript → WASM path via Javy (QuickJS). Every other language — Rust, AssemblyScript, Go (TinyGo), C/C++, Zig — produces its own WASM and joins the Rotifer pipeline through the Bring-Your-Own-WASM (BYO-WASM) channel:
# 1. Compile your gene to WASM with the toolchain of your choicewasm-pack build --target nodejs # Rustnpx asc index.ts --outFile gene.wasm # AssemblyScripttinygo build -target=wasi -o gene.wasm . # Goemcc gene.c -O3 -s STANDALONE_WASM -o gene.wasm # C / Emscripten
# 2. Hand the WASM to the Rotifer CLIrotifer compile my-gene --wasm path/to/gene.wasmrotifer arena submit my-geneWhy this works. The Rotifer IR Specification §1.2 Positioning of Rotifer IR defines IR as a language-agnostic intermediate representation — multiple language frontends can target it. The CLI’s Javy path is one frontend among many. As long as your WASM honours the ABI contract below, it’s a first-class Rotifer Gene.
The ABI contract
Section titled “The ABI contract”Your WASM module must export one of two entry points plus memory:
| Style | Required exports | Typical producer |
|---|---|---|
| Rotifer | express(i32, i32) -> i32 + memory | Rust (#[no_mangle] extern "C"), AssemblyScript, Zig, hand-rolled WAT |
| WASI | _start + memory (no params, no return) | Anything that defaults to a WASI entry point |
For the Rotifer style, the two i32 parameters are (input_ptr, input_len)
into linear memory; the i32 return is a packed (output_ptr << 32) | output_len. The host reads / writes JSON across that buffer.
The WASI style is simpler — useful for hello-world fixtures and any language with a built-in WASI runtime.
Recipe 1 — Rust via wasm-pack / cargo
Section titled “Recipe 1 — Rust via wasm-pack / cargo”Cargo.toml:
[package]name = "my-rotifer-gene"version = "0.1.0"edition = "2021"
[lib]crate-type = ["cdylib"]
[profile.release]lto = trueopt-level = "z"strip = truesrc/lib.rs:
#[no_mangle]pub extern "C" fn express(input_ptr: i32, input_len: i32) -> i32 { // Real genes would: // 1. Read JSON input from linear memory at [input_ptr .. input_ptr + input_len]. // 2. Compute the result. // 3. Allocate output buffer in memory and return packed (ptr, len). 0}Build and submit:
rustup target add wasm32-unknown-unknowncargo build --release --target wasm32-unknown-unknownrotifer compile my-rust-gene --wasm target/wasm32-unknown-unknown/release/my_rotifer_gene.wasmrotifer arena submit my-rust-geneA working minimal Rust source lives in
tests/fixtures/polyglot/rust-style/source/
in the playground repository.
Recipe 2 — AssemblyScript
Section titled “Recipe 2 — AssemblyScript”AssemblyScript is the lowest-overhead path for TypeScript developers who want smaller WASM than Javy produces (~10-50 KB instead of ~700 KB).
index.ts:
export function express(inputPtr: i32, inputLen: i32): i32 { // Real genes would read input from memory, compute, and return packed (ptr, len). return 0;}asconfig.json:
{ "targets": { "release": { "outFile": "gene.wasm", "optimize": true, "runtime": "stub" } }}Build and submit:
npm install --save-dev assemblyscriptnpx asc index.ts --target releaserotifer compile my-as-gene --wasm gene.wasmrotifer arena submit my-as-geneA working minimal AssemblyScript source lives in
tests/fixtures/polyglot/as-style/source/.
Recipe 3 — Go via TinyGo
Section titled “Recipe 3 — Go via TinyGo”tinygo build -target=wasi -o gene.wasm ./gene.gorotifer compile my-go-gene --wasm gene.wasmTinyGo emits a WASI-style module; the IR pipeline accepts it via the WASI ABI.
Watch out for TinyGo’s compatibility caveats
— most of the Go standard library is supported, but reflection-heavy packages
(encoding/json with arbitrary types, text/template, etc.) may not work.
Recipe 4 — C / C++ via Emscripten
Section titled “Recipe 4 — C / C++ via Emscripten”emcc gene.c -O3 -s STANDALONE_WASM=1 -s EXPORTED_FUNCTIONS='["_express"]' -o gene.wasmrotifer compile my-c-gene --wasm gene.wasmSTANDALONE_WASM=1 is critical — without it Emscripten emits a glue layer
that depends on a JavaScript runtime, which the IR sandbox does not provide.
Status: BYO-WASM today, built-in compilation under review
Section titled “Status: BYO-WASM today, built-in compilation under review”| Language | Status | Path |
|---|---|---|
| TypeScript | ✅ Built-in (auto-detect index.ts) | esbuild + Javy/QuickJS |
| Rust | ✅ BYO-WASM | --wasm target/.../*.wasm |
| AssemblyScript | ✅ BYO-WASM | --wasm gene.wasm |
| Go (TinyGo) | ✅ BYO-WASM | --wasm gene.wasm (WASI ABI) |
| C / C++ | ✅ BYO-WASM | --wasm gene.wasm (STANDALONE_WASM) |
| Zig | ✅ BYO-WASM | --wasm gene.wasm |
| Python | ❌ Not viable (Pyodide ~10 MB exceeds WASM fuel budget) | — |
Promoting Rust + AssemblyScript from BYO-WASM to built-in compilation paths is under evaluation. The trigger is genuine community demand — open a GitHub issue or join the Discord if you’d find it useful.
Why not Python?
Section titled “Why not Python?”Python’s runtime cost in WASM is incompatible with the per-call fuel budget:
- Pyodide (full CPython in WASM) is ~10 MB and exhausts the fuel budget on module instantiation alone.
- MicroPython-WASM (~1 MB) is small enough but lacks most of the standard library and the AI/ML packages that would justify a Python frontend.
- CPython-WASI (3.12+, ~3 MB) is the most realistic option but is still 4× larger than Javy’s QuickJS.
More importantly, the libraries that make Python attractive for AI work (PyTorch, NumPy, Transformers) are C/Fortran extensions that cannot be compiled to WASM. A “Python Gene” would only be able to express pure-Python business logic — which TypeScript already covers without the runtime overhead.
For Python-heavy workloads, use a Wrapped Gene instead: declare the gene’s phenotype with a metadata pointer to your existing Python service, and let the Cloud Binding execute it. See Hybrid Gene Guide for the composition pattern.
Reference
Section titled “Reference”rotifer compile --wasm— CLI surface- Rotifer IR Specification §1.2 Positioning of Rotifer IR — language-agnostic IR design
tests/fixtures/polyglot/— minimal working WASM modules + source examples