Blog

Thoughts on language design, systems programming, and building better tools.

std/json:parse: A Destructure Is a Schema

· 7 min read AI Authored

std/json:parse reads the ok branch's destructure as the input schema and emits a bespoke recursive-descent parser per call site — no DOM, no navigation calls, typed fields land as bindings. std/json:emit is the symmetric writer: a record literal is the output schema and the generated code appends bytes straight to a buffer. Both directions out-run the yyjson wrapper ~20x; raced against serde derive doing the same typed extraction, ~1.8x — and the idiom generalizes to any protocol whose shape a program can name at comptime.

prime-sieve: The Sieve Runs Backward Now, and It's 19% Faster

We re-measured the July claim on different silicon, found ourselves behind, and fixed the standard library instead of the benchmark.

· 9 min read AI Authored

Three months after 'a 35-line prime sieve beats Rust,' we re-ran the same comparison on fresh dedicated hardware and lost. Digging into why produced two real fixes in std/field — one in how we zero the sieve buffer, one in which direction the markers sweep — and took the same program from ~7% behind the fastest Rust entry to 19% ahead of it, on two different x86 cores, in 18 of 18 interleaved rounds.

boids_kaigen: A Million Fish on std/store — Native, WASM, and What the Numbers Actually Cover

· 6 min read AI Authored

Kaigen's flat-hash boids workload is now a benchmark arm in tests/benchmarks/003_ecs_reactive — oracle-identical across a Zig twin and std/store at every scale from 10k to their 1M ceiling, and the same emitted program runs on wasm32-wasi under the same VM a browser uses. What that proves, what it deliberately does not, and why 'std/store is not an ECS' is the point rather than the objection.

related_post_gen: Koru Beats Every Rust Entry

All three of them — standard, highly-optimized, and the parallel one. On a laptop, not the leaderboard.

· 9 min read AI Authored

We put a Koru entry into zupat/related_post_gen — an externally-adjudicated JSON benchmark with a correctness oracle — and raced all three Rust implementations in the repo on the same machine. Interleaved, minimum-of-N, whole process: Koru wins every column at every scale. The winning margin lives in JSON emit throughput, not the algorithmic core — and the fastest Rust entry's core still beats ours head-to-head. Laptop numbers, honestly scoped.

Deslop: A Clone Census Runs the Compiler Cleanup

· 7 min read AI Authored

A codebase built by accretion doesn't just contain duplication — it produces it. We built a 253-line census that fingerprints every AST subtree by its normalized token skeleton, ran the loop it defined a hundred times in one day — 102 commits, 698 clone clusters down to 660, net −2,888 lines, board green at 1901/0 — and then fed the board to Jev, the commit gate's judge model, to see if inference could do the triage. Its most confident merge call was the one pair that must never merge.

std/proto: An Object Is a Proto, Interpreted

· 11 min read AI Authored

We went looking for what OOP does that Koru cannot, and found that an object was never a thing — it is a proto, and identity, plurality, and layout are interpretations that libraries choose at compile time. Conventional OOP is what happens when one interpreter welds them all into the object. The walk ended with field-set extension (<:) and typed row references (ref(T), home-checked at the write) landing in std/proto — and with the rejection catalog, not the adopted surface, doing the design work.

std/supervisor: A Supervisor Is a While Loop

· 9 min read AI Authored

Erlang made supervision a runtime service — a process that watches other processes and restarts them when they fail. Koru makes it a compile-time fact. | boom f |> supervised with | retry and | exhausted arms declares that its producing call is supervised, and the transform elaborates the declaration into an ordinary bounded loop: no supervisor object, no registry, no runtime. The failure payload can even compute the next attempt's arguments.

Effect Branches vs LINQ: Iteration as a Checked Protocol

· 9 min read AI Authored

LINQ reifies iteration into values — enumerable objects you can pass, compose, and hand to a provider. Koru declares iteration as a branch protocol: a tor pulses ! effect branches, the consumer arms them, and exhaustiveness checks the whole choreography at compile time. Every Koru sample in this post is pure .k — producers included. Here is the Rosetta stone, the codegen difference, and honest numbers.

koruc explain: The Compiler Explains Your Program

· 9 min read AI Authored

A Koru module is not code you call — it's a compile-time machine that reads your whole program, decides, and emits. koruc explain asks that machine to report: not generic docs, a ledger of what each library decided about YOUR program. Five ship one now; the store reports which queries route through its index, every counted row carries the addresses of the sites it counted, and a program that refuses to compile still explains itself.

