Nexium roadmap

Where the language is, where it goes, and in what order. Dates are not promises; the order is. Each phase ends when its exit criteria hold, and every item lands with tests, docs, and a decision entry when it settles a design question. This file is updated when a phase closes.

The spec's one sentence is the compass: a language complete enough to build everything in, that is also the best thing to adopt for one piece of something else. The second half is ahead of the first, on purpose.

Now: 1.0.0#

What exists and is verified on Windows, Linux, and macOS:

Numbers: 36.2k lines of Nexium (25.4k of them the compiler and its tools), 2.0k of C (the runtime and the GUI window layer), 307 std functions, 32 examples, 21 tutorial programs, 37 spec conformance cases and 49 compile-fail cases, 13 harness suites, verified on three platforms by CI and under the sanitizers.

Phase 1: a language you can write your tools in (0.3)#

Goal: someone replaces a Python or Rust command-line tool with Nexium and misses nothing for the tool's own needs.

Exit: examples/tool.nx, a real utility (a log grep with regex, dates, and file walking) under 300 lines, runs on all three platforms from the release. Status: done except ?T chaining (a?.b, waiting on the spec review) and the nx fmt trailing-comma rule. std.fs, std.time, std.regex, std.text, std.testing, std.stream, range steps, while/else, full match exhaustiveness, nx test --filter/--verbose, os.environ, and examples/tool.nx (142 lines) shipped in 0.3.0.

Phase 2: a language that talks to the world (0.4)#

Goal: services and clients without leaving the language.

Exit: examples/server.nx, an HTTP server serving JSON from a directory, and examples/client.nx fetching and parsing a URL, both under test.

Phase 3: a language other people can build on (0.5)#

Goal: sharing code beyond a sibling file.

Exit: a second person's package is used by a third person's program.

Phase 4: the compiler in Nexium (0.6 to 1.0)#

0.6 opens with the syntax settled for 1.0 (decision 87): if c { }, while c { }, for x in items { }, if let v = opt { }, braces always, no semicolons. nx fmt migrates 0.5 sources. Nothing else about the surface syntax is planned to change before 1.0.

Goal: nx built by nx. Runs in parallel with phases 1 to 3; each stage is checked against the Rust compiler on identical inputs.

The rest of the climb, one release each (decision 90):

Exit: cargo is no longer needed to build nx from a release tarball (0.8), and no Rust is left in the repository (1.0). Both reached.

Phase 5: 1.0#

A 1.0 means the language stops changing under people's feet.

Every item is done: 1.0 is the release that deletes bootstrap/rust/.

Past 1.0#

What 1.0 is not yet#

The four things a careful reader will hold against 1.0, and where this roadmap answers each:

weaknesswhere it is answered
Memory safety is not guaranteed: ownership without a borrow checker still lets a view outlive its storage (two were found in std and the compiler under AddressSanitizer while the tutorial was written)1.2, the whole theme; until it lands the docs say "memory-safe by default" nowhere
Maturity: writing one tutorial found eight compiler bugs; a stranger will find morethe hardening commitments under Always below: the corpus, the fuzz budget, the sanitizer job, a patch within a week of a fix
No performance numbers: it compiles through C, which is not the same as a tablethe numbers page, pulled forward from 1.6 into 1.1
No ecosystem: sixteen std modules, no registry, no third-party packages, one maintainer1.4 (std), the registry and the second-maintainer items under Ecosystem; async is answered under Not planned, errors with payloads under 2.0 candidates

After 1.0 the language changes only by addition, under the stability policy of phase 5. Each minor version has a theme; a bullet moves into a version when it has a decision entry and a test plan. The compass sentence still decides the order: what the compiler and the tools in self/ and std/ needed first, what other people's programs need next. Everything here was found by writing Nexium, not by reading other languages' feature lists.

Before anything: the open bugs, and 1.0.3#

KNOWN_ISSUES.md is this roadmap's page zero: every open bug lives there with a reproduction and the fix it needs, a fix removes the entry, adds a Fixed line and a regression test, and the next patch release ships it. Nothing below is started while a known bug that a user can hit sits there. (1.0.2 was the hotfix for the release binaries, which were built for the runner's CPU.) The entries an outside review of 1.0.1 added, in the order they will be fixed, all for 1.0.3:

  1. A contained panic leaks what the call acquired: the export wrapper's longjmp skips every drop between the panic and the boundary. The fix is a per-call tracker in the runtime that releases live allocations, open files, sockets and held locks on the panic path; it is also the first half of 1.2's "a panic releases what it owned".
  2. nexium.lock is written and never read, so the lockfile pins nothing: nx fetch honours it, nx update is what re-resolves.
  3. The Python wrapper takes a list for a []mut T parameter and drops the writes: mutable slices accept only writable, contiguous, matching buffers.
  4. Effect notes point at the function rather than the recorded witness, so "exact line" is not yet true.

