Literate Driven Development

Case study · kcc

kcc — a C compiler, written as literature.

One of the hardest programs there is, authored end to end in Literate Driven Development. kcc reads C17, checks it against the Standard, optimizes it, allocates its registers, and emits native ARM64 machine code — plus x86-64 for macOS and Linux — and it compiles itself to a byte-identical binary. It doesn't build textbook toys; it builds the code that runs the world.

Boots a Linux 6.6 kernel ARM64 + x86-64 SQLite Lua zlib doomgeneric self-hosting

Built by one person on a $100/mo Claude Code subscription, powered by Claude Opus 4.8 — using the LDD methodology.

A Linux kernel compiled with kcc boots and reaches a login session — recorded in real time.

How it compares

One person, $100 — against agent fleets and $20,000.

In 2026 two high-profile efforts built AI-written C compilers that boot the Linux kernel: Anthropic's Claude C Compiler and Blitzy's autonomous fork. Both are impressive — and both make kcc's point for it.

LDDkcc AnthropicClaude C Compiler BlitzyAutonomous
Built byOne person + Claude Code (Opus 4.8)16-agent team + a researcherAutonomous agents (fork of Opus 4.6)
Cost~$100 — one Max subscription~$20,000Enterprise platform (undisclosed)
Effort~230 h · 42 days · 408 commits~2,000 sessions · 2 weeks~2 weeks, built on the Anthropic effort
ImplementationLiterate ARM64 assembly (no Rust runtime); emits its own Mach-O~100,000 lines of Rust~230,000 lines of Rust
Self-hostingYes — byte-identicalNo (depends on Rust std)No (Rust-based)
MethodologyPure literate programming — a readable bookAgent teams; conventional codeAutonomous generation; conventional code
TargetsARM64 (native, Apple silicon) + x86-64 (macOS & Linux)x86 · ARM · RISC-Vx86 · ARM · RISC-V
Boots a kernelLinux 6.6 → BusyBoxLinux 6.9 (three arches)Linux kernel
VerificationISO Standard + differential + byte-identical self-host99% on major suites (incl. GCC torture)Enhanced CCC suites

~200×

cheaper than the ~$20,000 effort — a single $100 subscription.

1 vs 16

one author, not an agent fleet with a researcher steering it.

Self-hosts

the others do not — kcc recompiles itself to a byte-identical binary.

The takeaway

kcc's point is the whole thesis of LDD: the same headline result — a from-scratch C compiler that boots a Linux kernel and passes rigorous tests — reached by one person, on a $100 subscription, that self-hosts, and that is legible by construction — a book you can read. The others produced hundreds of thousands of lines nobody will ever read front to back. kcc produced an artifact and its explanation, inseparable.

Sources: Anthropic, “Building a C compiler”; Blitzy, “Hello World: the Blitzy C compiler has arrived.” Figures for kcc are drawn from its own repository and commit history.

What it compiles

Not toys. The real thing.

A compiler only earns trust by building software people actually depend on. Each of these is a milestone in its own right — together they are a gauntlet.

A Linux 6.6 kernel

The ultimate stress test — GNU C, inline assembly, and every dark corner of the language. kcc compiles kernel objects that link into a Linux 6.6 image and boot all the way to a BusyBox login prompt. A compiler that produces a booting kernel is production-grade by definition.

SQLite & Lua

SQLite is the most widely deployed database engine on Earth — in every phone, browser, and aircraft. Lua is the embedded language behind countless games and tools. kcc compiles both as whole programs, handling code that billions of devices rely on.

zlib

The compression library beneath the entire internet — HTTP, PNG, Git, the kernel itself. Small, battle-hardened, and utterly unforgiving of a compiler that gets the details wrong. kcc's optimizer is tested with zlib and Lua as the oracle.

doomgeneric

Doom — computing's favorite benchmark for “does it really work?” kcc builds the doomgeneric port and it runs. If Doom plays, the compiler is not a demo; it is real.

The hard bar

Why the kernel is the acid test

“Compiles C” and “compiles the Linux kernel” are worlds apart. The kernel uses the full, real-world dialect the language is actually written in:

  • GNU C extensions — statement expressions, typeof, __attribute__, computed gotos, and more, used pervasively.
  • Inline assembly — hand-written machine code threaded straight through C, where the calling convention and clobbers must be exactly right.
  • Freestanding, no libc — the kernel is its own world; the compiler cannot assume the comforts of a hosted environment.
  • Undefined-behavior discipline — volatile, memory barriers, and aliasing rules that must be honored precisely or the machine misbehaves in the field.

A compiler that clears this bar has confronted the parts of C that break lesser tools — and it did so from a source a person can read.

How it is built

A compiler as a narrative

Every C compiler walks a well-worn road. Written in the literate style, each stage of that road becomes a section you can read in order — the explanation and the code side by side, in whatever sequence teaches best:

  1. Preprocess — macros, includes, and conditional compilation resolved.
  2. Lex — raw bytes become a stream of tokens.
  3. Parse — tokens become a syntax tree that mirrors the grammar.
  4. Type-check — the tree is validated and every expression is given a type.
  5. Lower to IR — the tree becomes a simpler intermediate form.
  6. Optimize — the IR is rewritten to be faster and smaller.
  7. Emit — machine code (and its debug info) is written out.

