1. Getting started
What this is for
Most of what anybody writes to check something is small — five lines to confirm a total, ten to see what a parser does with one input. And in most languages you cannot run five lines. You need a manifest, a build file, a dependency install, an entry point, and a runtime on the machine that will run it. So people stop checking, which is the actual cost.
One file is a program here. There is no manifest, no project layout, no entry point to declare and
nothing to configure. burxt run hello.bx produces a native executable of about 16 KB that links
nothing but libc — no runtime to ship, no VM to start.
And one command you have probably never had before: burxt review, which reads two versions of a file
and tells you whether the newer one promises less than the older one. That is further down this
page, because it is the reason the rest of the language looks the way it does.
Think of one button, not an assembly line
A microwave has one button. You do not configure a microwave.
A step closer
The compiler is written in Rust and emits native code through LLVM 18. You need both to build it; you need neither to run what it produces.
sudo apt install llvm-18-dev libpolly-18-dev libzstd-dev clang-18 # Debian/Ubuntu
export LLVM_SYS_181_PREFIX=/usr/lib/llvm-18
git clone https://github.com/andrecorugda/burxt && cd burxt
cargo install --path . # puts `burxt` on your PATH
No LLVM to hand? Open the repository in a Codespace — it builds itself on first start, extension included.
In code
let name: String = "world";
print("hello, " + name + "!");
$ burxt run hello.bx
hello, world!
That is the whole file. Two things in it are worth naming now, because they are the two things everybody notices in the first minute.
Types are written down. let name: String, not let name. A binding says what it is, so the type
a reader sees is the type you meant — and a mistake in it is a compile error here rather than a
surprise three functions away. Inside a function body Burxt will infer from an obvious right-hand
side; at a boundary anyone reads, it will not.
There is no main. The file is the program, top to bottom. A five-line calculation is five lines.
main is in fact a name the language reserves, precisely so that a function called main cannot
look like an entry point without being one.
The command that is not like other languages
Here is a function that will not let you overdraw an account:
function withdraw(balance: Decimal<2>, amount: Decimal<2>) -> Decimal<2>
requires amount > $0.00
requires amount <= balance
{
return balance - amount;
}
Now suppose something — a colleague in a hurry, an agent that could not satisfy the rule — removes the
second requires. The body still compiles. Every test still passes; in fact the tests pass more,
because whatever was failing was failing on purpose. In any other language you catch that by noticing
one deleted line in a diff at 5pm on a Friday.
$ burxt review before.bx after.bx
WEAKENED withdraw lost `requires amount <= balance`
1 weakened promise(s). A weakened contract is the one change that passes every test — the tests were failing BECAUSE of it.
$ echo $?
1
It exits non-zero, so it is a gate and not a report. Put it in CI and a promise cannot get quietly smaller.
The loop
Why it is built this way
burxt review works for one reason, and that reason is the design of the whole language: everything
that matters is in the signature. The scale of the money, the rounding rule, the preconditions, what
is private, what the function is allowed to reach. Nothing important hides in a body — so a tool that
reads only declarations can still tell you whether the program’s promises changed.
Every other decision in this guide is downstream of that one. Money carries its scale in the type
because a reviewer scans types. Effects are written rather than inferred because a written effect is a
promise and an inferred one is a fact nobody stated. Contracts sit on the signature rather than as
assert in the body because a body is not what anybody reads.
The 16 KB binary follows from the same discipline in a different direction: there is no runtime because there is nothing that needs one — no collector, no reflection, no boxing.
What it costs
Building the compiler needs LLVM 18, which is the largest single thing you have to install. Running what it produces needs nothing.
You write types at boundaries. let name: String, and every parameter and return. Inside a body
let x = 0; infers.
Burxt 1.0.0 is released, and what that means here is narrow and checkable: you can write a program, test it, debug it with a real debugger, depend on other people’s code with a lockfile that pins commits, and ship it to a machine with neither Rust nor LLVM installed. The standard library is 22 modules.
What is still missing is named rather than implied: no concurrency, no sockets, no wasm host yet.
Every gap, with its reason.
The editor extension has one trap, and it cost a full afternoon: it runs whichever burxt binary
it finds, and if you have both a --release and a debug build it prefers the newer. After
rebuilding, run Burxt: Restart Server from the command palette. An editor reporting an error the
terminal does not is almost always this.
When you reach for it
| Command | What it does |
|---|---|
burxt run x.bx |
Compile to native code and run it |
burxt build x.bx -o prog |
Compile and keep the binary |
burxt check x.bx |
Parse and typecheck only — no LLVM, no linker, fast |
burxt check x.bx --json |
The same, as JSON, for an editor or a script |
burxt review old.bx new.bx |
What changed about what it promises. Non-zero if anything got weaker |
burxt mcp-schema x.bx |
The MCP tool manifest, derived from the preconditions |
burxt lsp |
The language server, over stdio |
burxt emit-ir x.bx |
Print the LLVM IR |
burxt layout x.bx |
Print class sizes, alignments and field offsets |
Use -o unless you want the executable in your current directory. Arguments after the source file go
to the linker unchanged: burxt run pay.bx cside.o -lm. Every command is documented in the
reference.
In an editor:
python3 editors/vscode/pack.py
code --install-extension editors/vscode/burxt-0.1.4.vsix
Syntax highlighting, diagnostics as you type, hover, and a ▶ button (Ctrl+F5). It talks to
burxt lsp — the same compiler you run from the terminal, so the editor cannot disagree with the
build.
Examples
The whole program, and what it prints.
let name: String = "world";
print("hello, " + name + "!");
hello, world!
Five lines that check something, which is the case this language is shaped around. No wrapper, no entry point, no build file:
let price: Decimal<2> = $19.99;
let quantity: Int = 3;
print(price * quantity);
59.97
And the refusal you will meet first, because it is the one an agent trips over. Adding a rate to a price:
let price: Decimal<2> = $19.99;
let rate: Decimal<4> = 8.25%;
print(price + rate);
error: cannot + Decimal<2> and Decimal<4>: scales must match. Burxt does not silently rescale money.
--> hello.bx:3:7
|
3 | print(price + rate);
| ^^^^^^^^^^^^
That message is the subject of the next page.
Next
Numbers and money — where being wrong costs, and the first thing the compiler will refuse to let you do.