This roadmap describes where NURL is today and where it is going. It is forward-looking and deliberately concise — the full, reverse-chronological record of what shipped when lives in CHANGELOG.md. Anything marked done here has a regression test in compiler/tests/ and is covered by the bootstrap fixed point.
_Last reviewed: 2026-09-13 · Current release: 0.65.0 · Language: **Grammar v2.7** (spec/grammar.ebnf)._
NURL is a small systems language with a regular prefix-arity grammar, a self-hosted compiler written in NURL, and an LLVM backend. The compiler bootstraps to a byte-identical fixed point on its own source (stage1 ≡ stage2). The only build dependency is clang / LLVM 15+.
What is solid today:
|) and product types (structs),
generics over structs and functions (incl. generics over option/result types), pattern matching with match guards, or-patterns, and N-ary payloads, trait bounds on type parameters ([A: Ord]), **compile-time constant folding** (const_eval_int), a full numeric type set (i = i64 and u = byte/u8, plus sized i8/i16/i32, u16/u32/u64, f = f64 and f32), tail-call optimization, and variadic FFI (the printf family callable directly). Since 0.40.0 the language also spells the shapes a fast numeric kernel is written in: v128, a first-class by-value SIMD vector type over ~27 nurl_v128_* primitives (§4.1b) that lowers to SSE2 / NEON / wasm simd128 with no CPUID probe and no fallback path, and **wide arithmetic** — nurl_umulhi (the high half of a 64×64 multiply) plus nurl_addc / nurl_subb / nurl_mac for carry chains the backend recognises. 0.46.0 adds the two that need a runtime decision: v256 (sixteen 16-bit lanes) and the simd declaration prefix (grammar v2.6, §3.3b) — nurlc emits one clone of the function per instruction-set tier and dispatches on CPUID once per process, so a kernel written once runs AVX2 where it exists and baseline where it does not, with no #ifdef and no separate build. 0.49.0 adds the second declaration prefix, inline (grammar v2.7, §3.3c): LLVM's alwaysinline, for the case where the cost model is structurally wrong — a helper whose arguments are constants at every call site, scored on its whole body, called from a caller large enough to push the decision the other way. The grammar decision for prefix-arity (no grouping delimiter) is formally locked, and since 0.37.0 the n-ary &/| arity trap it makes possible is a **hard error by default** (--no-strict-arity demotes it to a warning) — the shape compiled to working, wrong code before.
scope exit — no GC, no hidden boxing. A **static borrow checker, on by default** (--no-borrowck to disable, --strict-borrowck to tighten), catches use-after-move, alias double-free, escaping closure captures, interprocedural/return escape, loop-carried double-frees, and iterator invalidation as hard errors without changing generated code. Since 0.44.0 no rule depends on definition order: every check that consults a per-function summary parks what it cannot answer and resolves it after the module, so where a helper is written can no longer change a verdict. Since 0.53.0 the coverage is measured from the other direction: an inverse-oracle fuzzer (tools/fuzz/genreject.py) writes one ownership violation into every context the language offers and demands the diagnostic that violation deserves, not merely a failed compile. Its first sweep found the two contexts where a definite double free still compiled clean and segfaulted at run time — a ?? arm and a closure body, the latter because the checker was switched off wholesale inside one — and both are now analysed. Since 0.55.0 a closure body's two exits agree: one that falls off its end reclaims what it bound, where only one that returned through ^ did, and --no-borrowck is a flag the corpus runs rather than one nothing had ever exercised. 0.57.0 closed the other direction across that same boundary: the checker knew what a closure body frees, but nothing tied a handle the enclosing frame freed to a later call of a closure holding it, so every spelling of that use-after-free compiled clean. **Invoking a closure is now a read of everything it captured.**
async/await colouring** — ordinary code runs unchanged under the scheduler — plus threads/mutex/cond, typed channels, and Go-style ?? channel select. Since 0.43.0, Send / Sync marker traits (stdlib/core/marker.nu) are derived over a type's whole graph and checked wherever a value crosses a thread boundary — thread_spawn, spawn, chan_send, and an Arc's payload — so an Rc or a Cell reaching a worker is a compile error however it is spelled, and % NotSend / % Send mark the cases a structural derivation cannot see either way. It is a sound lint, not a proof: docs/MEMORY.md §6.5 states what it does and does not guarantee. Since 0.58.0 the Linux I/O path has no reactor thread: an idle worker becomes the poller and blocks in epoll_wait itself, so a ready fiber resumes on that worker with no queue hop, no cross-thread wake and no migration (the Go netpoller / tokio driver shape). Sockets register once per fd lifetime, edge-triggered, and readiness that arrives while the fiber computes is banked so the next wait skips the park entirely. The surplus a saturated poller cannot keep spills into a fair global FIFO taken in batches, which is what keeps the tail flat under load; non-Linux POSIX keeps the portable poll(2) reactor. The contract — a wait may only follow an EAGAIN — is in docs/ASYNC.md.
spanning collections, hashing, serialization, a full HTTP/1.1+2 + WebSocket stack, database clients, distributed systems (p2p overlay, CRDTs), MCP, and the Anthropic Claude API.
bootstrap fixed point + the Windows golden corpus on every push and PR, plus a Linux-side mingw-w64 cross-link gate, since the Windows runner's two toolchains are both UCRT and the cross one is not), macOS ARM64 (CI-tested on Apple Silicon: bootstrap fixed point + the full corpus against the same goldens as Linux, on every push and PR; needs Homebrew LLVM, no prebuilt toolchain) and macOS x86_64 (cross-compiled Mach-O, no CI), wasm32-wasi, static Linux ARM64 / RISC-V64 (musl), and bootable unikernel images — a NURL program as its own kernel on x86_64, AArch64 and RISC-V64, no host OS and no libc. Tier definitions: docs/PLATFORMS.md.
nurlc (compiler), nurlfmt (canonical formatter), nurl-lsp
(language server), nurlpkg (package manager + test/bench runner), nurldoc (API-doc generator), tools/repl, DWARF debug info (--g), a VS Code extension, and nurlapi — a compiler-as-a-service container that powers the public playground and MCP endpoint.
The path to 1.0 is hardening, documentation precision, and external validation rather than new language surface — see Toward 1.0 below.
A high-level map of what exists. Dates and per-feature detail are in CHANGELOG.md.
compiler/nurlc.nu) with a deterministic, byte-identical
bootstrap; stage-0 links the committed nurlc_lastgood.ll snapshot (no Python in the toolchain).
spec/). v2.x added:
visibility (pub) enforcement across functions, types, consts, and enum variants; trait bounds; match guards + or-patterns; const folding; channel select; dynamic trait objects (%Trait + ( dyn Trait v ), v2.3); break / continue as reserved identifiers (v2.4); the v128 SIMD lane type (v2.5); the simd CPU-dispatch prefix on @ declarations (v2.6); the inline always-inline prefix (v2.7); and locked the prefix-arity grouping decision.
conversions. Sized integer/float types with **signedness carried in the type representation itself** (u/u16/u32/u64 distinct from the signed types end to end — no flag side-channels); explicit # casts with correct sext/zext/trunc/fpext/fptrunc. Since 0.58.0 every value boundary — return and every argument path, including generic instantiations, trait-method dispatch, closure/fn-pointer invocation and %Trait dynamic dispatch — ends in a **total-agreement backstop**: after the sanctioned coercions the value's lowered type must equal the declared one, so a pair nobody enumerated is a diagnostic rather than a call clang assembles and the callee reads as garbage (docs/spec.md §4.1).
emission: declarations may follow their impls, associated types and defaults are order-independent, and explicit/default methods share argument-type and inout/sink signature registration.
monomorphs, including behind */? prefixes), generic nesting (Channel[A], Vec[Thread]), and generics over ?T / !T E.
Drop for boxed enum/struct payloads,
% Drop user destructors, move/borrow analysis (incl. interprocedural and loop-carried escape detection). Model and known gaps: docs/MEMORY.md.
identifiers, call-arity mismatches, unbalanced braces / stray top-level tokens, and visibility violations are hard errors with source locations — nothing malformed reaches the backend silently. Since 0.39.0 that claim is measured corpus-wide: a mutation probe (one realistic mistake injected into each of the ~790 test programs, ~5 400 mutants) produces zero compiler hangs, zero crashes, and zero broken programs reaching the LLVM verifier or linker; every return path is type-checked (implicit fall-off and closure tails included), and errors inside generic/trait re-parses point at the template's real file:line with the instantiation named.
CI**: check_diag_coverage.sh reports which of the compiler's 311 die/warn sites a test has ever made it print (84%, with the never-fired set baselined so a new silent diagnostic fails the build); check_diag_anchor.sh gates that every baselined diagnostic points at the mistake rather than at the token after it; diag_mutate.py injects one realistic error into a working program and reads the answer. Between them they have found messages that were false, messages that were unreachable, and programs the compiler accepted and miscompiled.
construct reached by a path that skips a check the compiler already performs in another spelling? Round after round it says yes, and the ledger of what was closed and what remains open is docs/dev/V1_HARDENING.md — silent reinterprets, invented error payloads, calls that jump into a constant, IR only llvm-as rejects. Two oracles keep it honest: a token-deletion mutation sweep (tools/fuzz/mutate_delete.py --clang) that asks clang whether a surviving mutant's module is even valid, and tools/tree_sweep.sh, which requires byte-identical diagnostics over every tracked first-party .nu file so a new rejection rejects nothing that was valid.
main can reach the .ll
(--no-dce to emit everything). Reachability is computed over the finished IR, so closures, monomorphs, drop glue and dyn vtable thunks need no special casing — worth 30–40% of the clang step on a stdlib-heavy program. What survives is then emitted as several independent modules (--split=N) that the driver lowers concurrently and links with ThinLTO, taking the clang step on the compiler's own 3.2 MB of IR from 11.3 s to 2.0 s — at a measured 3.4% of the built program's own speed, which is why nurl.sh splits your program and build.sh does not split the compiler it installs (NURL_SPLIT=0 opts out). Since 0.40.0 that link is also cached — per-module ThinLTO backend codegen, the pre-link object keyed by content hash of the emitted IR, and the driver's toolchain probes, all under ~/.cache/nurl — so an empty program links in 99 ms instead of 305 and a warm rebuild costs less than the equivalent C compile (NURL_CACHE=0 opts out; NURL_LTO=full is still the maximal-inlining release build). Both passes: docs/BUILDING.md.
nurlc --g) with ptype/print over structs.
Organised as core/ (language essentials), std/ (general-purpose), and ext/ (external-format / network / service bindings). All pure NURL except a small C runtime (stdlib/runtime.c) for the bootstrap surface and a few platform-specific shims.
string, vec, option, result, errors, char, slice,
pair, box, cell, mem, io (write_bytes, read_all_stdin_bytes), symtab, posix.
hashmap, set, deque, heap,
ordmap, btree, lru, bitset, iter, sort, cmp, bytes, bufio, fmt, int, float, bigint (arbitrary-precision integers), decimal (exact fixed-point).
async, thread, channel, arc, rc,
arena, signal, panic/recover, process, unixsock (local IPC), log (text + JSON), time (incl. local time via the platform's zone, timezone/DST, HTTP/RFC 2822 dates), args (CLI parser), term (POSIX termios, ANSI), sysinfo (uname fields, host name, processor count).
mlkem (ML-KEM-512/768/1024, FIPS 203),
mldsa (ML-DSA-44/65/87 & HashML-DSA, FIPS 204), slhdsa (SLH-DSA, FIPS 205, SHAKE & SHA-2 families), hash_sha3 (SHA-3 & SHAKE128/256, FIPS 202). Classical & symmetric: x25519, ed25519, ecdsa_p256 (P-256 + P-384 constant-time), rsa (PKCS#1 v1.5 + PSS), aes_gcm, chacha20poly1305, hash (SHA-1/224/256/384/512, SHA-512/224, SHA-512/256, MD5, HMAC), hash_blake3, hash_xxh64 (XXH64), hkdf, pbkdf2, scrypt, encode (hex, base64, base32), random (OS CSPRNG rand_bytes), rng (xoshiro256**).
x509 (DER parser + chain/host validation, ML-DSA & SLH-DSA OIDs), x509_gen (self-signed P-256 & ML-DSA certificates, PKCS#8), csr (PKCS#10 RFC 2986 parser, generator, self-signature verifier, PEM round-trip, CA issuance from CSR), pkey (PEM private-key loading: SEC1/PKCS#8 P-256, RSA, and ML-DSA). A complete private CA built on them — classical or post-quantum, with enrollment, CSR signing, revocation and CRLs — is the pki-server registry package.zstd (pure-NURL RFC 8878 Zstandard decompressor & compressor up to level 19 optimal parser, no libzstd), deflate (RFC 1951 + table-driven CRC-32).fs (incl. streaming, stat/lstat/fstat + statvfs,
glob matching, readlink, file_sync, dir_sync, file_truncate, set_permissions, set_times), path (typed), net (TCP/TLS), udp, dns, dos.
json, toml, csv, msgpack, cbor, xml, yaml,
protobuf (checked Protocol Buffers wire readers/writers, docs/stdlib/protobuf.md), serde, regex (a Pike VM, with capture groups and back references).
auth, JWT bearer-auth with HS256/EdDSA/ES256, cookies, forms, multipart, router, middleware, access log + Prometheus metrics, DoS caps, graceful shutdown, per-request timeouts, panic recovery), HTTP client (with cookie jar), Post-Quantum TLS 1.3 (client & server: X25519MLKEM768 hybrid & pure ML-KEM key exchange, ML-DSA certificate support, SNI + ALPN + mTLS + live cert reload), HTTP/2 (RFC 9113 + HPACK, server and client — served by every HttpServer / HttpApp listener, ALPN h2 over TLS and prior knowledge on cleartext, h2spec-gated in CI), HTTP/3 over a pure-NURL QUIC (RFC 9000/9001/9002 + 9114 + QPACK, served beside every HttpApp TLS listener with Alt-Svc, h3spec-gated in CI), WebSocket (RFC 6455, **server and client, with permessage-deflate** compression — RFC 7692), reverse proxy with binary-safe streaming. Since 0.46.0 the serve path's scaling mode is fiber-per-connection (http_app_async n): TLS record I/O parks on the reactor instead of blocking a worker pthread, and the TLS handshake runs on the connection's own fiber, so handshakes overlap rather than serialise on the accept loop. The stack has had a dedicated security-hardening pass (path-traversal, SSRF, request-smuggling, HTTP/2 CONTINUATION-flood + stream-accounting, and clean cross-thread listener shutdown) with regression tests, and its serve path is peer-benchmarked against Rust hyper and Node (bench/HTTP_RESULTS.md: since 0.58.0 ahead of hyper on req/s, p50, p95 and p99 at every measured concurrency, an HTTP request served in 2 syscalls).
sqlite (production-hardened), mqtt 5.0 client,
smtp (mail submission). Postgres and Redis clients live in the registry packages psql and redis (pure NURL — no libpq, no hiredis).
mcp (+ server — the one server framework, on
which every MCP server in the tree is built since 0.60.0, with its wire frozen by compiler/tests/mcp_server_contract.nu; client, http, session, stdio, search, since 0.40.0 tasks — the io.modelcontextprotocol/tasks extension, so a long-running tools/call returns a pollable task handle instead of holding a JSON-RPC response open — and since 0.61.0 auth, the OAuth resource-server half of the MCP Authorization spec: RFC 9728 protected resource metadata and the 401 challenge that points at it) and anthropic (Claude Messages API incl. streaming SSE + tool-use deltas).
semver, manifest, lockfile, resolver,
registry_index, pkg_fetch, pkg_publish (the nurlpkg backend).
compress (pure zlib/zstd/gzip), zip (archives), tar, uuid (v4/v7),
credentials, env.
NAT traversal, DERP relay, SWIM membership, state-based CRDTs (PN-Counter, LWW-Register, OR-Set), gossip replicator, consistent-hash ring, distributed computation (Crown).
ARM64 (CI-tested on Apple Silicon; needs Homebrew LLVM, no prebuilt toolchain), macOS x86_64 (cross-compiled, not CI-tested).
wasm32-wasi (WASI SDK), including the compiler itself running
in the browser playground, and **whole neural networks running client-side in the browser** — the pure-NURL ONNX runtime compiled to wasm, executing on the CPU (precompiled kernels) or on the visitor's GPU via WebGPU (the CUDA-C kernels translated to WGSL compute shaders; the gpu package's third backend). Live YOLOE segmentation and tiny-YOLOv2 detection run in a tab with no server inference (packages/yoloe-demo, the playground objdet demo).
packages/nwasm) that
decodes and executes real wasm32-wasi modules (full int/float instruction set, linear/bulk memory, tables + call_indirect, threads + atomics, sockets, WASI + --dir file ops), with no external runtime — and with a template JIT on top that emits x86-64 for hot functions over guard-page linear memory. Over bench/wasmbench.sh's corpus it runs the same modules at a geometric mean 0.78× the reference Cranelift JIT's wall clock, 12 of 15 rows at or below parity — and the control columns say this is not a NURL-shaped fast path: the same corpus emitted by clang and rustc runs at 0.73× and 0.73×, the foreign frontends slightly ahead of the one that wrote the runtime. The compiler self-hosts on wasm: nurlc compiled to wasm32-wasi recompiles nurlc.nu to byte-identical IR, both under the external reference wasmtime and under this pure-NURL runtime — and identically under its interpreter and its JIT.
C906) validated on-device.
libc, no interpreter — on three architectures: x86_64 (QEMU microvm, and the same PVH image boots under Firecracker and cloud-hypervisor), AArch64 and RISC-V64 (QEMU virt; on AArch64 a flat Image wrapper covers Firecracker/cloud-hypervisor). Since 0.40.0 the x86_64 image also carries a Multiboot2 header beside its PVH note and packages into a hybrid BIOS+UEFI disk, so it **boots on real PC hardware off a USB stick** — with screen output (EGA text or a UEFI framebuffer) where a microvm had a serial port, and a PIT-calibrated TSC where no firmware states the frequency. Per-arch QEMU gates run the hosted corpus against the same goldens (19–20 each, including the SIMD corpus), with virtio net/rng/blk drivers, TLS handshakes in the guest, native fiber switches on all three ISAs, and CI booting every architecture on every commit. Since 0.48.0 a guest can also keep state: --disk links in a virtio-blk driver and a read/write FAT12/16/32 filesystem, so the ordinary std/fs.nu calls reach a volume any host can read — checked by fsck.vfat and by an independent reader, across reboots. The same release closed the endpoint milestone (a guest that boots straight into a swarm compute appliance, answering expression and wasm tasks) and ran the compiler itself inside the machine: nurlc.wasm compiles in the guest to output byte-identical to native, and takes the bootstrap fixed point there. The playground builds and boots these images (POST /build_unikernel + target dropdown), and agents do the same over MCP (nurl_build_unikernel).
packages/nurlbox
is a busybox-shaped multi-call executable: 100 of the everyday UNIX utilities, sh among them, in pure NURL over the shipped stdlib with nothing to link beyond libc. It builds for Linux, macOS, Windows and wasm32-wasi, and boots as its own kernel on the unikernel target. 348 differential cases hold it to the original: the same command line through nurlbox and through the system busybox, agreeing on stdout, on the bytes, and on the exit status.
nurlfmt canonical formatter (idempotent, IR-preserving), nurl-lsp
(completion, references, unused-symbol lint), nurlpkg package manager, DWARF debugging, VS Code extension, and the nurlapi compiler-as-a-service container (playground + cross-compile endpoints + public MCP server).
targets in examples/, Milk-V Duo programs in duo/, and a Push-To-Talk distributed voice app (pttvoice/).
nurllama + gguf):
pull a GGUF model from HuggingFace (resumable, content-addressed store), then run, chat, or serve an ollama-compatible API that existing clients speak unchanged. A hostile-input GGUF parser, a tokenizer read from the model's own metadata, and a llama forward pass whose matvec kernels decode quantised blocks inside the matmul — Q4_0…Q8_0 and the K-quants (Q4_K/Q5_K/Q6_K) — so weights never expand to f32 on the device, and the same kernel sources run on the CPU backend byte-identically. Verified against independent references at every layer: token IDs vs a SentencePiece implementation, logits and greedy text vs a numpy forward pass, dequantisation bit-identical to an independent decoder. Architectures span llama / qwen2 / gemma3 / phi3 and, since 0.21.0, diffusion language models: LLaDA2.x, a Mixture-of-Experts llada2 model that converts from its Hugging Face checkpoint (nurllama convert, streaming a model larger than RAM to GGUF at constant memory) and generates by block denoising — parallel commits with token editing, not left-to-right — its logits matched to a numpy forward and its decoded ids to a reference-faithful loop.
whisper + audio + safetensor +
tokenizer): a WAV goes in and text comes out — *word for word what Hugging Face transformers produces from the same model*, on whisper-tiny and on distil-large-v3, on the GPU or the CPU. Every stage is verified against an independent implementation rather than against our own understanding of it: the resampler against scipy, the log-mel against HF's own feature extractor (r = 1.00000000, on both 80 and 128 bands), the 400-point FFT against numpy (Bluestein, because 400 is not a power of two and padding it computes a different transform), the weights bit-exact, the vocabulary against HF's tokenizer, the encoder against HF's encoder, and the transcription against HF's. Whisper is not the llama shape — LayerNorm rather than RMSNorm, error-function GELU rather than tanh, two conv1d layers, cross-attention, and the ecosystem's first non-causal attention.
f5tts + audio + safetensor +
torchpt + gpukit): a reference recording and its transcript go in and the same voice comes out saying something it never said — F5-TTS, the flow-matching model, from the checkpoints Hugging Face ships, with no Python and no ONNX export. A 22-block diffusion transformer with adaLN-zero modulation, conditional flow matching with classifier-free guidance and sway sampling, and the vocos vocoder. Verified against the reference with fixed inputs at every stage: the text front-end id for id, the text encoder at 2.6e-6, the whole forward at 2.3e-6, 32 guided ODE steps at 7.4e-6, the waveform at 2.9e-4. What the model is not is the whole program — the duration is guessed linearly, the reference is loudness-normalised and scaled back, and long text is chunked and cross-faded, none of which is learned and all of which changes what comes out. The service answers wav, mp3 or raw PCM; the MP3 encoder is audio's own (MPEG-1/2/2.5 Layer III, all nine sample rates, no ffmpeg and no codec library), because a program that can only hand back WAV cannot answer a request for an mp3.
reg.nurl-lang.org,
nurlpkg install): GPU compute (gpu — CUDA driver + NVRTC, a CPU fallback backend, a static-kernel backend, and a WebGPU / WGSL backend; gpukit, tensor), pure-NURL vision and ML (image PNG/JPEG codecs, onnx runtime, objdet, yoloe, iforest, anomaly, and mlp — the first trainable package, a deterministic sklearn-faithful MLP regressor), local LLMs (nurllama, gguf, tokenizer, safetensor), speech recognition and synthesis (whisper, f5tts, audio — WAV, resampling, mel spectrograms and MP3 encoding), agent coordination (agora — channels, mail, a task board and notes over one SQLite file, as MCP and REST), distributed compute (swarm, swarm-mcp), web (template HTML templating, http, http-client — one client facade over HTTP/1.1, HTTP/2 and HTTP/3 — gRPC, a native client and server over that HTTP/2, and oauth, an OpenID Connect relying party and resource-server guard in pure NURL), PKI (pki-server — a private CA with a classical or post-quantum signing key), database clients (psql, redis — pure NURL), and application scaffolding (cli, cas, wasmbuilder, nurl-mcp). Installed tools carry runtime data via the manifest's [install] assets mechanism (staged into <prefix>/share/<name>/).
packages/registry): a
self-hostable server speaking the exact nurlpkg wire protocol — bearer-authenticated publish with server-side checksums, name ownership and version immutability, yank/revoke, search, and a server-rendered catalog that renders each package's README straight from its published tarball. SQLite as the single source of truth; built on the http, template and md2html packages and proven end-to-end against the real client. (The public reg.nurl-lang.org cutover from the Cloudflare Worker is pending deployment.)
published tarball with a project Ed25519 key; nurlpkg pins the public key and verifies the detached minisign signature — using a pure-NURL BLAKE2b + minisign implementation (std/hash_blake2b, std/minisign) — before unpacking, mandatory and fail-closed. Release archives are signed too; the installers always verify the checksum fail-closed and verify the minisign signature against a pinned key when minisign is available. Since 0.41.0 the packer also excludes compiler output by extension, so a given revision packs to the same bytes from any clean checkout — a checksum identifies the source, not the machine that happened to build it.
The remaining work to declare a stable 1.0 is mostly precision and proof, not new language features.
checker rejects vs. tolerates, with no implied Rust-equivalence (docs/MEMORY.md, docs/LIMITATIONS.md).
interprocedural escape analysis and *T raw-pointer flows are on the roadmap or out of scope by design; the checker is currently incomplete there by design. (Resolved: interprocedural escape and return-escape implemented.)
arm-local fall-through bindings, allocations inside a recover scope). (Resolved: leaks fixed.)
These convert a hypothesis into measured results.
characters) for NURL vs Python/Rust/JS across 8 matched programs (bench/TOKEN_EFFICIENCY.md). *Result: the raw token-count claim did not survive measurement — on today's tokenisers NURL is ~1.7× Python's tokens (median), losing to out-of-distribution glyph fragmentation. The claim was retired; the defensible arguments are grammar regularity and first-pass compile success.*
correctness, NURL vs Python/Rust, across four models (Sonnet 4.6 / Opus 4.8 / Haiku 4.5 / mercury-2 diffusion), primed with NURL's one-page reference since the training corpus contains zero NURL (bench/genacc/, results in bench/genacc/RESULTS.md). *Result: from a single page a model reaches the Python/Rust ballpark on several tasks but not parity first-try; failures are out-of-distribution habits (imports, then grouping-parens, then mutability) that targeted primer cues fix in turn. The follow-up measured the agentic half of the claim: with ONE round of compiler-diagnostic feedback (bench/genacc/repair.py — the model sees only its program and the compiler's stderr, never the expected output), Sonnet and Opus reach **exact Python/Rust parity — 100% compile, 100% correct** — Haiku reaches 100% compile, and the diffusion model quadruples its score. The diagnostic-first compiler is the load-bearing artifact, and its value is now measured, not asserted.*
project copy — "an agent can drive the toolchain over MCP" is a tooling win, not evidence the language is better for LLMs.
maintainer and publish a short governance note (license stays MIT OR Apache-2.0).
Not blocking 1.0; ordered roughly by likely value.
no_std-styleembedded profile. The RISC-V / ARM64 static cross-compiles already prove the shape; these extend it.
stdlib/runtime.c is
split into stdlib/runtime_core.c (bootstrap core) and stdlib/runtime_ffi.c (stdlib FFI shims), stitched by a thin aggregator so the single runtime.o build is unchanged. The core compiles standalone and defines the symbol set the no_std profile links.
Ideas under consideration, no committed timeline.
suggestions, leaning on the regular grammar and local error semantics.
the simple IR, but are not on the near-term path.
Deliberate exclusions, to set expectations:
model; rc/arc are opt-in library types.
async/await function colouring. Concurrency is via stackful fibers;ordinary code is scheduler-agnostic.
whole point.
(#).
recover — only
explicit panic is recoverable; faults remain process aborts.
compiler/tests/ and survives
the bootstrap fixed point; details in CHANGELOG.md.
docs/spec.md (normative) and
spec/grammar.ebnf (authoritative grammar).