wasm-vm documentation
Guest, artifacts, and state

Boot a guest without pretending the bytes are free.

The browser loader treats the kernel, initramfs, disk image, and snapshot as explicit artifacts. It fetches them, verifies the manifest hashes, then constructs the wasm Linux wrapper. Large disk paths are separate from the small public default.

manifest integrity checks WasmLinux wrapper large disk modes are local-only
ManifestURLs, sizes, SHA-256
Fetchstreamed bytes + progress
Verifyreject a mismatch
BootrunChunk drives Linux

The public default

The checked-in artifacts.json contains a kernel, an initramfs, and a compressed boot snapshot. The loader's default mode is initramfs, so the public path does not download the 512 MiB Alpine disk image. A matching boot snapshot can shorten a repeat boot; an incompatible or missing snapshot falls back to a cold boot.

Manifest entryCurrent checked-in sizeRole
kernel22,097,408 bytesLinux Image; always fetched for a boot.
initramfs1,151,596 bytesDefault root filesystem passed to the Linux wrapper.
bootSnapshot10,983,666 bytesOptional compressed resume state; identity checks decide whether it can be used.

The exact URLs and SHA-256 values are the manifest contract; this page intentionally does not duplicate them. If the manifest and bytes disagree, loader.js raises an integrity error before boot.

Three ways to provide storage

PathConstructionWhat is actually downloaded
initramfsnew WasmLinux(ram, kernel, initrd, bootargs, output, enableMic)Kernel and initramfs; enableMic opts into the guest input stream without requesting permission.
diskWasmLinux.newDisk(..., enableMic)Kernel and the complete rootfs image before construction.
chunkedWasmLinux.newChunkedDisk(..., enableMic)Kernel first; disk chunks are fetched only when guest reads park on them.
chunked + persistnewChunkedDiskPersistent(..., enableMic)Chunked base plus an IndexedDB copy-on-write overlay.

Availability matters. The disk and chunked Alpine manifests are local-only artifacts in this checkout. The public Pages deploy carries the small default manifest and staged boot artifacts, not every large development image.

Lazy chunks and integrity

In chunked mode, a missing block read parks the virtio request. The host asks pendingChunks() which indices are needed, fetchPending() retrieves them, and the wasm chunk store verifies each chunk before inserting it into the cache. There is no full-image download hidden behind the chunked label.

const controller = await startLinuxBoot({
  mode: "chunked",
  imageManifestUrl: "./releases/chunked-alpine/manifest.json",
  cacheBudgetMib: 256,
  bootProfileUrl: "./releases/chunked-alpine/boot-profile.json",
  onProgress: (role, loaded, total) => showProgress(role, loaded, total),
});

A boot profile is an ordered first-touch list used for readahead. It is an optimization hint, not a replacement for per-chunk verification. Cache metrics are available through the Linux wrapper's fetchStats() surface.

Durable overlay and snapshots

persist: true is meaningful only on the chunked path. Guest writes are kept as 4 KiB copy-on-write blocks and flushed to an image-namespaced IndexedDB store. The loader uses a Web Lock for a single writer; another tab can be forced read-only. A durable flush resolves only after the IndexedDB transaction completes.

const controller = await startLinuxBoot({
  mode: "chunked",
  persist: true,
  onWriterStatus: ({ readOnly }) => {
    console.log(readOnly ? "read-only guest" : "writer guest");
  },
});

Resume state has a separate coherence check. The build identity, base image binding, and overlay generation must agree before a stored snapshot is applied. A stale, foreign, or corrupt blob is reported as a typed cold-boot reason rather than silently restoring the wrong disk.

Network selection is explicit

The loader configures the guest's virtio network before construction. The default can be loopback; slirpNet selects the browser-local stack, while relay or Tailscale settings select their own provider. DNS-over-HTTPS, DHCP lease, MTU, relay credentials, and provider lifecycle commands are separate options and are not smuggled through an artifact URL.

Local development

make web-build
bash tools/serve-dev.sh
# open the printed local URL and choose the disk/chunked path

Use make web-dist for the deployable static tree. The small default path is the one to use when testing the public demo; local-only manifests are useful for storage and Alpine acceptance work but should not be described as public assets.

Source contracts