ARIA Bootstrapped: The Compiler Wrote Itself
Several weeks ago I published an argument. AI-optimized intermediate representations are the right abstraction for AI-authored code. Humans…
ARIA Bootstrapped: The Compiler Wrote Itself

Several weeks ago I published an argument. AI-optimized intermediate representations are the right abstraction for AI-authored code. Humans do not belong in the loop between the AI and the compiler. The representation should be designed for the only two entities that actually touch it.
That argument needed a proof. Here is the proof.
What we built
aria-clj is a Clojure implementation of the ARIA toolchain. It compiles ARIA-IR, an s-expression intermediate representation with explicit types, declared effects, and first-class intent annotations, to native binaries. It ships as a standalone JAR. You need Java. Nothing else.
The pipeline has four stages, all working.
Layer 1 takes natural language and produces ARIA-IR via Claude. You type “sort a list of integers.” You get a validated, type-checked ARIA program.
Layer 2 is the Clojure toolchain. Reader, parser, type checker. If the AI gets a type wrong or uses an operation that does not exist, the checker catches it before anything compiles.
Layer 3 is the backend. Three of them. ARIA-C produces C99 that gcc compiles to a native binary. ARIA-WAT produces WebAssembly Text format for WASI runtimes. ARIA-JVM produces JVM bytecode directly, no gcc required.
Layer 4 is intent verification. For each function with an intent annotation, the verifier generates a thin wrapper, compiles it, runs it with concrete inputs, captures the output, and asks the Claude API whether the observed behavior matches the declared intent. Not static analysis. Actual execution.
A function that claims to sort a list of integers and instead prints “Hello, world!” gets NOT_VERIFIED. Exit code 1.
The bootstrap
Arkaitz Mugica, the project’s first external contributor, built something that was not on the roadmap. ariac is an ARIA-IR compiler written in ARIA-IR itself. Not a monolith. Six modules: types, reader, parser, checker, codegen, main. Around 5200 lines total. The same pipeline as the Clojure implementation, expressed in the language it compiles.
The bootstrap chain:
ariac.aria [Clojure compiler] ariac-bootstrap (native binary)
ariac/ [ariac-bootstrap] ariac (native binary)
fibonacci [ariac] fib(10) = 55
The IR proved it could describe itself. The compiler compiled itself from its own six modules. The output was correct.
ariac also closed Issue #4 — the module import system that was labeled as a v1.0 feature. It shipped alongside the bootstrap:
(import "math.aria")
(call $math.gcd 48 18)
Path resolution is relative to the importing file. Circular imports are detected and rejected. Only exported symbols are visible to importers. The compiler resolves all modules and emits a single C file. ariac uses its own module system to compile itself.
What the IR found along the way
Writing 5200 lines of ARIA-IR to compile ARIA-IR is the most demanding test you can run on a language design. It found things the example programs never would.
Four bugs in the Clojure compiler itself surfaced only because ariac needed them fixed to compile. String literals were typed wrong. Struct field parsing was broken. A variable name prefix was not being stripped in codegen. Global variables were registered in the AST but never added to the type environment.
None of these showed up in fibonacci, bubble sort, or math demo. ariac found them all.
The most serious was a correctness bug in both the Clojure checker and the self-hosted checker. A function declared pure that mutated a global variable via set passed type checking without error. The C codegen then emitted __attribute__((const)) on that function. GCC, trusting the attribute, eliminated calls to it as dead code at -O2. The scope tracker stopped running. The program produced silently wrong output.
That is the kind of bug that production code finds years after deployment. ariac found it during compilation.
Then the checker went further. ariac now performs static pointer state analysis, detecting eight classes of memory errors at compile time: use-after-free, double-free, null dereference, memory leak, free of non-pointer, alias use-after-free, pointer arithmetic alias, and struct field dangling. The checker found and fixed real use-after-free bugs in ariac itself during development. The IR enforcing correctness on the compiler written in the IR.
Mandatory intent annotations are now enforced by the checker. Every function must declare what it does. If the AI omits an intent, compilation fails. The contract between the generator and the verifier is now structural, not optional.
Try it
curl -LO https://github.com/jhavera/aria-clj/releases/latest/download/aria-clj.jar
java -jar aria-clj.jar examples/fibonacci.aria --run
java -jar aria-clj.jar examples/fibonacci.aria --verify
The site is at aria-ir.org. The repo is at github.com/jhavera/aria-clj.
Build ariac from source:
# Stage 1: build ariac-bootstrap from the Clojure compiler
clojure -M:run aria-src/ariac-bootstrap.aria --emit-c -o /tmp/bootstrap.c
gcc -std=c99 -fwrapv -o ariac-bootstrap /tmp/bootstrap.c -lm
# Stage 2: build ariac from ariac-bootstrap
./ariac-bootstrap aria-src/ariac/main.aria --emit-c -o /tmp/ariac.c
gcc -std=c99 -fwrapv -o ariac /tmp/ariac.c -lm
# Use ariac
./ariac examples/fibonacci.aria --run
./ariac examples/import_demo/main.aria --run
The parentheses were always there
In June 2006, three weeks after returning from Baghdad, I wrote a blog post about discovering LISP. S-expressions. Trees all the way down. I was an IT Architect at IBM, trying to remember how to be excited about technology after a year thinking about survival. LISP felt alien. It also felt inevitable.
Twenty years later, ariac is 5200 lines of s-expressions that compile s-expressions to native code, organized as six modules that import each other through the module system they implement. The notation I stumbled onto in a post-deployment blog is the notation the compiler is written in. That is not a coincidence. It is the right choice. And now it compiles itself.
The AI composes. The machine performs. The representation holds.
메타데이터
- post_id
- bdb4253f515b
- slug
- aria-bootstrapped-the-compiler-wrote-itself-bdb4253f515b
- url
- https://medium.com/@jhavera/aria-bootstrapped-the-compiler-wrote-itself-bdb4253f515b
- canonical_url
- https://medium.com/@jhavera/aria-bootstrapped-the-compiler-wrote-itself-bdb4253f515b
- author_url
- https://medium.com/@jhavera
- status
- ok
- fetched_at
- 2026-06-09 15:37:30