Grasm v1.0.0 Get started

More

Status

Every number here comes from the repository as the site is written, or out of the document that recorded the measurement. Five figures here used to be typed by hand instead. Four of them were wrong by the time anybody looked — the worst by a factor of two — and the fifth, “0 open defects”, was a claim no gate on this page makes. The scorecard has all 11 goals and where each one stands.

What holds

511programs, engines identical
415identical in wasm
511cross-compiled, agreeing
258conformance programs
101findings recorded
15fuzz generators

Interpreter, bundle and native builds agree byte for byte on stdout, exit code and diagnostics. All 511 are also compiled for x86_64 and run under Rosetta, every one of them agreeing, on 15 October 2026. Every generated program is checked for what it keeps as well as for what it prints.

Which run wrote which figure

The corpus is 520 standalone programs, counted as this page is written and by difftest's own filter — so a program added today is in that number today. Everything below it needs a run, and these are not all from one run. site/facts.json used to carry no date at all, which is how a September figure sat on this page under a sentence claiming every number came from the run that proved it; it carries one per figure now, and this is the whole record:

GateWhat it comparedFigureTaken
difftestinterpreter, bundle and native identical51115 October 2026
wasmtestidentical in the browser engine41515 October 2026
wasmtestskipped: no filesystem, socket, process or thread9615 October 2026
crosstestcross-compiled to x86_64, identical under Rosetta51115 October 2026
ProjectGoldwhole programs agreeing on every engine4415 October 2026
fuzz_lawslaws that held against arithmetic20515 October 2026
depthnested calls the interpreter reaches, against 10,000 promised31,44415 October 2026

Every figure in this table was taken today, which has not been true before and is the only reason the paragraphs that used to sit here are gone. crosstest had two records and neither was the sentence anybody wants: a clean run over the corpus as it stood in September, against an October one that attempted 224 of the corpus on a machine at load 38 rising to 134, which docs/binary-size.md asked to have retaken on a quiet machine. It has been — at load 12.4, the whole corpus, nothing declined, in twenty-four minutes. The October row stays in that document as the record of what a machine under that load could measure at all, which was always its point.

difftest used to be the other one, and is not any more: its row is a run of today over all 511 programs, which is every program the corpus holds, and it agrees exactly with the count this page takes from the tree. Three earlier attempts at it were stopped at a two-hour limit, which read as the gate being too big for the window — and was not. The run that finished took nineteen minutes on a machine at load 13. The same work had not finished in two hours at load 100, so what those attempts measured was the load, not the gate.

The depth figure is a capacity, not a limit, and it is only comparable with itself. A frame holds the locals of whatever function is recursing, so the number moves with the shape of the program measuring it: the gate's own function reaches 31444, where the one in ProjectGold/08-fibonacci reached about 42,000 on the same build. That is why the gate pins one shape and asks not to have it tidied. What the specification promises is 10,000, and what the gate fails on is the margin falling under twice that — the smallest margin in which a frame doubling is caught here rather than by the guarantee breaking. It is in the table because the margin moved once already with nothing noticing: see F99.

What does not work

