A language for the age of agents
“Heroes”
Decades of programming-language history, condensed into fewer than 16K tokens.
It reads like Python and has all the power of C. Many of the mistakes LLMs make, the AI models that write code, simply don’t compile here. No braces, no semicolons. No interpreter, no virtual machine. No null in your own types, no exceptions. No garbage collector, no heavy runtime. Mature enough to compile its own compiler. Small enough to fit in a prompt. What you write becomes a standalone executable.
variant Token
number
value: i64
word
text: str
plus
times
open
close
# What a token is called in a message.
function name_of(t: Token) -> str
return match t
.number _ => "a number"
.word _ => "a word"
.plus => "`+`"
.times => "`*`"
.open => "`(`"
.close => "`)`"
leave a case out and it does not compile · read the example →
- 16K tokens: the specification’s ceiling The specification describes the whole language in about seven pages. A token is a piece of text a model reads or generates. A short specification leaves room in the prompt for your program. the specification → why it is designed this way → common questions →
- 0 exceptions, garbage collector, null in your own types The code shows where a value may be missing or an operation may fail. Memory is freed automatically, without a garbage collector, a system that looks for unused data and can pause your program. how to handle errors →
- 1 command for all the tools One executable builds, runs, tests, formats and checks your code. It is written in Heroes. it compiles itself →
The count behind the 16K is the model’s own, taken through Claude’s token-counting API and recorded with the model that produced it; a test holds the specification under that ceiling on every commit.
The whole language, in one file: curl -L heroes-lang.org/spec.md
The compiler reports mistakes
A model writes totl instead of total. In languages that let an assignment declare a variable, a typo like this can create a new variable. Heroes uses different syntax for declaring and updating variables: the compiler rejects the unknown name and suggests a correction:
error[unknown_name]: nothing named `totl` is in scope — did you mean `total`?
at tests/golden/check/typo-not-a-new-binding.hero:10:9
|
10 | totl @ total + x #~ unknown_name
| ^^^^
fix (certain): rename to `total`
The compiler also catches swapped labelled arguments, missing cases and keywords from other languages. Each message identifies the problem and its location in the code. When possible, it suggests a fix; fixes marked certain can be applied automatically. More error examples →
Heroes uses C libraries
Heroes uses C libraries for maths, files, sockets, databases and graphics. A few lines declare the library functions your program needs. Clang, the C compiler, checks these declarations against the library’s header, the file that describes its functions and types. If the types do not match, compilation stops.
extern "math.h" link "m"
function sqrt(x: f64) -> f64
function pow(base: f64, exponent: f64) -> f64
function floor(x: f64) -> f64
The examples include programs that use a database, call a graphics library and send a web request. Their pages also show recorded output where available. Examples using C libraries →
The thesis
A language designed so that every plausible LLM mistake is a compile error will produce working programs in fewer total tokens than a conventional language, even if each program costs more tokens to write.
One part of the thesis has been tested. heroes mutate introduces one realistic mistake at a time into working programs and counts how many the compiler catches. It repeats the run with the Heroes-specific checks switched off. The rules that require an argument’s name and refuse a reused one carry the difference: with them off, those mistakes compile. The same table names the mistakes no check catches.
The other part is the total number of tokens a working program costs, corrections included, with the Heroes-specific checks on and with them off. The instrument that measures it has run once, on tasks written and sealed before the run, under a prediction published first. With the Heroes-specific checks and without them, the models solved the same tasks within three tries: for the experiment, that result is called inconclusive. The figures are stated at the publication gate. A comparison with other languages comes after it. What is measured → The available results →
Run it · speed of life ·
Heroes is in beta: the language still changes. The version you build below is heroes 0.5.0. Until 1.0.0, a change in the middle number can change the language itself, and a change in the last number never does. A program you write today may need small edits later.
$ git clone https://github.com/heroes-lang/heroes
$ cd heroes
$ clang -I runtime seed/heroes.c runtime/runtime.c -o heroes
$ ./heroes run examples/gallery/03-fallible.hero
read 42
failed: not_a_digit (expected 0-9)
20
The third line builds the compiler from a single C file. It takes under
four seconds on a MacBook Air, the machine every measurement here comes
from. The Heroes compiler generated that C file, so clang is all you need. The line saying
failed is the example refusing a character it cannot read.
The getting started guide → · the language, one idea at a time →
Who is building it
One person and an AI assistant. The person had never seriously written a compiler before this one, but had studied the history of programming languages and their compilers, and the book below came out of that study. The assistant follows rules stored in the repository, the project’s archive. A panel of five judges reviews every language change; four can veto it. The author approves or rejects each decision. Who wrote this → · how changes are reviewed →