Skip to content
Uncontained Install the SDK

If it runs on Linux, it runs in the browser.

Uncontained puts a real Linux machine in your users’ tab, for coding agents, IDEs and tutorials. Zero cloud: it runs on their device, in Chrome, Firefox and Safari. Node, Bun and Wasm skip emulation.

Try it in your browser
npm i @uncontained/sdk
  • Native JS Node and Bun, on the browser’s own JS engine
  • Native Wasm Wasm, on the browser’s own Wasm engine
  • Emulated Any other arm64 program, on Linux 6.18
import { Sandbox } from '@uncontained/sdk';const sb = await Sandbox.boot(); 
  1. await sb.spawn('node', ['--version']) v26.13.0 Native JS
  2. await sb.spawn('bun', ['--version']) 1.4.4 Native JS
  3. await sb.spawn('claude', ['--version']) 2.1.322 (Claude Code) Native JS
  4. await sb.spawn('python3', ['--version']) Python 3.13.5 Emulated
  5. await sb.spawn('uname', ['-srm']) Linux 6.18.57-neutrium aarch64 Emulated

sandbox runningTypeScriptUTF-82 vCPUs

The SDK: a Linux machine in ten lines

One npm package. Boot a machine, write files, spawn programs and open the ports they serve, from your own front end.