With them, the words the same review found wrong: SECURITY.md says "memory-safe" in one sentence and lists safe-code use-after-free cases in the next; until 1.2 the claim is "deterministically memory-managed without a garbage collector, memory safety complete in 1.2", everywhere. The README says "language-stable, early ecosystem" near the top. And for discovery: "Nexium language" in every title and package (nexium-lang on PyPI and npm, since nexium is taken there by unrelated projects).

First: the quick wins, in order#

Everything below is described in a theme further down; this is the same work sorted by how soon it can ship. None of it changes the language, so each lands as a 1.0.x patch or in 1.1 the day it is done, in roughly this order. The themes after this section keep their order; this is the queue in front of them.

Hours each.

  1. nx doctor compiles and runs a one-line program before it says "everything works": the checker, the C emitter, the C compiler, the linker and the executable all have to answer, and an illegal instruction from the probe is named as such with the fix. 1.0.1's doctor reported a working installation on a machine where the compiler could not compile a line, because it had only asked the C compiler for its version. The harness runs the check. (The code for this was written and set aside on 2026-09-20; it is the next thing.)
  2. The installer refuses to run twice (a setup mutex naming the one already open), closes a running nx before replacing files, and writes a log; the uninstaller the same.
  3. The one-C-file install on the front page of the docs, and install.sh falling back to cc bootstrap/nx.c when there is nothing to download.
  4. The release workflow writes a .torrent with the assets as web seeds and puts the magnet link in the notes; a QR code beside it.
  5. A Homebrew tap, a Scoop bucket and the winget manifest, from the archives the release already builds.
  6. nx doctor says when a newer release exists.
  7. The VS Code extension on Open VSX beside the Marketplace.
  8. A packages.md: the packages people can nx add from git today.
  9. An "Open REPL here" folder entry and a Windows Terminal profile from the installer.
  10. ghcr.io/londopy/nexium: the compiler with Zig, on Alpine and Debian.

A day or two each.

  1. install.ps1, the PowerShell one-liner, and the Chocolatey package that wraps it.
  2. REPL :undo, :save and :load; :effects expr.
  3. nx -e and nx -p one-liners on the REPL's compile cache.
  4. nx layout Type: offsets, sizes, padding, the reordering.
  5. expect_snapshot in std.testing.
  6. pip install nexium and npm install nexium, wheels and packages that carry the binary.
  7. The installer detects an installed version: upgrade, repair, remove, the previous choices as defaults.
  8. nx upgrade, and nxup behind it later.
  9. Portable mode, and nx install from a portable copy.
  10. The effects lockfile (nx audit --lock) and the CI check.
  11. Panic proofs as code lenses in the language server.
  12. Colour as you type and completion in the REPL, from the server.

About a week each.

  1. nx explain f effect: the provenance tree.
  2. The numbers page: bench/ in four languages, on a fixed runner, published.
  3. nx test --watch and nx run --watch (file watching in the runtime).
  4. The ownership trace, nx run --trace own and the REPL's :own.
  5. The binary-pattern debugger, nx bin.
  6. :show and :plot in the REPL: the inspector and chart windows on nexium-gui.
  7. The installer's editor page, and the wizard in six languages.
  8. Authenticode signing and macOS notarization in the release workflow (the certificates are the slow part).

Everything longer, in the order of the themes: memory safety (1.2), incremental builds and the semantic language server (1.3), std.tui and nx topo (1.4), the wasm playground (1.5), hot reload, profiling by effect, the visual tools (1.6), the seam (1.7), nexium-gui grown up and the Hut (1.8).

1.1: the language the compiler wanted#

Ergonomics the self-hosted compiler paid for by hand.

Exit: the compile-time interpreter and check.nx lose their hand-written copies and index workarounds; nx audit self/check.nx reports fewer panics than in 1.0.

1.2: memory safety without a garbage collector#

The promise of section 12, no undefined behaviour in safe code, has four holes that 5.6 and 5.7 hand to the programmer: a view stored past the storage it points into, a view kept across a growth of its container, a view into a value that is then moved or dropped, and a value that leaves its arena. 1.2 closes them, so that ordinary safe Nexium code cannot create a dangling view and unsafe marks everything the compiler cannot prove: memory-safe by default, with explicit escape hatches, the guarantee Rust gives, kept in Nexium's simpler shape.