LimitDetail
660 libraries, all first-partySee Packages; the plan for the rest is in docs/packages-plan.md. Anything else you need, you write, or bind to C with extern fn.
Blade is local onlyA path dependency and a local Blade registry both work. Nothing fetches from or publishes to a remote one yet.
Downloads are not code-signedmacOS binaries for both architectures are published on the releases page with SHA-256 sums, but they carry no Apple Developer signature, so Gatekeeper will ask before the first run. Notarisation is release work, not language work.
Not faster than RustThe geomean is 0.965× of it, 0.955× with the harness floor taken out of both sides, against a 0.95× target — so the goal is met and the claim is not available. tree at 0.51× is the worst row. On the systems suite Grasm loses etl by 3.6×, and wins memory everywhere — 8× on chat. Every row →
One integer width, one float widthi8…u64, usize and int are aliases for i64; f32 is an alias for f64 (spec/types.md [T-INT-ALIAS]). No unsigned and no wrapping arithmetic. bytes is writable in place at one byte each, so a byte buffer is no longer eightfold — but a buffer of samples is still [f64] at eight bytes apiece.
No shared mutable state across threadspar_map and par_filter demand an empty effect row and will not reach a ref from outside; a task cannot be spawned per list element. No mutable globals, statics or thread-locals, and a handler holds no state between calls — which is what makes a recording replay.
No SIMD, no file handles, no string builderNo intrinsics or autovectoriser. Whole-file and ranged reads only — no seek, no mmap, no streaming encoder. str is immutable, so appending in a loop is quadratic; collect and join.
A window, but no widgetspackages/sdl binds SDL2 — window, renderer, streaming texture, event poll — and scripts/sdltest.sh drives the whole path at 0.4 ms a frame at 256×256 RGBA, gated with no display. What is missing above that is the toolkit: no buttons, sliders, text fields or layout, and no glyph rasteriser, so text means binding SDL2_ttf. Nothing addresses the GPU, and the wasm build ships the interpreter without DOM reach.
A union error cannot be narrowed(A|B) is raised, propagated and printed, never destructured. Declare one sum type and match it.
Polymorphic recursionRefused by name at build time. It is what monomorphization is; no work removes it.
Small standard library84 methods. Enough for 44 whole programs and 12 applications; you will find gaps in something larger.
Linux never linked or run hereThe 2,100 lines of the operating-system layer written for Linux went through a compiler on this machine for the first time on 15 October 2026: cargo check --release --target x86_64-unknown-linux-gnu --workspace passes for every crate. Nothing has been linked or run, and a type-check does not catch a wrong constant — which is how AF_INET6 was 30 on Linux for four commits. CI compiles it properly.
Tasks refuse every effect1,000,000 tasks run, and none of them may do I/O. G6's uncolored half is the open one.
One gate is red, on purposeThe specification is 71 pages against the 50 §19.2 binds it to, and crates/grasm_spec/tests/core.rs fails past 70 because that is where recording the gap stops being enough. It crossed on 12 October when [E-SCHEDULE] was rewritten. The ceiling is not being raised and the metric is not being re-scoped, because spec/core.md rules both out: a number that is met by redefining what counts is not a number. docs/known-issues.md has what closing it costs.
No query engineEdit-to-diagnostic is p95 40 ms by re-checking the whole program, which is fast enough at this repository's size and will not be at a million lines.
No users but this projectNobody has hit it from an angle nobody here thought of.
Region sweep not implementedTier 1's rule is enforced; the bulk deallocation it makes sound is not built.

Deliberate, and still surprising

Four things an outside port tripped over in its first week. None is a defect and each one refuses with a diagnostic that explains itself — they are here because a reader arriving from Rust, npm or Go will write all four by reflex, and finding out one at a time costs an afternoon.

You writeWhat happensWhy
pub type Shape = …refused Types are one namespace across the whole program, so every type is already reachable from every module. There is nothing for pub to change.
let own = 1refused own is a parameter mode and one of the 37 Core constructs, so it is reserved. It is a common variable name, and that is a real cost of spending the word here.
name = "my-pkg"refused A consumer writes import my_pkg with the name bare, so the name has to be a Grasm identifier. Registries whose import syntax quotes the name — npm, PyPI — can afford hyphens; this one cannot.
let x = fallible()refused A failure cannot be dropped on the floor. Use try to propagate, match to handle both arms, or annotate the binding : T ! E to hold the failure as a value.

What is not claimed

Grasm is not faster than Rust, Go or Zig, and no benchmark here says it is. It is not battle-tested. Defects are still being found at roughly one per working session — falling, but not zero, and a language with zero known defects and no users has told you more about its test suite than about itself.

The no_std conversion that took a hello-world from 351.1 KB to 85.7 KB found nine defects on its way, and no gate on this page would have caught any of them: they were in the operating-system layer, below everything the corpus exercises. Two would have shipped silently — a variadic open passing a garbage mode, and an RwLock releasing the wrong lock. The list is on the scorecard.

How that is kept honest

All 101 findings are written down in ProjectGold/FINDINGS.md, including the ones that were the test harness's fault, the ones withdrawn as wrong, and the ones caught before they shipped. Every gate is verified by breaking the thing it guards and confirming it fails — and one of them had to be, because replaytest was matching 0 of 39 journalled builtins and exiting 0 for weeks, its pattern expecting a struct written on one line. It now asserts its own count, which is the check that would have caught it on day one.