What "1.0.0-rc2" is, exactly
rc2 is a small, deliberate step, not a feature wave. It was cut for two reasons.
- To exercise the release pipeline end to end. The tag-release jobs (bootstrap-verify plus the release build) now produce the registry artifacts, so what adopters download is built by CI from a tagged commit rather than hand-uploaded. rc2 is the first tag to run that path in anger.
- To carry the fixes accumulated on
mainsince rc1 into one coherently-versioned build: a compiler fix where an untyped struct-return bind failed to propagate its type through a for-loop, a codegen fix where spawning a void-returning function emitted invalid IR, and the new features below. VERSION,src/main.kern, and the README all read1.0.0-rc2.
The honest-framing rule from rc1 still holds: the language implementation is 1.0-grade (it self-hosts, the full suite is green, the concurrency model is race-free, the build is reproducible), and the verifiable-trust goal is mid-roadmap. What changed in rc2 is one of the trust rows.
Reproducibility moves past single-machine
The single biggest caveat on rc1 was the word single-machine: everything was evidenced on the one box that built it. rc2 breaks that for the compiler's intermediate representation.
- Two machines, two operating systems, byte-identical IR.
check_reproducible.sh --iremits all 102.llfiles and they are byte-for-byte identical across two independent bootstraps: on the Mac (viakern_v4) and on a Linux box (viakern_seed), verified 2026-07-13. Cross-OS determinism holds too: the macOS seed and the Linux re-emission agree. This is Step 3 of the trust roadmap, no longer local to one host. - End-to-end binary, reproducible on the box. On the Linux machine the gen2 and gen3 binaries are byte-identical, which is Step 4 evidenced there.
The honest boundary is precise, and worth stating rather than blurring: the IR
is reproducible cross-machine and cross-OS; the whole binary is reproducible on
one box; and none of it is yet a per-commit CI gate or externally audited. The
live TRUST.md dashboard marks each of these rows as manual, not
gated. The direction of travel is what matters: trust is becoming a property a
second machine re-derives, not a promise the author makes.
Static files that actually serve, over HTTP and HTTPS
http_static(url_prefix, dir) used to be a no-op: it recorded the
mount and never read it, so every static path 404'd. In rc2 it serves files,
and it does so on both the plain-HTTP worker and the TLS server.
- It serves real files. Content type is set by extension (html, css, js, json, svg, png, fonts, wasm and more),
index.htmlis served for the mount root and for directories, and onlyGETandHEADare answered. Dynamic routes coexist with the static mount. - Path traversal is refused before a file is opened. Any request containing
..is rejected with403before the filesystem is touched at all. It was verified that the guard will not serve/etc/passwd. - The same code serves plaintext and TLS. The implementation was refactored around a write sink: the plain worker passes a raw file-descriptor sink, the HTTPS worker passes a TLS sink, so static files no longer get written as plaintext onto a TLS socket (which is what made the HTTPS worker 404 every static path before).
A safe escape hatch for long-lived state: persist
Kern can run HTTP requests under an epoch garbage collector
(KERN_HTTP_EPOCH_GC): every object allocated during a request is
reclaimed in one shot at the end of the request, which is fast and leak-proof
for request-scoped work. The sharp edge is global state. If you take a
request-derived value, say a client IP, and store it into a long-lived global
map (a rate-limiter's table, a cache), the arena pages it lived in are
munmap'd at request end and the key dangles, which is a hard
segfault, not a subtle bug.
persist(s: str) -> str is the fix: it returns a permanent-heap
copy of the string, safe to store in global state even when called inside a
request epoch. It is implemented as a thread-local redirect in the GC allocator
that copies the bytes onto the permanent heap without disturbing epoch or
collection semantics, verified with a C escape reproducer and
test_persist.kern. It is the smallest primitive that makes an
in-process rate-limiter or cache correct under epoch GC, chosen over a narrower
keyed-limiter built into the runtime.
Adopter tooling: version pinning and a Docker-independence attestation
Two features came straight from adopters, and both turn a claim into a check you can run.
.kern-versiontoolchain pinning. Drop a one-line file (for example1.0.0-rc2) next to the source you build or in the working directory.kern build,run, andcheckcompare it to the running compiler and printwarning: kern-version-mismatchwhen they differ, so a compiler upgrade or a stale binary surfaces immediately. It is warning-only and never breaks a build; a CI job that wants hard enforcement greps for the warning.kern audit-docker <file>. It walks a program's full resolved import graph and reports whether it takes any Docker dependency: an import ofsys.docker(which shells out to the docker CLI), or a/var/run/docker.sockreference. A clean program printsaudit-docker: PASS; a Docker dependency isFLAGGEDand the command exits non-zero, so CI can gate on it. "Docker-free" stops being a README sentence and becomes an auditable fact: a Kern binary is native and links no Docker client.
The standard library continued to grow alongside these: it is now 272 modules
and 1,961 public functions across std, data,
net, db, and sys.
Where verifiable trust stands: Steps 2 to 7 of 12
The trust program is a 12-step roadmap, and being honest about a release means being honest about which steps are done and how far. rc2's progress lands in the reproducibility rows, which are no longer confined to the build host:
- Step 1: the Trusted Computing Base is written down. Exhaustively, in
TRUST.md: every component a Kern binary must trust, and which step verifies it. - Step 2: the C runtime TCB is shrunk to an auditable core. The trusted part is named and minimal by construction; new functionality defaults to capability-bounded Kern, outside the TCB.
- Step 3: deterministic compiler output. Now byte-identical across two machines and two operating systems (macOS and Linux), verified by hand, not confined to the build host.
- Step 4: reproducible end-to-end binary. gen2 and gen3 binaries byte-identical on the Linux box; not yet a per-commit CI gate.
- Steps 5 and 6: an independent bootstrap path and a diverse double-compilation gate. In progress: the second machine now runs its own
kern_seedbootstrap, which is the raw material for both. - Step 7: a capability-secure core. All authority-bearing entry points require an explicit
Cap<T>; ambient authority is a compile error (E0404).
What stands between rc2 and 1.0.0 final
The remaining five steps are exactly the difference between "trust we can evidence here, on two machines" and "trust a third party can re-derive on a per-commit basis." None are aspirational; each has a Done-when clause on the roadmap.
- Step 8: capability provenance and audit tooling. Make a binary's actual grants inspectable and checkable.
- Step 9: sound, whole-program flow analysis. The soundness backing for the privacy and capability claims.
- Step 10: a verifiable supply chain.
- Step 11: formal verification of the trust-critical path. Coq was chosen as the proof assistant (INRIA, EU-native, the CompCert track record); the lexer track is scaffolded.
- Step 12: an independent audit and the verification dossier. Plus turning CI on, so every claim above is re-checked on a machine that is not the author's.
Every item is on the ROADMAP with a checkbox and a Done-when clause. A trust claim with no check is not done.
By the numbers
- 1,014 tests at 100% pass, 787 conformance and 227 negative; both gates CI-blocking
- Compiler IR byte-identical across two machines and two OSes (macOS and Linux, manual); end-to-end binary byte-identical on the Linux box
- Steps 2 to 7 of 12 trust-roadmap steps done, with reproducibility now cross-machine; Steps 8 to 12 remain
- 0 data races: the GC is thread-safe, ThreadSanitizer-verified
http_staticserves files over HTTP and HTTPS, with a strict path-traversal guardpersist(): the epoch-GC escape hatch for long-lived global state.kern-versionpinning andkern audit-dockerattestation- 272 stdlib modules, 1,961 public functions, across
std,data,net,db,sys - 36,192 lines of Kern in the self-hosted compiler, 42K lines in the C runtime
- EUPL-1.2, hosted on Codeberg, governed from the Netherlands
Try v1.0.0-rc2
Install on Linux or macOS. Single binary, no runtime dependencies.
curl -fsSL https://kern-lang.eu/install.sh | bash