Wanix
- title
- Wanix
- type
- toolbox
- summary
- Plan 9-style per-process namespaces in the browser β run Wasm and x86 programs sandboxed, no server
- tags
- golang, webassembly, sandboxing, plan9, browser, watchlist
- language
- Golang (kernel), JavaScript (elements)
- license
- MIT
- created
- 2026-07-29
- updated
- 2026-07-29
Wanix builds a Unix-shaped environment inside a web page. It borrows the two ideas that made Plan 9 interesting β everything is a file, and every process gets its own namespace β and implements them over browser APIs, so a page can run Wasm binaries and, through an x86 emulator, actual Linux, with no server involved. The 0.4 release wraps all of this in custom HTML elements, which is how the demo on wanix.dev gets a working shell out of three tags:
<wanix-term>
<wanix-bind dst="rc.wasm" type="file"
src="https://wanix.dev/extras/0.4.0-rc2/rc.wasm">
</wanix-bind>
<wanix-task cmd="rc.wasm" term start></wanix-task>
</wanix-term>
rc there is the Plan 9 shell, compiled to Wasm and fetched into the namespace at rc.wasm, then executed as a task with a terminal attached.
The namespace model
Everything a program can touch is a path, and the kernel exposes its own facilities under #-prefixed device paths: #task for process control, #term for terminals, #vm for virtual machines, #ramfs for in-memory filesystems (cloned per bind), #pipe, #signal, and #web for browser integration β including #web/opfs for the Origin Private File System, which is where persistence comes from. A task inherits its parent's namespace by default and can be given a different one, which is the whole sandboxing story: a program sees exactly the files someone bound in for it, and nothing else. That is a stronger and simpler boundary than the capability wiring wasmer and other server-side runtimes do through WASI preopens, because the composition happens in the same primitive the program uses to read files.
<wanix-bind> is the primitive that builds those namespaces, and it does more than link names. type="file" fetches a URL or inlines content, type="archive" unpacks a .tar/.tgz into a directory tree β and layering several archives or directory binds onto the same dst produces a recursive union, the Plan 9 union-mount behaviour rather than an overlay filesystem. type="import" pulls in a remote namespace, spoken as 9P over a WebSocket or embedded as an iframe. A page can export its namespace with an id and an allow-origins list, so two pages on different origins can share a filesystem across a protocol from 1992.
Running things
Tasks are dispatched to pluggable drivers selected by a type attribute: js for plain JavaScript, gojs for Wasm built with GOOS=js GOARCH=wasm, wasi for wasip1 modules, and auto to detect. Keeping gojs and wasi as separate drivers is the right call β the two targets have genuinely different host contracts, and picking the wrong one is exactly the failure documented in adding-go-to-a-browser-code-runner, where GOOS=js hung forever inside a bare V8 isolate because nothing drove the microtask queue.
<wanix-vm> is the escape hatch for code that was never going to be Wasm. It runs v86, an x86 emulator in JavaScript, inside the namespace: bind in the emulator assets and a Linux system image, and it detects the kernel and boots to a shell. Attributes cover RAM size (mem), console terminal allocation (term, which needs raw mode for VM consoles), and export, which republishes the guest's internal namespace at #vm/1/guest if the image cooperates. So the same page can host a Wasm shell and an emulated Linux and treat both as files.
The heaviest element is <wanix-workbench>, an embedded VS Code workbench backed by the Wanix namespace, usable as an editor, a file explorer, a full IDE, or an app shell. It requires an extra assets bundle and a task marked role="shell" before its terminal works.
Adding it to a page is one script tag:
<script type="module"
src="https://cdn.jsdelivr.net/npm/wanix@0.4.0-rc2/dist/wanix.min.js"></script>
Caveats
The version on the landing page is 0.4.0-rc2 β a release candidate, not a stable release, and the docs say custom workbench extensions and live-editing them in place are future work. The project comes out of tractordev and has been going since October 2023, at 797 stars and 38 forks as of late July 2026, with the last push on 2026-07-19. That is steady rather than fast, and it is effectively one shop's project.
Worth noting about the source: wanix.dev's per-element examples are rendered by the page's own JavaScript, so a clipped copy of the site arrives with the code blocks empty. The device names and task-driver list here come from the repository README instead.
Tagged watchlist β pre-1.0 and single-vendor, see watchlist. The reason to keep an eye on it is that per-process namespaces are a better fit for sandboxing untrusted browser-side code than the ad-hoc capability plumbing most Wasm hosts use, and this is the only implementation of that idea aimed at the web.
MIT, ~797β as of 2026-07-29. There is a 19-minute talk on the design at youtube.com/watch?v=kGBeT8lwbo0.