Zero to running in one binary
The verum binary is the whole toolchain — compiler, interpreter, LSP server, debugger, REPL, Playbook TUI, formatter, test runner. Prebuilt for six platforms, rebuilt daily. No runtime to install, no package manager required before your first program.
# Grab today's build (macOS arm64 shown; six triples published daily)
curl -LO https://github.com/verum-lang/verum/releases/download/dev/verum-dev-aarch64-apple-darwin.tar.gz
tar xzf verum-dev-aarch64-apple-darwin.tar.gz
sudo install -m755 verum /usr/local/bin/verum
# Write a program
echo 'fn main() { print("hello, verum"); }' > hello.vr
# Run it two ways — same bytecode, same semantics
verum run hello.vr # Tier 0: interpreter, instant start
verum build hello.vr # Tier 1: native AOT binary
The language itself
Before any proof enters the picture, Verum is a full modern systems language — the code below is its everyday register, and all of it runs identically under the instant-start interpreter and the native AOT compiler.
Types that say what they mean
The standard vocabulary is semantic, not implementation-flavoured: List, Map, Set, Text, Heap, Shared — names that state intent and leave representation to the compiler. Errors travel as values through Result and Maybe with ? propagation; interpolated strings and newtypes keep the everyday code short and typed.
type OrderId is (Int); // newtype — not just an Int
fn total(orders: &Map<OrderId, Order>) -> Result<Money, PriceError> {
let mut sum = Money.zero();
for (_, order) in orders.iter() {
sum = sum.add(order.price()?); // ? propagates the error
}
Ok(sum)
}
fn receipt(id: OrderId, m: Money) -> Text {
f"order {id}: {m}" // typed interpolation
}
Model the domain, match on it
Sum types carry exactly the states your domain has — no nullable placeholders, no sentinel values. match is exhaustive: add a variant and every non-total match in the codebase becomes a compile error, with guards for the cases that need a condition.
type Shape is
| Circle(Float)
| Rectangle(Float, Float)
| Square(Float);
fn describe(s: Shape) -> Text {
match s {
Circle(_) => "a circle".clone(),
Rectangle(w, h) if w == h => "a square in disguise".clone(),
Rectangle(_, _) => "a rectangle".clone(),
Square(_) => "a square".clone(),
}
}
// Add a variant to Shape and this match stops compiling
// until you say what it means. That is the point.
Protocols, not hierarchies
Behaviour is a protocol; any type can implement it, including types you did not write. Generics take protocol bounds, and function types go up to rank-2 polymorphism — fn<R>(Reducer<B, R>) -> Reducer<A, R> is an ordinary type here, which is what makes transducer-style libraries expressible without macros.
type Drawable is protocol {
fn draw(&self) -> Text;
fn area(&self) -> Float;
};
implement Drawable for Circle {
fn draw(&self) -> Text { f"Circle(r={self.radius})" }
fn area(&self) -> Float { 3.14159 * self.radius * self.radius }
}
fn report<S: Drawable>(s: &S) {
print(f"{s.draw()} covers {s.area()}");
}
Concurrency that composes
Async functions suspend at .await and cost nothing until spawned. Bounded channels give you backpressure by construction; select races sources; structured spawning keeps every task owned by a scope that joins it — no orphaned work, no ambient executor state.
async fn producer(tx: Sender<Int>, n: Int) {
let mut i = 0;
while i < n {
tx.send(i).await; // blocks when the buffer is full:
i = i + 1; // backpressure is automatic
}
}
fn main() {
let (tx, rx): (Sender<Int>, Receiver<Int>) = bounded(4);
let p = spawn(producer(tx, 100));
let c = spawn(consume(rx));
p.join();
c.join();
}
What Verum gives you
Six engineering decisions that change how you write, verify, and ship systems code — without committing you to machinery you did not ask for.
Batteries included, dependencies zero
The standard library is written in Verum on the no-libc substrate and ships inside the toolchain: an embedded SQL engine, PostgreSQL / MySQL / Redis wire clients, HTTP with TLS 1.3 and QUIC, a full terminal-UI framework, a shell DSL, X.509 / post-quantum / zero-knowledge crypto, tensors with GPU lowering, reverse-mode autodiff. No package manager required before your first real program.
mount core.database.sqlite.native.l7_api.{
Database, DbError, open_readwrite};
fn example() -> Result<(), DbError> {
let mut db: Database = open_readwrite()?;
db.execute(&"CREATE TABLE users (id INTEGER PRIMARY KEY, \
name TEXT NOT NULL)".into())?;
db.execute(&"INSERT INTO users (id, name) \
VALUES (1, 'alice'), (2, 'bob')".into())?;
let rows = db.query_all(&"SELECT id, name FROM users \
ORDER BY id".into())?;
for row in rows.iter() { print(f"{row[1].as_text()}"); }
Ok(())
}
// A SQL engine written in Verum, embedded in the toolchain.
Three-tier memory safety
A safe reference, a compiler-proven safe reference, and an unsafe reference — all the same type family, chosen per use site. The default tier carries a per-access generation check; escape analysis routinely promotes hot-path references to the proven-safe tier with zero residual cost. The unsafe tier is available where you need it (FFI, custom allocators) — and visible to the audit when you use it.
fn sum_ages(users: &List<User>) -> Int {
let mut total = 0;
for u in users.iter() { // &u: &User — checked default
let age: &checked Int = &checked u.age;
total += *age; // 0 ns — compiler proved safe
}
total
}
// $ verum analyze --escape
// sum_ages: most references promoted to &checked
// safe by default, zero-cost where provable
No hidden runtime
No language runtime, no hidden allocator, no hidden exception machinery. Tier-0 binaries talk to the OS through the platform-required boundary only — direct syscalls on Linux/FreeBSD, libSystem on macOS, kernel32+ntdll on Windows, bare-metal on embedded. The interpreter and the AOT compiler share the same bytecode — instant startup for development, native-speed binary for production, identical semantics across both.
// Embedded build — no malloc, no libc, no stdio.
@no_std
@target("thumbv7em-none-eabihf")
module firmware.uart;
mount sys.mmio;
public fn write_byte(b: u8)
using [UartRegisters]
{
while !UartRegisters.tx_empty() {}
UartRegisters.tx_data.write(b);
}
// Compiles to a microcontroller binary. Same language as
// the verified theorem corpus.
One context system unifies DI and meta
The same using [...] clause drives runtime dependency injection (Database, Logger, Clock, FileSystem) and compile-time metaprogramming (TypeInfo, AstAccess, CodeSearch, Schema). One lookup discipline, no hidden globals, no thread-locals, no ambient state. Application developers see a clean DI system; metaprogrammers see a stage-aware reflection layer; both are the same grammar.
// Runtime — caller provides Database and Logger.
fn handle(req: &Request) -> Response
using [Database, Logger]
{
Logger.info(f"{req.method} {req.path}");
Database.find_user(req.auth)
.map(|u| Response.ok(&u))
.unwrap_or_else(|| Response.unauthorised())
}
// Compile time — the compiler provides TypeInfo.
meta fn field_count<T>() -> Int using [TypeInfo] {
TypeInfo.fields_of<T>().len()
}
Architecture is a type
Architectural intent — what a module is allowed to do, what it depends on, what invariants its boundaries preserve, what stage of maturity it is at — is a typed annotation the compiler enforces on every build. Architectural drift becomes a compile error with a stable diagnostic code, not a code-review gap. The same discipline scales from a single embedded driver to a federation of services.
@arch_module(
lifecycle: Lifecycle.Definition,
exposes: [Capability.Read(Database("ledger")),
Capability.Network(Grpc, Outbound)],
requires: [Capability.Read(Logger)],
preserves: [BoundaryInvariant.AllOrNothing,
BoundaryInvariant.AuthenticatedFirst],
composes_with: ["payment.fraud", "payment.audit"],
)
module payment.settlement;
// Capability escalation, boundary violation, lifecycle
// regression — each is a compile-time diagnostic with a
// stable code. Claiming Theorem status without a closed
// proof triple is itself an error the compiler catches.
Correctness is a dial
One spectrum from runtime assertions to kernel-checked certificates, indexed so every step is at least as strong as the previous. Refinements erase at runtime; proofs are per function, per module, or per project — never required, never silently taxing the code that does not ask. The kernel re-checks every certificate from every solver, and two independent kernels must agree before an audit passes.
// Same body, different tiers.
type NonNeg is Int { self >= 0 };
@verify(runtime) // assertion at runtime
fn abs_r(x: Int) -> NonNeg { if x >= 0 { x } else { -x } }
@verify(formal) // SMT-proved at compile time
fn abs_f(x: Int) -> NonNeg { if x >= 0 { x } else { -x } }
@verify(certified) // certificate exported, kernel re-checks
fn abs_c(x: Int) -> NonNeg { if x >= 0 { x } else { -x } }
// Promote the tier when the function lands in a load-bearing
// role. Demote when the role changes back. Same source.
Same source, four levels of correctness
Plain code, refinement type, explicit context, formal proof — each level is one annotation apart. You stay in the same file, the same syntax, the same toolchain.
// Plain systems code — no annotations needed.
fn parse_packet(buf: &Bytes) -> Result<Packet, Error> {
let header = read_header(buf)?;
if header.magic != MAGIC { return Err(Error.BadMagic); }
Ok(Packet { header, payload: buf.slice(HEADER_LEN..) })
}
// Add a refinement when an invariant matters.
type Port is Int { 1 <= self && self <= 65535 };
// Add a context when a dependency is explicit.
async fn serve(port: Port) -> Result<(), Error>
using [Logger]
{
Logger.info(f"listening on :{port}");
accept_loop(port).await
}
// Add a proof when correctness is load-bearing.
@verify(formal)
fn binary_search(xs: &List<Int> { self.is_sorted() },
target: Int) -> Maybe<Int>
where ensures (result is Some(i) => xs[i] == target)
{ /* body */ }
// Each level is a single attribute apart. Pay for what you use.
The standard library ships whole
Fifty-plus top-level modules, written in Verum on the no-libc substrate and baked into the toolchain binary. Every name below is a directory in core/ today — not a roadmap.
Data
Network
Security
Compute
Runtime
Surface
One binary, the whole workshop
Everything below ships inside the same verum executable you installed above — there is no companion toolchain to version-match.
verum run — Tier 0
The interpreter. Instant start on the same bytecode the AOT path compiles — your development loop is edit → run, no build step, identical semantics.
verum build — Tier 1
Native AOT through LLVM: one self-contained binary holding the native-C parity bar (1×), speaking syscalls (or libSystem / kernel32) directly. Cross-target flags included.
Language server
Completion, diagnostics, go-to-definition, incremental lossless parsing — the same binary serves your editor over LSP. First-party VS Code extension.
Step debugger
A Debug Adapter Protocol server in the box: breakpoints, stepping, variable inspection — wired to the interpreter tier for zero-rebuild debug sessions.
REPL & Playbook TUI
An interactive REPL for quick exploration, and Playbook — a terminal notebook for literate, replayable sessions against real code.
Tests, benches, audits
A spec-test runner with tiered conformance levels, criterion benchmarks, escape-analysis reports, and architecture audit gates that aggregate to one verdict.
By the numbers
Performance claims here are either measured on benchmarks that live in the repository or held by contract tests that fail the build on regression — never a slide-deck figure.
Memory-safety check
Measured cost of the default-tier reference check on the production benchmark — against a 15 ns budget. Escape analysis promotes most hot-path accesses to exactly zero.
Lines parsed per second
Front-end throughput, held by a compile-speed contract test in the repository — a regression fails the build, not a quarterly report.
Native-C runtime
Parity with C is the bar, not the ceiling — whole-program optimization aims beyond it. Interpreter startup is effectively instant, and both paths execute the same bytecode with identical semantics.
libc dependencies
Linux, FreeBSD and embedded builds speak raw syscalls; macOS uses libSystem and Windows kernel32+ntdll — the platform-required boundary and nothing else.
Who Verum is for
A single language across the full systems-engineering spectrum. Each audience gets the surface they need; the layers below are invisible until you ask for them.
For embedded developers
No runtime, no libc, no allocator. Direct hardware access through typed MMIO registers. Bare-metal targets across ARM Cortex-M, RISC-V, Xtensa. Same language as the desktop AOT path; only the toolchain target changes.
For systems programmers
Memory safety without garbage collection. Three reference tiers cover the safe / proven-safe / unsafe spectrum. Structured concurrency with cancellation. AOT compilation to native binaries that run at near-C speeds.
For application developers
A semantically honest standard library — List / Map / Text / Heap / Shared, no implementation-leaking names. Async with explicit join and select. Database, HTTP, TLS and QUIC stacks in the box. One context system for dependency injection.
For correctness engineers
Refinement types in the type system. SMT integration with capability-based routing across multiple solvers. Pre/post conditions, loop invariants, decreases clauses. Counterexample extraction with delta-debugging minimisation.
For working mathematicians
Dependent types, identity types, cubical paths. A trusted base small enough to read in one sitting. Two independent algorithmic kernels with continuous differential testing. Proof export to Lean, Coq, Dedukti, Metamath, Isabelle.
For architects and auditors
Architectural intent — capability discipline, boundary invariants, lifecycle maturity, foundation profile — is a typed annotation checked on every build. Every artefact carries an explicit lifecycle status; promoting and demoting are deliberate, audited actions.
For data & ML engineers
Tensors with GPU lowering (PTX, Metal, SPIR-V), reverse-mode autodiff, and SIMD in the standard library. An embedded SQL engine plus PostgreSQL, MySQL and Redis wire clients for the data plumbing around the model.
For security engineers
X.509, TLS 1.3, AEAD/HPKE/KDF suites, post-quantum and zero-knowledge primitives, JWT/OIDC/WebAuthn, sigstore and TUF — with a constant-time subtle module and capability-typed boundaries the compiler enforces.
Side by side
Each of these languages is excellent at what it optimises for. This table is where Verum sits — the column to read is the one whose trade-offs match your problem.
| Verum | Rust | Go | C / C++ | |
|---|---|---|---|---|
| Memory safety | Generational references, three tiers — no lifetime annotations in types | Ownership + borrow checker, lifetimes in signatures | Garbage collector | Manual |
| Formal verification | In the language: refinements → SMT → kernel-checked certificates, one dial | External tools (Kani, Prusti, Creusot) | — | External tools (Frama-C, CBMC) |
| Concurrency | Structured async in the stdlib; select, channels, supervision | Library executors (tokio, async-std) | Goroutines on a managed runtime | Threads + libraries |
| Standard library | SQL engine, TLS 1.3/QUIC, terminal UI, tensors — in the box | Lean core, rich crates.io ecosystem | Broad stdlib | Minimal, per-platform |
| Development loop | One binary: instant interpreter and native AOT on the same bytecode | Compile-first | Fast compile | Compile-first |
| Embedded / no-libc | First-class: no runtime, raw syscalls, bare-metal targets | no_std, mature | Needs the runtime | First-class |
Start where you are. Climb when you need to.
Download a prebuilt verum binary — rebuilt daily for Linux, macOS, and Windows. Write ordinary code with an extraordinary standard library behind it. Add a refinement when it pays, a contract when it earns its keep, a proof when it is load-bearing — and let the compiler hold every invariant you decide is one.
