A lightweight, language-agnostic operating-system personality that boots inside a Web Worker and runs applications — written in JavaScript or WebAssembly — as real processes.
An OS-style runtime where the executable format is JavaScript or WASM instead of native binaries, and the "CPU" is the host's own JS/WASM engine.
The kernel is written in Rust (compiled to WASM), is Node-agnostic, and
is the sole authority for the VFS, the process table, module resolution, and
capability granting. Node compatibility is a swappable guest-side tenant layer,
never part of the kernel. See ARCHITECTURE.md,
PLAN.md, and DECISIONS.md.
M3 — Usable shell reached. On top of the MVP (spawn/run/kill/concurrent JS)
there is now wsh, which has grown from a one-line planner into a real
bash-subset script interpreter (packages/workeros-web/src/shell/): pipes,
redirects (incl. 2>&1), &&/||/;, background jobs, globbing, # comments,
$VAR/${…}/$(…)/$(( … )) expansion, if/for/while/until/case,
functions with local, and builtins that have no external (test/[, read,
export, set -e, trap, printf, cd, …). It runs alongside the coreutils
(echo cat ls cp mv rm mkdir pwd env true false) that execute as real,
ps-visible, killable processes. So a script like
OS=$(uname -s); for f in *.txt; do echo "$f"; done runs as written — though
curl … | bash installers still fail on what they do (native binaries, no
fork/exec), not on the shell grammar. The grammar stays in Rust (the kernel's
shell_parse returns the AST; ADR-012); the JS evaluator only walks it and drives
the async spawn/wait plumbing that wasm can't. The kernel owns VFS, process table,
and glob.
There is now also a real npm + node inside the OS (a Phase-5 slice):
npm install fetches packages from the npm registry (semver + transitive deps),
gunzips/untars their tarballs into node_modules, and node index.js runs
CommonJS that require()s them — all as ordinary programs invoked through the
shell (os.exec("npm install …"), os.exec("node app.js")). npm/node are guest
programs; the kernel stays Node-agnostic (INV-1).
WASI is running (Phase 4). An unmodified wasm32-wasip1 binary runs as a
WorkerOS process — the program worker instantiates the .wasm against a WASI
Preview 1 host bound to the kernel's syscalls and calls _start. It does stdio,
args/env, clocks, random, proc_exit, and real blocking I/O: a
SharedArrayBuffer synchronous-syscall channel lets a wasm program open/read VFS
files (std::fs), seek, read_dir, rename, and block on stdin from a pipe. A
curl program speaks HTTP(S) over the worker's fetch — downloads, headers,
methods, -d/-F bodies, Basic auth, -i/-I, -w, -f, --max-time — so you
can fetch and run a wasm, or hit a JSON API:
curl -o /hello.wasm https://example.com/hello.wasm # needs CORS on the host
/hello.wasm
curl -sS -H 'Accept: application/json' https://api.example.com/thing
curl -X POST -d '{"a":1}' -H 'Content-Type: application/json' https://api.example.com/xThe transport is browser fetch, so its rules apply: cross-origin URLs must send
CORS headers, and forbidden request headers (Host/Cookie/User-Agent/…) are dropped.
| Milestone | Phases | State |
|---|---|---|
| M1 — Boot | 0–1 | ✅ kernel boots, VFS + WASI-shaped syscall spine, fully native-tested |
| M2 — Run JS (MVP) | 2 | ✅ spawn/run/kill JS, concurrent, import resolved by the kernel |
| M3 — Usable shell | 3 | ✅ wsh (pipes, redirects, &&/||, glob, &), IPC pipes, coreutils, ps |
| M5 — Ecosystem | 5 | 🚧 npm (registry install, deps) + node CJS require; preview/lockfiles TBD |
| M4 / M6+ | 4,6,7 | ⏳ WASI binaries, preview, persistence |
crates/workeros-kernel/ Rust core: VFS, process table, syscall dispatch, resolver, wsh parser/glob (native-testable)
packages/workeros-web/ wasm-bindgen bindings + host runtime (kernel/program workers, shell driver, client API)
packages/workeros-coreutils/ system binaries: POSIX coreutils as guest programs over the `sys` ABI
packages/workeros-programs/ OS programs (npm, …) as installable /bin programs + the Node-compatible guest runtime (process shim + CommonJS require)
website/ marketing site + live playground, built with the OTF Web framework
examples/ runnable demos (run-js, shell)
Run a package inside the OS (all through the normal shell):
npm init -y
npm install is-even # registry fetch → gunzip/untar → node_modules (+ deps)
echo 'console.log(require("is-even")(42))' > app.js
node app.js # CommonJS require resolves node_modules → true
npm run startRequires a Rust toolchain with the wasm32-unknown-unknown target, wasm-pack,
and Node.js.
# Native kernel tests (pure logic — no browser needed)
cargo test --workspace --exclude workeros-web-wasm
# Node-ism grep gate (keeps the kernel Node-agnostic — INV-1)
./ci/grep-gate.sh
# Build the kernel wasm + host runtime, then serve with COOP/COEP
cd packages/workeros-web
npm install
npm run build:wasm # or build:wasm:dev
npm run serve # http://localhost:8080
# Headless browser tests (boot handshake + MVP acceptance)
npm testOpen a demo at
http://localhost:8080/examples/run-js/index.html (run a JS program) or
http://localhost:8080/examples/shell/index.html (the wsh terminal).
Cross-origin isolation (COOP: same-origin, COEP: require-corp) is required
for SharedArrayBuffer; the dev server sets these headers (ADR-010).
Apache-2.0. See NOTICE for attribution details.