# kern 1.0.0

> The release line is stable, releases are signed, and the clock became a capability.

Source: https://kern-lang.eu/releases/1.0.0

The release line is stable, releases are signed, and the clock became a capability

October 3, 2026

## Release notes

## v1.0.0, and what the label means

The first stable release, tagged 2026-10-03\. The language **implementation is 1.0-grade**: it self-hosts, the full suite is green (**1,423 conformance + 403 negative, 1,826 tests at 100% pass**; both gates CI-blocking), the concurrency model is race-free (thread-safe GC, ThreadSanitizer-verified, ASan/UBSan-gated) and the build is reproducible byte-for-byte.

### The surface is frozen

`docs/stability.md` enumerates what 1.0 promises: the grammar, type system, taint rules and capability model, every `pub fn` in the stdlib index, the CLI and its `--json` schemas, the `kern.toml` keys. A removal takes a full deprecation cycle: `@deprecated` in a minor release, warning **W0004** at every call site for the rest of the major line, removal only in 2.0, and `kern fix` performs the drop-in migrations mechanically. The systems surface a hypervisor builds on (`std.cap_vm`, `std.cap_unsafe`, `std.arena`, `std.dma`, `std.irq`) is locked in `docs/systems-surface.lock`, and a changed line without a recorded reason is a red gate.

### A release is a signed tag that builds from source

Tags are signed with a key whose public half is pinned in the repository; the release job refuses to publish from a tag that does not verify; artefacts (the C runtime bundle and the Windows launcher) are signed offline with a second pinned key. No compiler binary is published by any route, because for a compiler a downloaded binary is exactly the Trusting-Trust threat the toolchain exists to remove; the Homebrew tap is the repository itself, so there is no second copy of the formula to fall behind.

The project's headline goal is **verifiable trust**, and that programme is at ten of eleven steps. Deterministic compiler IR (Step 3), the reproducible end-to-end binary (Step 4), the independent bootstrap path (Step 5) and the diverse double-compilation gate (Step 6) are **per-commit CI gates**. `kern audit-caps` makes the audit surface the capability grants, not the code (Step 8). The verifiable supply chain (Step 10) is closed on all four sub-claims.

Capability enforcement, the lexer bisimulation and flow-analysis soundness are **machine-checked** in Rocq with zero admits (Step 11), re-checked per commit. What 1.0 does _not_ claim, named rather than left to be found: the proofs are about _models_. The lexer model is now measured against the shipped lexer on every file in the tree, and the taint model is extracted and judged beside `kern check` on generated programs (300 of 300 agree); for the capability model the evidence that the compiler implements it is still the probe grid and the negative suite, not a mechanised link.

Step 12, the independent external audit, was removed from the plan on 2026-09-19 and is taken up when ready. Performance is not at Go's on every benchmark cell; the per-cell matrix and ceilings are in `docs/design/performance-to-go-parity.md`. The live `TRUST.md`, `ROADMAP.md` and `docs/threat-model.md` track exactly what is and is not verified. The flagship privacy claim, `PersonalData<T>` to AI is a compile error, extends to every sink: display, file, database and HTTP, not just the LLM call.

## v1.0.0: the release line is stable, releases are signed, and the clock became a capability

Around the 1.0.0 tag the type system tightened in four places, two of them found by the project's own formal models. Two of the four are in the tag (the clock capability and per-type generics); the other two, E0331 and the trait-bound fix, landed on `main` on 2026-10-04, the day after, together with the PersonalData runtime fixes, and ship in 1.0.1.

### Implicit flow is E0331

The shipped checker accepted `if secret: out = "a"` followed by `print(out)`, for two reasons each sufficient on its own: `pd == q` typed as a plain `bool` (the operator dropped the tag), and there was no program counter. The machine-checked taint model, extracted to OCaml and run beside `kern check` on 300 generated programs, disagreed on 83 of them, every one an implicit flow. Now an operator's result carries every tag of its operands, `if`/`elif`/`else`, `while`, `match` arms and a `for` over a tagged iterable run under a program counter, and under a tagged pc a write to an untagged variable, a call to an effectful function, a `spawn`, an untagged `return` or a `break` out of an untagged loop is refused. Measured across all 2,352 files in the tree: seven new diagnostics, all real; 300 of 300 and 2,000 of 2,000 generated programs now agree.

### The clock is authority

`time_now_ms`, `time_now_seconds` and `time_sleep_ms` take `Cap<Time>`; the ambient `now_ms` / `now_seconds` / `sleep_ms` are confined to `std.cap_time` and are E0404 anywhere else, exactly as entropy already was.

### Trait bounds were dead code

The call-site check looked for a one-letter type name; since a 2026-09-10 rename a generic parameter's type is a marker, so the guard was false for every call and a bounded generic accepted any argument. It hid because the two gates that would have caught it ran only in `make verify-release`, which nothing ran automatically, so v1.0.0 was tagged with both red. Both are release-gates steps now, and `check-release-checklist-in-ci` fails when a verify-release member is run by nothing in CI.

### Generics are compiled once per type when they compare their parameter

A comparison on two erased generic operands used to segfault for an inline-packed int, so it had been refused as E0330 and the stdlib carried `_int` twins; the typechecker now records which type each parameter takes at every call and emits one specialisation per binding. `any_eq`, `all_eq`, `count_eq`, `list_contains` and `list_count` are generic, their `_int` twins deprecated with `replace:` so `kern fix` does the rename.

### The JSON parser left C

221 code lines out of the `protocol` class, the largest single risk the threat model names. The C parser was declared to return a map and returned whatever the top level happened to be, so `json_decode("[1,2,3]")` parsed and the first map operation walked a list as a map, exit 139, reachable from the network through the service dispatcher. The C fuzz harness had run 97 million executions under AddressSanitizer and was clean, because it called the function and never used the result as its declared type promised.

The Kern decoder is total and strict; the harness is deleted rather than left calling a stub. With it, the TCB is now **split by kind of trust** (substrate, protocol, platform, binding, migratable, asm) and the split is a gate, so a new runtime file cannot be added without saying what kind of trust it carries.

### Packages cross repositories

`kern-pkg publish` packs and uploads from the file, `update` records a real SHA-256, `install` checks the checksum, the pinned signature and that the archive names the locked package before moving it into place, and the compiler resolves a dotted import into `kern_modules/<name>/src/`. None of it had worked before (publish truncated the tarball at its first NUL byte); `check-pkg-roundtrip` runs it end to end against a loopback registry.

### Also in this cut

Two builds of one program are byte-identical (the pid left the link name, a macOS link without `-g` drops its dead debug map; gate 64); a signed JWT whose payload was a JSON array never expired, found by writing the test for its documented error code; every bare error string in the stdlib is now a coded error and the ceiling is zero; `kern desktop` is the Docker Desktop equivalent served from the one binary on loopback with three independent controls; a rootless container maps the user's subordinate id range and a non-root host agent holds a container to its disk through a privilege-separated mount helper; and the cloud control plane gained four-eyes approval on destructive actions, durable volumes, snapshots, revocable SSH keys and a web console into a running instance.

[Read the announcement: kern v1.0.0, the release line is stable ](https://kern-lang.eu/blog/v100-release) 

Install

`$ curl -fsSL https://kern-lang.eu/install.sh | sh`

Upgrade with the same install command. Releases are signed.

[Get started ](https://kern-lang.eu/get-started)