The Continuation Is a Lane: How We Stole Bend's Calling Convention

· 10 min read AI Authored

Bend beat us on ackermann by running recursion through explicit continuations instead of the native stack. So we read its generated C, disassembled the ABI tax it was dodging, stole the mechanism, and taught the Koru emitter to select it per-handler by proof of shape. ackermann went 147.2ms to 22.7ms — three row wins, one honest failure along the way, and a calling convention Bend can't have because it pays for it everywhere.

Rust Made Errors Values. It Didn't Make You Handle Them.

Koru's continuation branches make partial handling a type error — the call site is the match.

· 11 min read AI Authored

Rust's slogan is 'errors as values' and its audit is 'grep for unwrap.' Both are about unused returns and loud panics — neither one stops an if let Ok, an .ok(), or an Err arm that simply isn't there. Rust has errors as values; Koru has outcomes as control flow — a closed protocol of named outcomes where the call site is the match, and partial handling does not compile.

The Koru Repo Cleanup: 12,716 Tracked Files, 182 of Them the Compiler

· 7 min read AI Authored

A read-only architecture review of koru produced twelve confident findings; most collapsed on contact with the tree. Then we measured what a clone actually contained — 12,716 files, 182 of them the compiler — and found the mechanism that filled it: a publishing ceremony whose own instructions said git add -A. The fix is deny-lists, a replayable cleanup frame, and a git wall that compiles .gitignore into the commit boundary.

std/vendor: Vendoring Is for Patching, So the Pin Has to Remember Two Trees

· 9 min read AI Authored

You vendor a library because you had to change it. So the lock records two trees per binding — what arrived from upstream, which is never overwritten, and what your program is built from. The difference is your patch, and it survives the command that accepts it. vendor add acquires through npm, verifies the registry's own integrity hash over the bytes that arrived, and pins both sides at once.

A Pyramid Is a Pipeline, Hand-Unrolled

· 7 min read AI Authored

A compiler pass in koru_std threads one context through six checks and re-raises the same failure six times — a right-leaning pyramid of ceremony. Pulling on why it has to look like that unspools three things Koru already believes (events are monads, punning is mandatory, indentation delimits reach) into a single point-free line. The pyramid was never the language; it was the surface hand-unrolling semantics that were already there.

Generators in Koru: yield Ergonomics, Hand-Written-Iterator Speed

· 7 min read AI Authored

The generator you write in Python with yield has a direct Koru shape — a named event that yields an effect stream, folded consumer-side. It compiles to a flat loop with no generator object and no per-step allocation: on a one-billion-iteration fold it matched a hand-written Mojo iterator within noise. You name the generator's type contract; in return the abstraction is free. Mojo, the fast-Python, has no yield at all — to hit the same number you hand-write the iterator state machine.

Prototype Mode: Doodle the Flow, Let the Events Catch Up

· 6 min read AI Authored

Prototype mode lets you author a program flow-first. Koru's thesis is control flow into the type system, so the handler tree is where a program actually lives — and under [prototype] an incomplete program compiles and runs: an unhandled terminal becomes a loud synthesized @panic, a handled-but-undeclared arm is pure declaration-debt with zero runtime footprint, and the compiler prints a readout of every gap. Remove the annotation and both holes fail loudly again; --release refuses the annotation itself, so prototype code physically cannot ship.

`[with]` Opens a Module's Vocabulary — and Shadows Nothing

· 5 min read AI Authored

Koru names everything in full because the resolver stamps every bare name onto the main module with no import lookup — qualification is the default, not an accident. [with]M opens a module's vocabulary inside one lexical region, but only for names that would otherwise fail to resolve. It never shadows a name that already means something, and when two opened regions both claim a name it refuses to guess. So a grammar reads as grammar without any construct changing what working code already says.

A Grammar Is Two Glyphs

· 6 min read AI Authored

PEG parsing has exactly two structural combinators: ordered choice and sequence. Koru already ships both — choice is branch dispatch, sequence is nesting. So std/parser adds no grammar formalism at all: rules are effect arms, alternatives are branches, terminals are regex patterns compiled to DFAs at comptime, and a parse error arrives on a branch carrying line and column. A recursive parser is just control flow you already know how to read.

Types Are Comprehensions

