Skip to main content
The kernel is a userspace OS that routes commands to pluggable runtime drivers. Mount WasmVM for shell/coreutils, Node for JavaScript, and Python for Python — all sharing a single VFS.
1

Install

pnpm add @secure-exec/kernel @secure-exec/runtime-wasmvm @secure-exec/runtime-node
2

Create a kernel

import { createKernel } from "@secure-exec/kernel";
import { createInMemoryFileSystem } from "@secure-exec/os-browser";

const vfs = createInMemoryFileSystem();
const kernel = createKernel({ filesystem: vfs });
import { createInMemoryFileSystem } from "@secure-exec/os-browser";

const vfs = createInMemoryFileSystem();
const kernel = createKernel({ filesystem: vfs });
3

Mount runtime drivers

Mount WasmVM first (provides shell + 90 coreutils), then Node (overrides the node stub).
import { createWasmVmRuntime } from "@secure-exec/runtime-wasmvm";
import { createNodeRuntime } from "@secure-exec/runtime-node";

await kernel.mount(createWasmVmRuntime({
  wasmBinaryPath: "./wasmvm/target/wasm32-wasip1/release/multicall.wasm",
}));
await kernel.mount(createNodeRuntime());
Mount order matters. The last-mounted driver wins when two drivers register the same command. Mount WasmVM first so its node stub gets overridden by the real Node driver.
4

Run shell commands

kernel.exec() runs a command through the WasmVM shell and returns stdout, stderr, and the exit code.
const result = await kernel.exec("echo hello world");
console.log(result.stdout);   // "hello world\n"
console.log(result.exitCode); // 0
Pipes, redirects, and shell operators work:
const result = await kernel.exec("echo hello | tr a-z A-Z");
console.log(result.stdout); // "HELLO\n"
5

Run Node code through the kernel

Since the Node driver is mounted, node commands route to a real V8 isolate:
const result = await kernel.exec('node -e "console.log(2 + 2)"');
console.log(result.stdout); // "4\n"
Node’s child_process routes back through the kernel. This means Node code can call shell commands via WasmVM:
const result = await kernel.exec(`node -e "
  const { execSync } = require('child_process');
  const files = execSync('ls /tmp', { encoding: 'utf-8' });
  console.log(files.trim());
"`);
6

Spawn processes with streaming I/O

kernel.spawn() gives you a ManagedProcess handle with real-time stdin/stdout/stderr:
const chunks: string[] = [];

const proc = kernel.spawn("node", ["-e", `
  process.stdout.write("line 1\\n");
  process.stdout.write("line 2\\n");
`], {
  onStdout: (data) => chunks.push(new TextDecoder().decode(data)),
});

const exitCode = await proc.wait();
console.log(chunks); // ["line 1\n", "line 2\n"]
console.log(exitCode); // 0
Write to stdin:
const proc = kernel.spawn("cat", [], {
  onStdout: (data) => process.stdout.write(data),
});

proc.writeStdin(new TextEncoder().encode("hello from stdin\n"));
proc.closeStdin();

await proc.wait(); // stdout: "hello from stdin\n"
7

Use the shared VFS

All runtimes share the same kernel VFS. Writes from one are immediately visible to others:
// Write from kernel API
await kernel.writeFile("/tmp/data.txt", "hello from kernel");

// Read from WasmVM
const r1 = await kernel.exec("cat /tmp/data.txt");
console.log(r1.stdout); // "hello from kernel"

// Read from Node
const r2 = await kernel.exec(`node -e "
  const fs = require('fs');
  console.log(fs.readFileSync('/tmp/data.txt', 'utf8'));
"`);
console.log(r2.stdout); // "hello from kernel\n"
8

Clean up

await kernel.dispose();
dispose() sends SIGTERM to all running processes, waits 1 second, then cleans up drivers in reverse mount order.

Full example

import { createKernel } from "@secure-exec/kernel";
import { createInMemoryFileSystem } from "@secure-exec/os-browser";
import { createWasmVmRuntime } from "@secure-exec/runtime-wasmvm";
import { createNodeRuntime } from "@secure-exec/runtime-node";

const vfs = createInMemoryFileSystem();
const kernel = createKernel({ filesystem: vfs });

await kernel.mount(createWasmVmRuntime({
  wasmBinaryPath: "./wasmvm/target/wasm32-wasip1/release/multicall.wasm",
}));
await kernel.mount(createNodeRuntime());

// Shell commands
const echo = await kernel.exec("echo hello | tr a-z A-Z");
console.log(echo.stdout); // "HELLO\n"

// Node code that calls shell commands
const node = await kernel.exec(`node -e "
  const { execSync } = require('child_process');
  console.log(execSync('echo hi from shell', { encoding: 'utf-8' }).trim());
"`);
console.log(node.stdout); // "hi from shell\n"

// Shared VFS
await kernel.writeFile("/tmp/msg.txt", "cross-runtime");
const cat = await kernel.exec("cat /tmp/msg.txt");
console.log(cat.stdout); // "cross-runtime"

await kernel.dispose();

Next steps

Kernel API

Full type reference for all kernel exports.

Cross-Runtime

Pipes, VFS sharing, and npm scripts across runtimes.

Custom Runtimes

Write your own RuntimeDriver.