What is ARIA
An AI-optimized intermediate representation for the prompt-to-binary pipeline.
The Problem
AI generates Python. A compiler compiles Python. No human reads the Python. So why is the Python there?
Today's AI code generation pipeline produces code in languages designed for human ergonomics. Tab completion. Readable variable names. Syntactic sugar. These features exist for an audience that is increasingly absent from the pipeline: the human author.
The Insight
The Goldilocks zone between natural language (too ambiguous for compilers) and machine code (too low-level for AI) is an AI-optimized intermediate representation.
Not LLVM IR. That was designed for compiling human languages. Something designed from first principles for the AI-author, compiler-consumer pipeline. A representation where the AI can express intent, the compiler can verify correctness, and no one pretends a human needs to read it.
ARIA-IR Design Principles
S-expression syntax
Zero ambiguity, no precedence rules. Every structure is explicitly delimited. The syntax is the AST.
Type-suffixed operations
add.i32, mul.f64. No implicit coercion. Every operation declares its types.
First-class intent annotations
(intent "...") nodes let the AI state why, not just what. Preserved through compilation for verification.
Effect declarations
pure, mem, io, div. Verified at compile time. A pure function cannot perform I/O. The type checker enforces this.
SSA form
%immutable bindings, $mutable locals with explicit set. No hidden reassignment. Every data flow is visible.
The Pipeline
Layer 4 is not planned — it is built. The --verify flag compiles each function with concrete test inputs, runs the binary, captures the output, and asks the Claude API whether the observed behavior matches the declared intent.
This is dynamic verification, not static analysis. The verifier does not read the code. It runs it.
clojure -M:run examples/fibonacci.aria --verify
Each function with an (intent "...") annotation receives a VERIFIED or NOT_VERIFIED verdict. If any function fails, the process exits with code 1. The flag is orthogonal to backend selection — verify and compile in a single pass.
Generics Without Generics
ARIA has no parametric polymorphism. No templates. No trait system. It does not need one.
A comptime block executes at compile time. The AI generates a function that takes a type name as a string and prints a type-specialized ARIA function. The compiler runs it, captures the output, splices the generated functions back into the module, and compiles them. The result is monomorphized code with zero runtime overhead.
;; The AI generates this once
(comptime
(func $gen_max (param $T (ptr i8)) (effects io)
(print "(func $max_%s (param $a %s) (param $b %s) (result %s) (effects pure)\n" $T $T $T $T)
(print " (if (gt.%s $a $b) (then (return $a)) (else (return $b))))\n" $T))
(func $main (result i32) (effects io)
(call $gen_max "i32")
(call $gen_max "f64")
(return 0)))
This is the pipeline doing its job. The AI writes a comptime generator once. The compiler produces $max_i32 and $max_f64 as fully specialized functions. No generics in the IR. No type erasure. No runtime dispatch. The two-pass model handles it: compile the comptime block via the C backend, execute it, parse the output as ARIA forms, splice them in, compile the whole module.
This pattern scales. Identity functions, clamp functions, arithmetic wrappers, lookup tables. Any function shape the AI can describe as a printf template becomes a family of type-specialized implementations. The IR stays simple. The compiler stays simple. The output is the same code a human would write by hand for each type.
Why Not Just Use Clojure as the Target?
This is the obvious question. Clojure is s-expressions. ARIA-IR is s-expressions. Why not skip the IR and have the AI generate Clojure directly?
Because Clojure is still designed for humans. Namespaces, macros, lazy sequences, ergonomic abstractions. These features make Clojure productive for human authors. They add ambiguity and complexity for AI authors. ARIA-IR keeps the syntax but strips the ergonomics, replacing them with what the AI-to-machine pipeline actually needs: explicit types, declared effects, and verifiable intent.
Why Implement the Toolchain in Clojure?
The structural DNA argument. Parsing s-expressions in a language that is s-expressions. The parser collapses. The Clojure reader does most of the work. An ARIA-IR file is something Clojure can practically read natively. This is not a coincidence. It is the right choice.
The toolchain does not fight the representation. It is the representation. A Lisp compiler for a Lisp IR. The tool and the material are the same substance.