¶
Go → Wasm → Burroughs
A WebAssembly runtime written in pure Go, designed around one guest language: Go. Correctness-neutral, performance-partisan. The B5000 favored ALGOL. Burroughs favors Go.
In v0.12.0, a fork-built Go program runs through burroughs run with GOMAXPROCS > 1, several agents executing
guest code at once on OS threads, and garbage collection across them.
How that is witnessed, and what the witness does not show.
What it is¶
- Pure Go. No cgo, and no dependency outside the Go standard library. The module is
github.com/scttfrdmn/burroughs, and Burroughs is a library first: its CLI'sburroughs rungoes through the same public API and nothing else. - Go-partisan, correctness-neutral. Burroughs' host contract (threads, preemption, the memory model at host boundaries, stacks, the WASI 0.3 event loop) is written around what the Go runtime needs from a host. Any guest that conforms to the spec should run correctly, and the upstream WebAssembly spec test suite is how that is checked. Where a design tradeoff exists, the choice that favours Go wins, in API surface and optimization priorities, never in correctness.
- An interpreter. The pipeline is decoder, internal form, validator, interpreter. There is no compiler, and none is on the roadmap.
- A research engine first. Production hardening against hostile modules is a stated non-goal of the current contract (v0.1).
The name comes from the Burroughs Large Systems (the B5000, 1961), stack machines designed so that one high-level language would run best on them. Wasm is a stack machine too.
What works today, in plain terms¶
As of v0.12.0 (the release quoted below, when this page was written):
- Core WebAssembly (the MVP and Wasm 2.0 features, plus SIMD, relaxed SIMD, and four Wasm 3.0 proposals:
extended constant expressions, tail calls, multi-memory and memory64) runs, from Go (
burroughs.Instantiate) or from the command line (burroughs run). The spec suite's core board reports no failures. - Go programs built with
GOOS=wasip1 GOARCH=wasmrun throughWASIP1Config.Runorburroughs run, with arguments, an environment, the standard streams, and read-only or writable directory grants. - A WASI preview-1 guest can start its own threads. A module that imports
"burroughs" "spawn"and exportsmstartstarts agents on OS threads over its shared memory, through those same two paths. That is the door the Phase 4 Go fork uses, so a fork-built Go program runs with real threads. CoreInstantiatesupplies no imports, so it still starts no second thread, and host-started threads are not built. - Components load, and their typed exports can be called from Go with
u32,string,listandrecordvalues. The async component ABI, cancellation throughcontext, andwasi:cli/runworlds work. - Not yet: stack switching, a full WASI 0.3 host, and two proposals that stay gated off (GC and exception handling). Linux and macOS (64-bit) are built and tested; Windows runs the tests in a separate CI workflow as a measurement, not a gate, and is unsupported.
The known limits page has the details, with issue numbers.
The current release: v0.12.0 (2026-10-28)¶
Implements contract v0.1.
What changes by default: four Wasm 3.0 proposals, one stamped flip each. Extended constant expressions, tail
calls, multi-memory and memory64 are on by default (ADRs 0107–0110, Added below). Each flip moved the core board by
exactly its own lane's pre-registered reading, with 0 new failures, identically on darwin/arm64 and janus x86-64.
Each keeps an env-var rollback: BURROUGHS_EXTENDED_CONST=0, BURROUGHS_TAIL_CALL=0, BURROUGHS_MULTI_MEMORY=0 and
BURROUGHS_MEMORY64=0. Exception handling and GC stay off, with their open work (#95; #172, #262), and
return_call_ref is GC's.
Guest-started threads, through the public paths. A WASI preview-1 module that imports "burroughs" "spawn" and
exports mstart starts agents on OS threads over its shared memory, through WASIP1Config.Run and burroughs run
(#1122).
- The contract names the door: an append to §2 T-1.
- The end-to-end witness is a committed fork-built Go program. Its output equals stock Go's, with a digest recomputed natively, and 4 agents are sampled executing at once against a floor of 3.
v0.11.0's limit "no public path starts a second thread" is lifted for the WASIP1 path. CoreInstantiatestill supplies no imports (host-started threads are not built), and a component'sthread.spawn*is still refused.
Public-path defects fixed:
burroughs run <component>is routed whatever flags are given (#1128).- A mistyped
Component.Callargument is the caller's error, notErrUnsupported(#1129). - A shared memory used as a Canonical ABI memory option is refused by name (#1141).
A hardware weak-memory reading (scripts/hwlitmus.sh, #1126). MP, SB, LB and IRIW run at 2²⁰ trials per cell on
darwin/arm64, janus x86-64 and Graviton3, over the engine and a neuter build without ADR 0054's atomics, with a native
control and wasmtime as comparisons.
- The engine shows 0 SC-forbidden outcomes everywhere.
- Only Apple arm64 discriminates: there the neuter shows SB's forbidden outcome in every run and MP's in most. On Graviton3 and x86-64 the interpreter's store-to-load latency hides the reorderings, and those zeros are not evidence.
- Contract B-MM-5 gains a non-normative note saying so (Scott's answer, option B). It changes no MUST.
Contract v0.1 appends, on Scott's answer of 2026-10-28:
- §2 T-1's guest door;
- §6's interpretation of R-2, flagged as one: a stackless lift's callback is a pull;
- B-MM-5's note.
Board (make conformance): the core board reads 63769 pass, 0 fail, 0 unsupported, 1368 gated, 0 unimplemented
over 256 files (v0.11.0: 60957 pass, 4187 gated). The 2819 vectors answered are the four flips' own lanes, 2812
passing and 7 bound. The all-gates-on lane reads 65109 pass, 0 fail, 0 gated. The threads lane reads 576 pass,
41 fail, 2 bound over 4 files, unchanged from v0.11.0, and all 41 failures are superseded-corpus rows
(threads_superseded_test.go's register), with 0 engine defects.
Known limits, open on default-on paths, each with its issue:
- A guest that calls
runtime.LockOSThreadand then needs another M crashes on the Phase 4 fork (#1157), with "fatal error: on a locked thread with no template thread". The throw is the fork runtime's own. v0.12.0's end-to-end witness does not pin its workers for this reason. Closewith a zero bound returnsnilon Windows (#945), carried. Windows is outside the claim.- A Go runtime fatal was seen once on CI's arm64 runner in
internal/spec(#1089), carried. It has not repeated. array.new*'s backing allocation is not polled, soStopcan take over 1ms on a GC array of about 64 Ki elements or more (ADR 0104's named limit). This applies only with GC on, which is not the default.- Carried from
v0.11.0, both still open: - a shared-everything-threads heap type is refused as "malformed", not by name (#1120);
- a Go guest's stop-the-world still depends on the fork's compiler-inserted loop checks (#1064, parked).
Quoted from the v0.12.0 block of the engine's CHANGELOG.md, regenerated from the latest release tag on every build. References to sections "below" are to that CHANGELOG block.
Where to go next¶
- Docs: install, the CLI, the Go API, four tutorials, concepts, limits and the roadmap. Every example program on those pages is run by this site's CI against the latest Burroughs release.
- Blog: Building Burroughs, an eleven-part story of how the engine and its unusual process were
built, from an empty repository to
v0.12.0. - GitHub: the code, the
CHANGELOG.md, the decision records, and the issue tracker, where the project's status lives.
Burroughs is licensed under Apache 2.0, © 2026 Scott Friedman.