Not a garbage collector. A GC would simplify the language and weaken several of its defining promises at once: predictable destruction, visible allocation behaviour, !allocates, embedding in C, Python, Rust and Node processes, no substantial runtime. And not a borrow checker with lifetime annotations either: the language keeps ownership without one. What it keeps, and what it adds:

Rolling it out under the stability policy: undefined behaviour was never promised, so a program that had it may become an error in a minor (docs/stability.md). Each rule arrives as a warning in one release and an error in the next, so a codebase gets a release to run nx fix.

Exit: sections 5.6 and 5.7 list no case that is the programmer's responsibility; SECURITY.md extends its promise to views; every rule has a compile-fail case and a spec case; the fuzzer gains a hunter that compiles mutants in debug mode (freed storage filled with 0xDD) and runs them, so a dangling view that slips through is a finding rather than luck.

1.3: the toolchain grown up#

Exit: a one-line change rebuilds in well under a second on the compiler's own sources, and the language server answers from the checker.

1.4: a standard library people stop supplementing#

Exit: examples/tool.nx, service.nx and the self-hosted compiler import nothing they had to write themselves.

1.5: platforms#

Exit: a Nexium program runs in the browser, on a Raspberry Pi and on the three desktops from one source, and the docs say which combinations CI proves.

1.6: the runtime that release builds deserve#

Exit: every example in release mode is within a documented factor of its C counterpart, and the factor does not grow between releases.

1.7: the seam, both ways#

Today a Nexium library leaves the tree through nx ship: a C header and archive, a Python wheel over ctypes, a Rust crate with safe wrappers, an npm package. What crosses is what C carries: integers, floats, slices, layout(c) structs, a status code with an error name. Everything else stays home, and the traffic runs one way. This theme widens the seam in both directions, with the same rule as 1.0's spec section 15: a panic never crosses, no initialization call, no process-global state, and a symbol means the same thing from every language.

Python, deeper.

Rust, deeper.

More languages out. Each is an artifact kind with a wrapper in that language's idiom over the same C ABI, a test in CI that calls ropesim from it, and a chapter in the embedding guide:

The ABI itself.

Exit: ropesim shipped to C++, Go, Java, C#, Ruby, Lua and the browser and called from each in CI; the Python wheel takes a NumPy array without a copy and raises ropesim.InvalidInput; the Rust crate's error enums come from the Nexium error sets; an example calls a Rust crate and a Python library from Nexium; --abi-check fails on a removed export.

Tools only this language can have#

The REPL was the first of these: a feature no systems language is expected to have, cheap because the compiler was already there. Each item below is the same shape, built on a fact the compiler already knows (every function's effects, every move and drop, every binary pattern's shape) and offered as a tool. Each is pencilled into the minor it fits; the cheap ones may land earlier as patches to the tools, since none changes the language.

Answers from the effect system.

Answers from ownership and layout.

Binary patterns.

Interactive, in the family of the REPL.

The clickable line: windows, wizards and the REPL#

The installer wizard, the REPL and the GUI library are the parts of the project people touch rather than read. This line grows them together: each item is something to click, type into or look at, and each stands on what exists (the REPL recompiles a session; nexium-gui draws in a window or headless; the installer is a wizard already). Pencilled into minors the same way as the tools above.

The REPL you can look into (1.1, 1.3).

Run from the editor, everywhere (1.3). Ctrl+B runs the file, the variant tests it, and a diagnostic is a click away, in every editor the repository supports, the same way:

The first five minutes (1.3, 1.5).

The installer grown up (1.3). The wizard is the first thing a Windows user sees of the language, so it should behave like software people pay for, in every situation it can find itself in:

Every road in (1.3 to 1.5). Today nx arrives by the Windows setup, the install script, the portable archives, source, and the GitHub Action. People install software the way their platform taught them, so each road below is a manifest or a package built by the release workflow from the same archives, in the order of how many people stand on it. The community usually maintains the distribution-owned ones (AUR, nixpkgs, Homebrew core); the project's job is a release that makes that easy: stable URLs, checksums, and no post-install step.

The niche roads (1.3 onward). The ones people remember:

nx topo: the tutorial you can run (1.4).

The Topo as a course (1.4 for the content, 1.5 for the page). The chapters teach by showing; a course asks the reader to do. Every exercise is a file in the repository the harness runs, so the course cannot rot:

The docs, more (1.3 to 1.5).

std.tui (1.4).

Visual tools (1.6).

nexium-gui grows up (1.8, Gangapurna).

Apps (1.8).

2.0 candidates: questions the spec review should settle#

Additions large enough to deserve a spec version of their own. Each is a decision entry first, an implementation second, and none is promised.

Ecosystem, in parallel with all of the above#

Always#

Not planned#