userland.run70Try the demo
Changelog

What changed, and when

Releases of the SDK, the nano runtime, the app catalog and this website — taken from git tags, commit history and npm. Latest update: .

  • SDK
  • nano runtime
  • App catalog
  • Website
  1. Tools: run a real program on a folder from your disk

    New /tools/ pages pick a local folder, run a catalog app on it inside the tab, and save the results back — nothing is uploaded.

    • Batch resize and convert photos with ImageMagick 7, remove EXIF and GPS data with exifstrip, merge, split, optimize and password-protect PDFs with pdfcpu, and query CSV files with SQL with sqlite3.
    • Each page mounts the SDK's <nano-tool> web component with a built-in, data-only tool definition: the folder is copied to /work, Save to folder writes new and changed files back, and browsers without a directory picker get a zip download.
    • Presets fill an editable command box; ?preset=…&cmd=… share links pre-fill it but never run on their own. A Terminal tab opens the same folder in an interactive shell.
    • A live counter lists every request that leaves the site while the page is open.
    • The site now builds against @userland-run/nano-sdk 0.3.0.

    @userland-run/nano-sdk 0.3.0

    New `./folder` subpath for local folders, and registered wasm apps become real shell commands.

    • @userland-run/nano-sdk/folder: mountFolder(nano, dirHandle, { at }) copies a picked folder into the VM and keeps a snapshot; diff() and writeBack() write new and changed files back (never deleting unless asked); mountFiles() covers <input webkitdirectory>; zipFolder() builds a zip for download.
    • The guest BusyBox shell runs registered wasm apps with real pipes, redirects and exit codes, so nano.shExec("cd /work && photon a.jpg b.png && ls") works; nano.run routes them too.
    • execWasmApp(argv, { env, stdin, timeoutMs }) with binary-safe output; the vendored WASI shim implements the rest of preview1 (positioned I/O, rename, truncate, …).

    nano runtime v0.3.0

    The shell runs wasm-tier apps, the WASI shim covers preview1, and a new exifstrip core app.

    • A guest shell's execve of a registered wasm app waits for it, bridges stdin/stdout/stderr through kernel pipes and returns its exit status.
    • wasm apps see the filesystem like a normal process: absolute and relative paths, fd_pread/fd_pwrite, path_rename, truncation and the remaining preview1 calls.
    • exifstrip: lossless removal of EXIF/GPS, XMP and IPTC metadata from JPEG, PNG, WebP and HEIC, built for wasm32-wasip1.

    @userland-run/nano-sdk 0.2.11

    Returning visitors never run a stale wasm image against a newer host.

    • The service worker fetches same-origin .wasm, .tar.gz and /vendor/ requests with cache: "no-cache", so a long-lived HTTP cache entry from an older release (served as immutable until July 2026) is revalidated instead of reused.
    • Fixes live samples failing with Bad file descriptor for browsers that had cached the July console.wasm.

    @userland-run/nano-sdk 0.2.10

    New `./agent` subpath: hand an LLM agent a capability-scoped Linux sandbox.

    • createVmTools(nano, grants) turns a Nano or worker client into model-agnostic tools (read_file, write_file, run_shell, run_node, install_app, run_script, …) gated by fs/exec/node/install/script grants and an approve hook.
    • exposeWebMcp registers the tools with the browser's built-in agent over WebMCP.
    • About 11 KB, with no VM runtime inside — see Agent tools & WebMCP.

    @userland-run/nano-sdk 0.2.9

    Host-engine Node runs real-world CommonJS packages that redeclare `process`, `Buffer` or `console`.

    • The nodert module wrapper takes only Node's five parameters, so const process = require("node:process") (commander 12) no longer throws.
    • require("node:console") returns the global console wired to stdout/stderr.

    @userland-run/nano-sdk 0.2.8

    Previews for host-engine servers, host-engine Node in Chrome, and the terminal input and accessibility fixes.

    • ServeBridge.register({ injector: nano }) now previews servers on the host Node engine as well as in the VM; new nano.listeners().
    • Host-engine node() works in Chrome (no TextDecoder on shared memory).
    • BusyBox httpd and other forking servers keep answering after the first connection.
    • Terminal: paste, Option/AltGr characters, Ctrl+Shift shortcuts, missing keys, a screen-reader mirror inside the element, dispose().

    nano v0.2.2

    Forking servers survive their children, and runners decode text safely from shared memory.

    • A forked child closing an inherited socket no longer frees it under the waiting parent, so BusyBox httpd answers every request.
    • Node and wasm runners copy before decoding text from SharedArrayBuffer-backed memory (Chrome rejects shared views).

    @userland-run/nano-sdk 0.2.7

    Accurate README and type definitions, plus typed catalog and engine wrappers on the worker client.

    • Worker client (createNanoWorker) gains typed installApp, installBundle, execWasmApp and resolveNodeEngine — the catalog installer runs in the worker, next to the VM.
    • onProgress callbacks for installApp/installBundle stay on the main thread; progress events are proxied back from the worker.
    • Type docs corrected: ramMB auto-sizing, engines (ERR_NODE_HOST_RUNTIME_UNAVAILABLE / ERR_NODE_HOST_UNSUPPORTED, auto fallback to the VM), cwd/env honored by node() only, terminal feature defaults, TerminalHandle.dispose.
    • README rewritten against the actual API.
    • Published from GitHub Actions via npm trusted publishing (OIDC) with SLSA provenance.

    @userland-run/nano-sdk 0.2.6

    Service-worker routing fixes, serialized VM runs, catalog hardening — and the first release published via npm trusted publishing (OIDC).

    • nano-sw.js: forwards query strings, same-origin only, per-client routing, binary bodies, null-body statuses, credentialless COEP.
    • run/shExec/node/fs operations are serialized; calls are rejected while a server holds the VM.
    • Catalog: retries a failed generation lookup, rejects index rollback, re-verifies cached chunks.
    • Worker/VM leak and destroy() fixes; provision() template/flush fixes; Shell node lines honor cwd/env.
    • New publish.yml workflow: tag-triggered npm publish with an OIDC token (no npm token), provenance attached automatically.

    nano v0.2.1

    The kernel + four peer runners layout (riscv, node, wasm, boa), the wasm32-wasip1 app tier, and a round of POSIX correctness and host-robustness fixes.

    • Repository restructured into a kernel plus runners: runners/riscv (RV64GC VM), runners/node (Node on the host JS engine), runners/wasm (wasm32-wasip1 apps), runners/boa (sandboxed JS).
    • First wasm apps under apps/core: ripgrep (rg) and Photon, an image CLI on the pure-Rust image crate.
    • Open-file descriptions are refcounted, so file offsets and flags are shared across dup, fork and 2>&1; CLONE_VFORK goes through the serialized fork path.
    • Path handling: normalized parent paths in memfs, chdir validated by the host, *at syscalls honor dirfd, 4096-byte paths with ENAMETOOLONG.
    • File-backed mmap, munmap/MAP_FIXED free list; bounds-checked guest memory and ELF segments.
    • eventfd / timerfd / epoll / socket / dup3 / O_CLOEXEC fixes; trace output no longer on by default; new shipped-host test suite.

    Catalog publish pipeline and CORS proxy hardening

    The publish pipeline, the self-hosted CORS proxy and the recipe supply chain now fail closed.

    • Publish fails closed on previous-index/CAS fetch errors, verifies carried-forward manifests and asserts CAS completeness; generation = max(cas, catalog) + 1.
    • CORS proxy (Cloudflare Worker): origin allowlist, https only, revalidated redirects, header allowlist, git-only POST, fail closed.
    • Recipes pinned to commit SHAs, cargo --locked, sha256-checked downloads.
    • Least-privilege CI permissions; the key generator writes the private key with mode 0600.

    Docs rebuilt around live samples

    Every docs page now carries click-to-run samples that execute in your tab, and the site has new Features, Apps, Examples, Compare and Changelog sections.

    • Docs content split into typed modules with live samples (exec, shell, fs, node, serve, terminal, catalog, wasm, script); each sample declares the output it is tested against.
    • A Playwright suite runs every sample on every page.
    • Per-page canonical URLs, Open Graph images and JSON-LD; sitemap dates come from git history.
    • SDK bumped to 0.2.6 with the matching nano v0.2.1 wasm images; caching headers fixed for the fixed-name wasm/vendor/demo files.
  2. @userland-run/nano-sdk 0.2.5

    Publishes the wasm-app tier and the Node engine selector.

    • Wasm-app runner: registerWasmApp, execWasmApp, and installApp for kind: "wasm-app" catalog artifacts.
    • NanoConfig.engines — choose whether node() runs on the RISC-V VM or the host JS engine (vm / host / auto), with per-program routing pins.
    • Catalog: per-app execution-tier metadata (SignedIndex.appMeta, Tier).

    Multi-runner catalog

    The signed index lists apps of every tier, not just RISC-V.

    • Per-app {tier, kind, abi} is denormalized into the signed index; legacy apps default to the riscv tier.
    • Non-ELF recipes are conformance-tested on their own runner (wasm-app, node-app, boa-app).
    • Photon added as the first wasm-app recipe.

    Repositioned as a multi-runner platform

    The site describes the kernel + four runners, with live wasm, Boa and cross-tier demos.

    • Live Photon (wasm), Boa sandbox and cross-tier demos on the Node-in-the-browser page.
    • The emulator is presented as the "RISC-V VM" runner; SDK bumped to 0.2.5.
  3. @userland-run/nano-sdk 0.2.0 – 0.2.3

    First npm releases of the SDK.

    • 0.2.0: first published version, with a Playwright browser suite.
    • 0.2.1: the catalog CDN client points at @userland-run/nano-catalog.
    • 0.2.2: the CAS package is @userland-run/nano-cas.
    • 0.2.3: the terminal relaunches the shell when it exits.

    nano v0.2.0

    NanoVM grows from a single emulator into the userland.run platform.

    • Slim by default: make build produces a BusyBox-only nano.wasm; Node.js and the dev toolchain install on demand from the signed app catalog (make build-full still bundles them).
    • In-VM terminal and tty: line discipline, ppoll, interactive shells, signal delivery, scrollback — powers <nano-terminal>.
    • Boa scripting layer: a separate boa.wasm engine for sandboxed, capability-scoped JavaScript.
    • Catalog-installed binaries execute from the guest VFS via execve.
    • Syscalls pwrite64, pwritev, riscv_flush_icache, io_uring_setup; host-fetch bridge.
    • Dual-licensed AGPL-3.0-only OR LicenseRef-UEL.

    Live terminal on the homepage

    The homepage hero runs a real in-browser terminal through the SDK.

    • Full <nano-terminal> embedded on the homepage.
    • Demo 05 "flow-studio": a live React Flow view of the VM pipeline.
    • Open Graph images served as image/png.
  4. Categories and collections in the signed index

    The signed index carries browse categories and curated collections.

    • Topic categories and curated workflow collections are emitted into the signed index.
    • Published packages moved to the @userland-run scope (nano-catalog, nano-cas) on 2026-06-30.

    SDK docs and Cloudflare Pages

    SDK reference docs, the Node-in-the-browser page, and deployment to Cloudflare Pages.

    • SDK documentation and the Node-in-the-browser page.
    • Deploys moved to Cloudflare Pages.
  5. nano v0.1.0

    Initial release with a bundled WASM binary.

    • First tagged release of the RISC-V emulator compiled to WebAssembly, with BusyBox and Node binaries attached.