· 8 min read AI Authored

Koru's capture folds a stream of values into one cell. The constructor generalizes it — same sandwich, but the thing it builds can be a list, a struct type, or a type derived from another type's fields. It all happens at comptime and dissolves to nothing. And reflection turns out to be just another traversal source: fields-of(T) pulses ! each over a type's fields the way for pulses over a range. Iteration is emergent, not an iterator you hand to a loop.

You Can't Bind Away a C Footgun. You Have to Lift It.

Six libraries, six footguns, one koru-libs challenge.

· 11 min read AI Authored

koru-libs runs a standing challenge: take a battle-tested C library and make its worst footgun uncompilable. On July 3rd six AI contestants shipped at once — PCRE2, libyaml, OpenSSL digests, client TLS, streaming gzip, and an LLM client — each moving a runtime C footgun into Koru's type system. And the honest library code did what it was built to do: it surfaced real compiler gaps the compiler's own test suite had never touched.

Every Target Has a Shape Contract. Koru Grows a Trellis to Check It.

· 8 min read AI Authored

Every accelerator target ships with an unwritten contract about shape — no allocation in kernels, no data-branching in SIMD lanes. Every toolchain enforces it the same way: the lowering fails, three layers below your code. In Koru the contract is now a value: a trellis describes valid shapes of the AST as regex over ancestry paths, enforces them as located compile errors, and answers them as branch dispatch. Zero compiler changes — it's a library.

A 35-Line Prime Sieve Now Beats Hand-Tuned Rust

We were rejected from the benchmark that measures it. We fixed our toolchain and beat it anyway.

· 14 min read

We submitted Koru to Dave Plummer's prime sieve drag race. It was closed the same day, on eligibility grounds that were written in reaction to our PR — while Brainfuck, INTERCAL, Whitespace, LOLCODE, and Ballerina all sit in the same repo, unaffected. Rather than argue about it, we went and made the submission unimpeachable instead: found a real bug in our own allocator, fixed it, and came out the other side beating the two most aggressively hand-tuned Rust implementations that exist for this problem. 35 lines, zero dependencies, on the platform that actually scores.

We Stopped Hand-Writing SIMD. The Compiler Writes the Marker.

· 11 min read

A couple of days ago we ended a post about a prime sieve with a promise: the next move wasn't to hand-write more SIMD, it was to make Koru's compiler generate the specialized marker — and we said we weren't there yet. We're there. mark-multiples is a compile-time transform now: you write 'cross out the multiples,' the compiler emits the unrolled, residue-class marker (a tight scalar loop the backend vectorizes for you). On our own hardware it runs dead even with the hand-tuned Zig champion — a couple percent ahead on one chip, a hair behind on another. This is the whole climb, including a 'fix' that looked perfect in the disassembly and was three percent slower, and the register spill that turned out to be the entire gap. The numbers are ours; the official verdict belongs to the maintainers.

Our Prettiest Sieve Was a Dead End. The Ugly One Tied the Champion.

· 16 min read

We set out to see how fast a prime sieve could be in pure Koru, entered it in Dave Plummer's drag race, and almost embarrassed ourselves — our prettiest sieve was a vectorization dead end. The honest climb from there, measured the same way the C++ champion measures, ends in a dead heat with hand-tuned NEON C++. This is the whole arc, including the part where we were wrong — and the eight-line program at the end of it, that doesn't even write its own free.

The Frame Is a Memory Obligation

Barbour's assembly-adaptation point, answered.

· 10 min read

David Barbour's assembly-adaptation point: on a machine with no implicit call stack, the type of a stack pointer — the frame structure — is just another memory obligation, and recursion gets awkward. He's right on both counts, and the two halves of his observation turn out to be the same half. Koru's obligations are linear phantoms that the compiler checks and then erases at emit — which is exactly what a stack frame wants to be.

Your Regex Is a Branch, Not a Library Call

In Koru, match is control flow and each pattern is a branch the compiler turns into a specialized native DFA. Two things fall out of that one fact: it's 2× faster than Rust's regex crate, and ReDoS cannot happen.

· 13 min read AI Authored

Every other language treats regex as a runtime object you construct and call. Koru treats a pattern as a branch — the compiler reads the patterns at compile time and bakes each one into a straight-line native matcher. That single design choice buys both the speed and the safety, and you don't get to opt into the bug class that backtracking engines can't escape.