In a conventional codebase these stages are scattered across hundreds of files and understood only by their authors. Here the reasoning travels with the code, so the whole pipeline reads like a book. Here is a real slice of kcc's own literate source — the opening of the Type System chapter, where LaTeX prose, a memory-layout table, and the ARM64 that implements it all live in one file:

types.weft
\chapter{Type System}
\label{ch:types}

Every C expression has a type, and the compiler must track these types to enforce the language's constraints and to determine the size, alignment, and representation of every object.  This chapter defines the type descriptor---a 48-byte arena-allocated record that encodes kind, size, alignment, and qualifiers---and builds the infrastructure around it.  We begin with the descriptor layout and the pre-allocated singletons for built-in types, then provide constructors for derived types (pointers, arrays, functions, structures, unions, and enumerations), predicate functions for querying type properties, a specifier resolver that converts the parser's bitmask into a canonical type, and a diagnostic dump for debugging.

\section{Type Descriptor Layout}

A type descriptor occupies 48 bytes with the following layout:

\begin{center}
\begin{tabular}{lll}
Offset & Field & Description \\
\hline
0  & TY\_KIND  & type kind constant \\
8  & TY\_SIZE  & size in bytes \\
16 & TY\_ALIGN & alignment in bytes \\
24 & TY\_QUALS & const=1, volatile=2, restrict=4, \_Atomic=8 \\
32 & TY\_F0    & kind-specific field 0 \\
40 & TY\_F1    & kind-specific field 1 \\
\end{tabular}
\end{center}

@d Types: constants @{
// -- Type descriptor layout ---
.equ TY_KIND,       0
.equ TY_SIZE,       8
.equ TY_ALIGN,     16
.equ TY_QUALS,     24
.equ TY_F0,        32
.equ TY_F1,        40
.equ TY_DESC_SIZE, 48

// -- Type kind constants ---
.equ TY_VOID,       1
.equ TY_BOOL,       2
.equ TY_CHAR,       3    // F0=signed(1)/unsigned(0)
.equ TY_SHORT,      4    // F0=signed(1)/unsigned(0)
.equ TY_INT,        5    // F0=signed(1)/unsigned(0)
.equ TY_LONG,       6    // F0=signed(1)/unsigned(0)
.equ TY_LLONG,      7    // F0=signed(1)/unsigned(0)
.equ TY_FLOAT,      8
.equ TY_DOUBLE,     9
.equ TY_LDOUBLE,   10
.equ TY_PTR,       11    // F0=pointee type descriptor
.equ TY_ARRAY,     12    // F0=element type, F1=length
.equ TY_FUNC,      13    // F0=return type, F1=param vec*
.equ TY_STRUCT,    14    // F0=struct_decl AST, F1=member vec*
.equ TY_UNION,     15    // F0=union_decl AST, F1=member vec*
.equ TY_ENUM,      16    // F0=enum_decl AST
.equ TY_INT128,    17    // __int128, F0=signed(1)/unsigned(0); size 16, align 16

// -- Specifier bitmask constants (from parser) ---
.equ SPEC_VOID,       (1 << 0)
.equ SPEC_CHAR,       (1 << 1)
.equ SPEC_SHORT,      (1 << 2)
.equ SPEC_INT,        (1 << 3)
.equ SPEC_LONG,       (1 << 4)
.equ SPEC_LLONG,      (1 << 5)
.equ SPEC_FLOAT,      (1 << 6)
.equ SPEC_DOUBLE,     (1 << 7)
.equ SPEC_SIGNED,     (1 << 8)
.equ SPEC_UNSIGNED,   (1 << 9)
.equ SPEC_BOOL,       (1 << 10)
.equ SPEC_COMPLEX,    (1 << 11)
.equ SPEC_INT128,     (1 << 12)
@}

\section{Type Initialization}

Pre-allocate singleton descriptors for all basic types.  Alongside the standard
integer widths, two singletons cover the GNU 128-bit integer \texttt{\_\_int128}
(kind \texttt{TY\_INT128}, signed and unsigned): each carries size and
alignment~16, so it lays out correctly wherever a 16-byte object is expected---%
notably inside the \texttt{union \_\_u128\_halves} the Linux kernel's
\texttt{cmpxchg16b} code builds.  Only its \emph{arithmetic} is deferred
(Appendix~\ref{ch:limitations}); the descriptor itself is a first-class basic
type.

