This page covers the 5.21 releases from 5.21.0 to 5.21.3 and the plan for the next public release, 6.0.0. See what each one changes for your projects. The full list of released changes is in History.
| Version | Status | What it brings |
|---|---|---|
| 5.21.0 | Released | The topaz-5.21 language mode, std.typeset and Length literals, and embedded Lispex 1.21 |
| 5.21.1 | Released | Repairs to type inference, calls, diagnostics and runtime boundaries |
| 5.21.2 | Released | Faster everyday commands and signed build records |
| 5.21.3 | Current release | Signature checks in the npm installer, signed public source and release files without build paths |
| 6.0.0 | Upcoming | A new typed compiler engine, specification-led language changes, an official executable anyone can rebuild from public source, comparable benchmarks, a compiler rebuild recipe and a migration tool |
| Long-term initiative | Not scheduled | Lighter storage for local records and collections |
The released versions from 5.21.0 to 5.21.3 use the topaz-5.21 language mode. The next public release, 6.0.0, combines the new compiler engine with specification-led language changes and starts the topaz-6.0 language mode. A migration guide and tool help move existing programs to 6.0.0.
Version 5.21.0
5.21.0 is released. It started the topaz-5.21 language mode. Global functions, static namespaces, constructors and standard modules moved to value methods and std modules, and Moving to 5.21 lists every replacement. 5.21.0 also added Length literals and std.typeset, hexadecimal and binary integers with digit separators and integer bit operations, and Topaz began embedding Lispex 1.21. History records the full list.
Version 5.21.1
5.21.1 is released. It is a compatible patch that repairs type inference for generic callbacks and parenthesized calls, makes diagnostics name the right module and value, and fixes native and Web builds and runtime boundaries such as sorting with NaN and invalid dates. History records the full list.
Version 5.21.2
5.21.2 is released. History records its results. It is a compatible patch that makes everyday commands do less repeated work. It also adds signed records that connect each executable to the build that produced it.
Reuse type and import lookups
The compiler builds an ordered list of candidate declarations for each module, scope and name once, then reuses it for every lookup. Programs with many type references no longer search the whole program for each reference. Released in 5.21.2
Private declarations, shadowing, nominal type identity and import cycles keep their behavior. A change to any module rebuilds the lists.
Read plain string text in one step
The compiler reads long string literals, such as embedded data tables, in runs of plain text instead of one character at a time. Escapes, interpolation and error locations inside a literal stay exactly as they are. Released in 5.21.2
Run the checked program directly
topaz run evaluates the program the compiler has just checked. It no longer converts the checked program into another form and reads it back first. Output, exit codes, runtime errors, step limits and cancellation stay the same. Released in 5.21.2
Changes from the earlier plan
Measurements taken before implementation changed the scope. Each earlier item keeps its link here.
Cache syntax references moves to 6.0.0. The typed queries in 6.0.0 link each use to its declaration, so a separate cache would be replaced in the next release.
Reduce temporary compiler arrays is not included. It took almost none of the compile time, and the typed program model in 6.0.0 reads operands directly.
Reduce seed JSON conversions is not included. JSON conversion was a very small part of rebuilding the compiler from the seed.
Simplify generated Rust expressions is not included. Splitting expressions did not reduce Rust compile time or memory use.
The four improvements under review did not show up in measurements and are not included. Asynchronous overhead in generated code is addressed by direct calls in 6.0.0.
Release verification
5.21.2 also changes how a downloaded release can be checked. These changes do not affect program results.
Link each executable to its build
Each downloadable executable is published with a signed link record. The record ties the executable to its source revision, the generated compiler, and the build environment and checks that produced it. Released in 5.21.2
Each record is the project's signed statement of the source and build that produced an executable. The records are listed in signed checksum files, so the Ed25519 signature check on the install page covers them. The public verification workflow in studiohaze/topaz compares each record with the executable it names and checks that the public commit and the compiler.rs it names match the public repository, as described in Checking the release attestation (external).
The latest-version pointer moved to 5.21.2 after the signatures and every published file had been read back from their public addresses. Earlier releases keep their existing files and gain no new records.
Match standard module sources
The public source and Topaz Core Kit take the standard modules std.bytes, std.fs, std.io, std.json, and std.toml from the same files as the official CLI. Programs already produce the same results. Diagnostics that point inside a standard module report the same location in every distribution. Released in 5.21.2
Rebuild the compiler from the 5.21.1 seed
The 5.21.2 rebuild recipe (external) starts with the 5.21.1 public seed and 5.21.2 source, and lists the commands, expected compiler digest, recorded memory use and execution time. History links the published result.
Version 5.21.3
5.21.3 is released. It improves installation and the verification of release files. The language and the compiler are the same as in 5.21.2, so programs build and run exactly as before.
Signature checks in the npm installer
npx topaz-lang and npm install topaz-lang check the Ed25519 signature on the release checksum list before they install anything. It is the same check the install page describes. The installer then compares the archive and the executable with the signed list. A missing or wrong signature stops the installation and says why. Released in 5.21.3
Source and issues from npm
The npm package links to the public repository studiohaze/topaz, where you can read the source and report issues. Released in 5.21.3
Signed public source
The commits and tags that each release adds to the public repository are signed, and GitHub shows them as verified. Released in 5.21.3
Release files without build paths
Executables, the WebAssembly runtime of the playground and the other release files carry no paths from the build machine. Every file is scanned for such paths before it is published. Released in 5.21.3
Examples checked on the release
Before a release goes out, every Topaz example in the README files and the documentation runs on that release's CLI, and its output must match the page. Released in 5.21.3
Planned version 6.0.0
6.0.0 is the next public release of Topaz. It combines the new compiler engine with specification-led language changes. The release includes an official executable anyone can rebuild from public source, a compiler rebuild recipe, benchmarks and a migration tool.
It is the first Topaz release whose specification comes first. Every rule in a new language reference has examples that run on the release before it ships.
Two principles decide what changes. Topaz has one way to say it, and Topaz is a general-purpose language with typesetting built in.
A new compiler engine
The compiler written in Topaz works on typed data, gives known types their own Rust layouts and calls functions directly.
An official executable you can rebuild
In 6.0.0, the official topaz executable uses the Core Kit base with add-ons. Anyone can rebuild the base from public source using the published inputs and build instructions. They can compare it byte for byte with the base executable in the official release.
- The base. The compiler, the CLI commands, the language server and the MCP server are built from public source. Anyone can rebuild the official base executable and get the same bytes on every release target. The signature still shows that a release comes from us, and you can check what it contains yourself.
- Lispex. Lispex runs as a separate WebAssembly module inside a public host. The host, the interface between Topaz and Lispex and the resource limits are public, and the module can use only what the host hands to it.
std.lispexuses the module, and the recommended download and npm package include Lispex. - The reference compiler. The reference compiler used for comparison moves out of the official executable into an optional add-on. The compiler written in Topaz stays the only default.
The Core Kit CLI commands are written in Topaz. Rust stays only where the executable meets the operating system, the WebAssembly host and cryptography. The base and add-ons follow the commands, flags, output, exit codes and diagnostics defined for 6.0.0.
Typed program model and queries
The compiler stores each program as typed data with numeric IDs and answers name, signature and type questions through cached queries. Each answer records what it read, so an edit invalidates only the answers that depend on the changed code. Names that were looked up and not found count too, so a new declaration updates every place that needed it.
Release builds check the standard modules once and ship the result with the compiler. A program that imports std.typeset then checks only its own code on each command instead of the whole module again.
Tools receive the compiler's JSON output in the format defined for 6.0.0.
Records, strings and newtypes as Rust types
A record type whose fields are all known becomes a Rust struct, and reading a field becomes a direct access. Records with optional fields still tell a missing field apart from a field set to None. A record update still leaves earlier copies unchanged.
Strings pass between compiled code and the runtime without conversion. A newtype stays a distinct type and keeps the representation of the type it wraps. A match over string literals compiles to direct comparisons in the same order. Character, byte and Unicode behavior stays the same.
Enums, Option and Result as Rust enums
Enums, Option and Result with fully known types become Rust enums. A match without guards that covers every case compiles to a Rust match.
Direct calls
The compiler records which functions can pause, for example by running concurrent code, waiting on the host or reaching a cancellation point. A call to a known function that can never pause becomes a plain Rust call and no longer allocates on the heap.
Step limits, deadlines, cancellation, recursion limits and defer keep their behavior. A call through a function value whose target is unknown keeps the current path.
Incremental checking in the editor
The language server keeps query results between edits. Editing a function body rechecks that body and the code that reads its results, and leaves unrelated modules alone. Diagnostics appear only for the latest version of each file.
Rebuild the compiler from public source
6.0.0 publishes a recipe for rebuilding the compiler from its public source and published inputs. The reconstruction chain starts afresh at 6.0.0. The recipe regenerates compiler.rs and the checked standard modules that ship with the compiler, so anyone can compare them byte for byte with the published files. It lists the commands, inputs, build conditions, memory use and execution time.
Build cache
topaz build keeps compiled dependencies and unchanged work between builds instead of starting from an empty directory. The cache is keyed by the toolchain, target, build profile, runtime and inputs, so a change to any of them never reuses stale output.
One way to say it
Where Topaz has two ways to write the same thing, 6.0.0 keeps one. Line endings, letter case and parentheses no longer change what a program means. For example, defer requires a block, lambdas always put their parameters in parentheses, radix prefixes and hexadecimal digits are lowercase, an if without else always has the value unit, and every command that prints JSON takes --format json.
A specification you can check
Each rule in the new reference says why the language has it and links to examples that run on the release. Behavior the compiler does not follow yet is marked as a known limitation until it does. The current reference stays available for 5.21.
Documentation after 6.0
The 6.0 manual lives at /v6.0. 6.0.x patches keep that address, and a later 6.1 gets its own. The Topaz 5 manual stays available at the 5.21.3 release, with a notice at the top that it is an older version, and older 5.x links lead to it. Classic becomes the Topaz 5.6 manual, a snapshot of an earlier milestone, with the same notice. History links to both.
Moving to 6.0
6.0.0 starts the topaz-6.0 language mode. A migration guide lists every change, and a migration tool rewrites each removed form into the form that remains in one pass. Removed forms are not kept for a warning period.
All products we build with Topaz will move to Topaz 6 with this release.
Public benchmarks
6.0.0 will publish benchmark results alongside TypeScript, Python and Rust running the same programs under the same conditions. The results cover startup, run time, memory use and lines of code. A clean first build and a rebuild after changing one file are measured separately.
The programs, the scripts that run them and the measurement method will be in the public repository before 6.0.0. Anyone can review the method in advance and repeat the measurements. The Topaz executable measured is the official 6.0.0 release, which anyone can rebuild from public source using the published inputs and build instructions.
Release conditions
6.0.0 ships when the new engine is complete and meets What every engine change keeps. The official base executable and compiler must be rebuildable from public source. The remaining language decisions must be settled, and every example in the new reference must pass on the compiler. The migration tool must convert existing programs, and the benchmark results must be published. Incremental checking and the build cache are planned here and each ships in the first release where it is ready.
What every engine change keeps
The language specification (SPEC) defines values, evaluation order and errors, and leaves value storage to the implementation. Engine changes preserve these rules for each language mode while changing storage and calls.
- The same input produces the same Rust, and the compiler written in Topaz still regenerates its checked-in Rust byte for byte from source.
- Evaluation order, output, runtime faults and diagnostics stay unchanged.
- A program behaves the same when run directly, built as a native executable or built for the Web.
- Topaz adds no pointer operations, lifetime parameters, inline assembly or JIT compiler, and programs need no manual memory management.
- Release builds stay compiled ahead of time through generated Rust. Input and output stay visible as standard module calls, and existing release targets stay compatible.
Long-term architecture initiative
These plans run across several releases after 6.0.0 and are not tied to a version number.
Lighter storage for local records and collections
Zero-overhead canonical lowering (ZOCLE) removes runtime overhead from the Rust that Topaz generates. 6.0.0 delivers its first part with typed records, enums and direct calls. The steps below follow in this order on the same typed program model. Each step is kept only when measurements show a gain without longer builds, more memory or larger output.
- Local records. A record that is never returned, stored or captured becomes a Rust struct or separate local values. It then needs no heap allocation or reference count.
- Typed arrays and maps. Arrays and maps with known element types get typed Rust storage instead of the shared runtime value.
- Loop fusion. Chains of collection methods such as
filterandmap, and comprehensions, run as one loop without intermediate arrays. The compiler fuses them only when results, output and runtime faults stay the same, for example when the callbacks perform no input or output and change nolet mutstate. - Storage reuse. A record update such as
User { ...before, status: Status.Paused("review") }, or a collection method that returns a new array, reuses the source's storage when no other code refers to the source. The remaining code cannot observe the difference. - Vectorization. Arrays of
intandfloatare stored as contiguous Rust vectors, and loops over them are generated in a form that rustc and LLVM can vectorize. Vector instructions depend on the CPU and on WebAssembly features, so each target is measured separately.
Follow the plan through release
Each version and improvement on this page has a stable link. When a version ships, its History entry links to its plan here, and the included improvements link to their released results.
If an improvement moves or its scope changes, this page explains why and shows where it went. History records what has actually shipped.
This page covers the current line and the next public release. When a new line ships, the page starts again from its first release. Earlier lines stay in History.