Example · cross-tier
Three runners, one filesystem: a cross-tier handoff
node · host JS engineriscv · RISC-V VMboa · sandboxed JS
NanoVM's runners are peers over one kernel: they never call each other directly, but they share the kernel's in-memory filesystem, process table and router. This example makes that visible.
Step 1 runs a Node.js program on the host JS engine that writes report.json. Step 2 reads the same file with BusyBox cat on the RISC-V VM and prints uname -m from the emulated CPU. Step 3 hands the file to a Boa sandbox granted read-only file access. Three engines, one file.
Run it
Run the handoff
An async function body with nano and print() in scope. Every step reads the file the previous one wrote.
javascript
// Cross-tier handoff over one shared filesystem. This is an SDK snippet: an // async function body with `nano` (a booted Nano, engines.node = "host", // scripting enabled) and `print` in scope. const dir = "/work/handoff"; // 1 · Node.js on the host JS engine (nodert) writes a file… nano.fs.writeFile( `${dir}/producer.js`, `const fs = require("fs"); fs.writeFileSync("${dir}/report.json", JSON.stringify({ from: "node " + process.version + " " + process.arch })); console.log("wrote report.json");`, ); const a = await nano.node([`${dir}/producer.js`]); print("[node · host engine]", a.stdout.trim()); // 2 · …BusyBox on the RISC-V VM reads the same file… const b = await nano.run(`cat ${dir}/report.json`); print("[busybox · riscv VM ]", b.stdout.trim()); const m = await nano.run("uname -m"); print("[busybox · riscv VM ] uname -m:", m.stdout.trim()); // 3 · …and a sandboxed Boa script reads it too (read-only fs, nothing else). const from = await nano.script(`JSON.parse(nano.fs.readText("${dir}/report.json")).from`, { expose: { fs: "readonly" }, }); print("[boa · sandbox ]", from);
Expected output
[node · host engine] wrote report.json
[busybox · riscv VM ] {"from":"node v25.4.0 x64"}
[busybox · riscv VM ] uname -m: riscv64
[boa · sandbox ] node v25.4.0 x64How it runs
nano.node()runsproducer.json the host-engine Node tier (it reportsx64, see the limitations).nano.run("cat …")runs the BusyBox applet on the RISC-V VM against the same VFS.nano.script(…, { expose: { fs: "readonly" } })reads it once more from the Boa sandbox.
Source
From demos/cross-tier/.
handoff.js
javascript
// Cross-tier handoff over one shared filesystem. This is an SDK snippet: an // async function body with `nano` (a booted Nano, engines.node = "host", // scripting enabled) and `print` in scope. const dir = "/work/handoff"; // 1 · Node.js on the host JS engine (nodert) writes a file… nano.fs.writeFile( `${dir}/producer.js`, `const fs = require("fs"); fs.writeFileSync("${dir}/report.json", JSON.stringify({ from: "node " + process.version + " " + process.arch })); console.log("wrote report.json");`, ); const a = await nano.node([`${dir}/producer.js`]); print("[node · host engine]", a.stdout.trim()); // 2 · …BusyBox on the RISC-V VM reads the same file… const b = await nano.run(`cat ${dir}/report.json`); print("[busybox · riscv VM ]", b.stdout.trim()); const m = await nano.run("uname -m"); print("[busybox · riscv VM ] uname -m:", m.stdout.trim()); // 3 · …and a sandboxed Boa script reads it too (read-only fs, nothing else). const from = await nano.script(`JSON.parse(nano.fs.readText("${dir}/report.json")).from`, { expose: { fs: "readonly" }, }); print("[boa · sandbox ]", from);