npm i @uncontained/sdk
Programs
Every spawn goes through the exec router: node and bun run native JS, everything else emulated.
Files
The disk lives in the browser (OPFS) and is there on the next visit.
Browsers
Chrome 153, Firefox 157 and Safari 27 or newer.
import { Sandbox } from '@uncontained/sdk'; const sb = await Sandbox.boot({  memoryMB: 3072, cores: 'auto',  relay: myRelay,                      // no relay: no outside network  persist: 'opfs',                     // 'opfs' | 'memory'}); await sb.fs.writeFile('/app/server.js', code);const p = await sb.spawn('node', ['server.js'], { cwd: '/app' });p.output.pipeTo(terminal.writable);sb.on('port', ({ port, url }) => (iframe.src = url));

@uncontained/sdkTypeScriptUTF-8LF

The playground: a real machine in this tab

Start the machine and type. Every exec() picks an engine, and the pick is written to a log you can read. How the router decides

Machine

Engine switches

Off: every exec() runs emulated. Every program still runs.

bash, dev@neutrium

Recorded on a real machine, Chrome 156, 10 November 2026.

$ node --version
v26.13.0
$ neutrium-exec why node
program path=/usr/local/bin/node engine=js module= argv-policy=node
decision engine=js reason=table
policy value=wasm,js,cloud,bun
program key=bcfe70988c110e9e70b3f8668f59e82df5185eb00cba98623815858a63364790
Exec Router

neutrium-exec why node

Native JS

engine=js reason=table

tail -f /run/neutrium/exec/decisions.log (replay)

  1. pid=125 engine=js reason=table /usr/local/bin/node
  2. pid=126 engine=bun reason=bun-cli /usr/local/bin/bun
  3. pid=316 engine=emulated reason=optin /usr/bin/zstd
  4. pid=325 engine=bun reason=bun-graph ~/.claude/downloads/claude-2.1.322-linux-arm64
  5. pid=566 engine=bun reason=bun-graph ~/.local/bin/claude

Four engines, one exec()

Emulated by default, native where it can.

Emulated

Runs any arm64 program. A complete arm64 computer: our NWE engine, Linux 6.18 and unmodified Debian 13. Every native engine sits on top of it.

dev@neutrium:~$ uname -srmLinux 6.18.57-neutrium aarch64dev@neutrium:~$ python3 --versionPython 3.13.5dev@neutrium:~$ fastfetchOS        Neutrium 0.1 "Photon" (Debian 13 base) aarch64CPU       Neutrium vCPU × 2 (Arm Cortex-A55, emulated)Kernel    Linux 6.18.57-neutriumMemory    56.92 MiB / 3.47 GiB (2%)dev@neutrium:~$ 

Native JS

Runs Node and Bun on the browser’s JIT. Node’s own lib/, unmodified, on the browser’s JIT. A Claude Code turn takes 2.8 s instead of 6.7 s emulated.

Claude Code, one turn, Chrome
2.8 s native JS 6.7 s emulated
Claude Code, one turn, Firefox
4.7 s native JS 8.6 s emulated

One agent turn, same machine, same result.

Native Wasm

Swaps in a byte-identical Wasm build. Go’s compiler and tsc run as WebAssembly, only when the file’s sha256 matches. tsc type-checks in 3.1 s instead of 6.6 s emulated.

3.1 s tsc --noEmit, Chrome
6.6 s emulated

Fallback

Falls back with the same pid. A native engine never fails a program for something it lacks. It falls back to emulated with the same pid and files, and logs why.

Exec router Native JSNative WasmEmulated

Snapshot restore

476 ms

A saved machine is back in 476 ms in Chrome. It runs on the visitor’s own computer, so there is no sandbox server to keep running.

Idle restore, Chrome.

The exec router explains every pick

At every exec() it checks, cheapest first, and picks an engine. Pick a program to see each check and the answer the machine gave.

Programs

  1. Policy on
  2. Argv bun
  3. Known program Bun graph, 3,150 modules
  4. sha256 graph checked
  5. Engine Native JS reason=bun-graph

Claude Code 2.1.322 is a 342 MB single-file Bun executable. The router found its 3,150 JavaScript modules and ran it on native JS. Nobody listed it anywhere.

dev@neutrium, neutrium-exec why claude

dev@neutrium:~$ neutrium-exec why claudeprogram bun path=/home/dev/.local/share/claude/versions/2.1.322 size=341501368 modules=3150decision engine=bun reason=bun-graphpolicy value=wasm,js,cloud,bun jit=onprogram key=ef49d8645119275c8de761002db2075a177ee04752afefd4d2bd00b25d7af8f3 dev@neutrium:~$ claude --version2.1.322 (Claude Code)

Node and Bun, on the browser’s own JIT

The real runtimes, not look-alikes: Node’s own lib/ and the official Bun binary’s programs run on Native JS, with the machine’s files, pids and sockets.

Their own test suites, unmodified, in

Node.js 26.13.0

Native JS, API surface 7,470 of 7,590 members (98.4%)

5,035 of 5,402 test files pass in Chrome, 93.2%

166 fell back to emulated, 176 failed, 25 timed out.

  • npm 11.20.0; Corepack brings pnpm and yarn
  • N-API addons load as on Linux
  • A Node you install yourself still runs, emulated
dev@neutrium:~$ node --versionv26.13.0

Bun 1.4.4

Native JS, API surface 9,161 of 9,324 members (98.2%)

427 of 1,092 test files pass in Chrome, 39.1%

Of Bun’s own test files on Native JS; 190 not run.

  • bun, bunx, bun run and package scripts
  • Single-file executables: Claude Code and opencode
  • The official release binary, unmodified
dev@neutrium:~$ bun --version1.4.4

QUIC test files: 268 of 268 pass Node itself passes 5,358 of 5,395 files on native arm64 Linux.

WebAssembly: WASI 0.1, 0.2, 0.3, WASIX and wasmer

A .wasm file runs like any program, and wasmer run takes Native Wasm: modules, webc files and registry packages run on the browser’s Wasm engine. Each standard is checked against the reference runtime.

  • WASI 0.1

    wasi_snapshot_preview1

    117 of 117

    calls give the same result as wasmer 7.5.0

  • WASI 0.2

    components

    14 of 14

    wasi-testsuite C tests pass against wasmtime

  • WASI 0.3

    async components

    24 of 24

    wasi-testsuite tests pass against wasmtime

  • WASIX

    wasix_32v1, threads, sockets

    1,208 of 1,209

    battery tests equal to real wasmer, Chrome

wasmer run, on Native Wasm

# a Wasmer registry packagedev@neutrium:~$ wasmer run syrusakbary/cowsay hello# a webc, with socketsdev@neutrium:~$ wasmer run --net app.webc# a core module, run like any programdev@neutrium:~$ ./hello.wasm# a WASI 0.2 or 0.3 componentdev@neutrium:~$ ./app.wasmdev@neutrium:~$ 
106 of 106 registry and package runs print the same as real wasmer, in Chrome and Firefox

NWE: an ARM64-to-WebAssembly JIT, a whole computer in the tab

NWE, the Neutrium Wasm Engine, runs unmodified ARM64 machine code with two tiers: an interpreter for cold code and a JIT that compiles hot regions to WebAssembly. The browser’s own JIT then turns that into machine code. Real Linux runs on top: its own memory, scheduler and drivers.

  • Interpreter + JIT tiers
  • Written in Rust
  • Decoder generated from Arm’s spec
  • Floating point bit-exact with Arm
  • Several vCPUs, one compile
  • Inside the browser’s Wasm sandbox
  1. 01

    Cold code is interpreted

    Most code runs once. NWE counts what comes back.

  2. 02

    Hot code is JIT-compiled

    A hot region of ARM64 becomes one WebAssembly function, registers in locals, NEON in v128.

  3. 03

    Memory through a software TLB

    A hit costs one compare and one load.

  4. 04

    Code kept by content

    Named by a 128-bit hash, shared by every vCPU, warm on the next visit.

native time on a prime kernel, Chrome
1.3×
npm install in Chrome, from 64 s on our first engine
8 s
to bring a saved machine back
476 ms

Whatever runs on arm64 Linux runs here, unmodified.

The binary you curl. The package you apt install. The coding agent you npm i -g.

  • curl -fsSL https://claude.ai/install.sh | bash Native JSthe installer downloads a Bun executable
  • apt install -y ffmpeg EmulatedDebian’s own arm64 package
  • npm i -g opencode-ai Native JSnpm on the browser’s JIT

Toolchain in the image

Each tool with its version and the engine it runs on. Filter by engine.

ToolVersion
DebianNo systemd: systemctl and journalctl are our init.Emulated13.7 trixie, glibc 2.41
Node.jsA Node you replace yourself runs emulated.Native JSEmulated26.13.0
npmCorepack provides pnpm and yarn.Native JS11.20.0
Bunbun, bunx and Bun single-file executables run native JS.Native JSEmulated1.4.4
TypeScript (tsc)The compiler is a Wasm build of typescript-go.Native JSNative Wasm7.0.2
Gocompile, asm, link and vet run native Wasm.EmulatedNative Wasm1.27.3
wasmerThe common wasmer run form runs native Wasm.EmulatedNative Wasm7.5.0
Python, pip, venvEmulated3.13.5
uvEmulated0.13.4
gcc, g++Emulated14.2.0
clang, lld, cmakeEmulated19.1.7 / 19.1.7 / 3.31.6
Rust, cargoDebian packages, not rustup.Emulated1.85.1
gitEmulated2.47.3
ripgrepNative Wasm for the copy inside Claude Code.EmulatedNative Wasm14.1.1
zstd, xzzstd compression on the host.EmulatedNative WasmHost acceleration1.5.7 / 5.8.1
sha256sum, openssl dgstHashing on the host.Host accelerationEmulatedDebian
Docker client, ComposeClient only.Emulated26.1.5 / 2.26.1
Claude CodeA Bun executable, recognised by its modules.Native JSvendor installer
opencodenpm i -g opencode-ai.Native JS1.19.4
Anything from apt, pip, cargo, npm or a URLEmulatedas published

An alternative to WebContainers, BrowserPod, Nodebox, WebVM and E2B

Not an emulator, and not a JavaScript-only runtime: both. Node and Bun skip the emulator, and a real Linux machine runs everything else. Rival facts are from their own documentation, read on 10 November 2026.

Native JS for Node and Bun

Node and Bun skip the emulator. Their JavaScript runs on the browser’s own JIT, the way a JavaScript-only runtime does.

Everything else: a real Linux machine

apt, Python, Go and gcc run unmodified on arm64 Linux 6.18. The exec router picks the engine for each program.

One Claude Code turn

Native JS 2.8 s

Emulated 6.7 s

Capability Uncontained Native engines + Linux WebContainers JS runtime BrowserPod Wasm kernel + JS Nodebox JS runtime WebVM x86 emulator E2B Cloud VM
Node and Bun on the browser’s JIT, no CPU emulation Yes Node only Node only Node only No, emulated x86 on their servers
Runs in the user’s tab Yes Yes Yes Yes Yes No
Real Linux kernel Yes No No No No Yes
Runs unmodified arm64 binaries Yes No No No No n/s
Native Node addons (N-API) Yes No Wasm replacements only No 32-bit x86 only Yes
Bun Yes not documented not documented not documented not documented Yes
Single-file Bun executables on a native engine Yes No No No No n/s
Automatic fallback to a full machine Yes no machine no machine no machine no native engine n/s
Raw TCP, UDP and TLS sockets Yes No HTTP and WebSocket only No through Tailscale Yes

Node and Bun on the browser’s JIT, no CPU emulation

Uncontained
Yes
WebContainers
Node only
BrowserPod
Node only
Nodebox
Node only
WebVM
no, emulated x86
E2B
on their servers

Runs in the user’s tab

Uncontained
Yes
WebContainers
Yes
BrowserPod
Yes
Nodebox
Yes
WebVM
Yes
E2B
No

Real Linux kernel

Uncontained
Yes
WebContainers
No
BrowserPod
No
Nodebox
No
WebVM
No
E2B
Yes

Runs unmodified arm64 binaries

Uncontained
Yes
WebContainers
No
BrowserPod
No
Nodebox
No
WebVM
No
E2B
n/s

Native Node addons (N-API)

Uncontained
Yes
WebContainers
No
BrowserPod
Wasm replacements only
Nodebox
No
WebVM
32-bit x86 only
E2B
Yes

Bun

Uncontained
Yes
WebContainers
not documented
BrowserPod
not documented
Nodebox
not documented
WebVM
not documented
E2B
Yes

Single-file Bun executables on a native engine

Uncontained
Yes
WebContainers
No
BrowserPod
No
Nodebox
No
WebVM
No
E2B
n/s

Automatic fallback to a full machine

Uncontained
Yes
WebContainers
no machine
BrowserPod
no machine
Nodebox
no machine
WebVM
no native engine
E2B
n/s

Raw TCP, UDP and TLS sockets

Uncontained
Yes
WebContainers
No
BrowserPod
HTTP and WebSocket only
Nodebox
No
WebVM
through Tailscale
E2B
Yes

Yes or no where the owner’s documentation, staff replies or public issues say so. “Not documented”: the vendor’s pages do not mention it. “n/s”: no primary source we read answers it. E2B runs in the cloud, not in the tab.

SDK questions before you embed it

Anything not answered here, the playground above can answer on a running machine.

Does my program need a special build?

No. The arm64 Linux build that already exists is the build that runs. Debian 13.7, glibc 2.41, apt.

What happens when a native engine cannot run something?

The program falls back to emulated in the same process, and the reason is written to /run/neutrium/hybrid.log.

Can I turn the native engines off?

Yes. Each engine has a switch, and NEUTRIUM_HYBRID=off runs everything emulated. Every program still runs.

Which browsers does it run in?

Current stable Chrome, Firefox and Safari.

Does Python run on a native engine?

No. Python 3.13.5 runs emulated, with Debian’s native wheels.