@d Types: init @{
// -- kcc_types_init ---
// void kcc_types_init(void)
// Pre-allocates singleton type descriptors for all basic types.
.text
.globl _kcc_types_init
.p2align 2
_kcc_types_init:
    stp x29, x30, [sp, #-32]!
    mov x29, sp
    stp x19, x20, [sp, #16]

    // void
    mov x0, #TY_DESC_SIZE
    bl _kcc_arena_alloc
    mov x19, x0
    mov x1, #TY_VOID
    str x1, [x19, #TY_KIND]
    str xzr, [x19, #TY_SIZE]       // void has no size
    str xzr, [x19, #TY_ALIGN]
    str xzr, [x19, #TY_QUALS]
    str xzr, [x19, #TY_F0]
    str xzr, [x19, #TY_F1]
    adrp x1, _kcc_type_void@@PAGE
    add  x1, x1, _kcc_type_void@@PAGEOFF
    str x19, [x1]

    // _Bool
    mov x0, #TY_DESC_SIZE
    bl _kcc_arena_alloc
    mov x19, x0
    mov x1, #TY_BOOL
    str x1, [x19, #TY_KIND]
    mov x1, #1
    str x1, [x19, #TY_SIZE]
    str x1, [x19, #TY_ALIGN]
    str xzr, [x19, #TY_QUALS]
    str xzr, [x19, #TY_F0]
    str xzr, [x19, #TY_F1]
    adrp x1, _kcc_type_bool@@PAGE
    add  x1, x1, _kcc_type_bool@@PAGEOFF
    str x19, [x1]
@| _kcc_types_init
@}

\paragraph{Character and Integer Type Singletons}

The next block allocates singletons for every standard integer type, from
\texttt{char} through \texttt{long long}, each in both signed and unsigned
variants.  The C17 standard treats plain \texttt{char}, \texttt{signed char},
and \texttt{unsigned char} as three distinct types (\stdref{6.2.5p15}); our
implementation maps plain \texttt{char} to \texttt{signed char}, following the
default sign convention on Apple ARM64 targets.  Each descriptor stores its
signedness in \texttt{TY\_F0} (1 for signed, 0 for unsigned) so that later
stages can select the correct conversion and promotion rules.

One file, three registers of thought: the LaTeX prose that teaches, the constants that define the layout, and the ARM64 that implements it — woven for a document, tangled into the compiler. This is the Type System chapter of kcc's own source.

How LDD built kcc

kcc, Literate Driven Development in practice.

kcc is not a demonstration bolted onto the method — it is what the method produced. Here is how each pillar of LDD solved a real problem in building a real compiler.

01

Understanding

A black box, read straight through

Every decision was written down before it was coded — in prose that must name the clause of the C Standard it obeys. The document records why; the tests record that; and when the two disagree, the disagreement is visible instead of latent.

Nothing is taken on faith. A compiler famous for being a black box — lexer, preprocessor, parser, type system — is here a narrative you can read straight through.

02

Complexity

Read the story, not the code

A compiler is a mesh of interlocking parts — lexer, preprocessor, parser, type system, IR, optimizer, register allocator, code generator, object writer — and the classic failure mode is that no one can hold the whole in mind. The literate web dissolves that: each concept is told as its own story, at its natural size, while the narrative keeps the whole in view.

More than once a defect spanned three of those layers at the same time. The way to it was to read the story, not to grep the code.

03

Speed

Weeks of work, landed in hours

Work that would occupy a team for weeks landed in hours: an optimizer with constant folding, dead-code and common-subexpression elimination, and the promotion of locals into registers; a full register allocator with a dedicated floating-point bank; the difficult tail corners of C17 — _Generic, correctly typed integer constants, volatile semantics, long double.

The AI moves through the literate structure — its machine-readable map of fragments, its reverse mapping from a line of generated assembly back to the prose that produced it — so each change stays local, and each local change stays testable.

1

person

~230

hours of sessions

42

working days

408

commits

Built by one person, using pure literate programming and Literate Driven Development. Estimated from the project's own commit history: roughly 230 hours of AI-paired terminal sessions, spread across 42 working days in under seven calendar weeks — for a self-hosting C compiler that has historically been the work of a team over years.

04

Cost

One $100 subscription, no team

A production C compiler was historically the work of a large, expensive team over years. Because generation is now nearly free, LDD spends the cheap thing — writing — to protect the expensive one — understanding. The whole of kcc was authored on a single $100/month Claude Code Max subscription, running Claude Opus 4.8 — no team, no tooling budget, no license fees.

And what you get back is not throwaway output: it is a legible, lasting source you can study, extend, and retarget — the book even ships a porting playbook for exactly that.

$100/mo

A single Claude Code Max subscription, running Claude Opus 4.8 — the entire budget for a self-hosting C compiler.

05

Craft

Reads like a book, runs like a compiler

kcc self-hosts to a byte-identical binary, passes its full suite, and ships with a user manual for the person who wants to use it and a porting playbook for the person who wants to extend it. It is documentation and program at once — and neither is free to drift from the other.

This is the ambition Knuth named: real, production-grade software that reads like a book and behaves like an engineering artifact. Correctness and beauty stop being a trade-off and become the same pursuit.

Nothing taken on faith

Verified three ways

Against the Standard

The prose cites the ISO C clause each decision obeys.

Against a reference compiler

Differential testing over a large corpus — SQLite, Lua, zlib and more as the oracle.

Against itself

It recompiles its own source to a byte-identical binary.

If LDD can write a C compiler, it can write your most complex, cutting-edge software projects.

kcc — A Formal C17 Compiler in ARM64 Assembly, Volume 1 of Literate Driven Development (book cover)