Skip to main content

Verum

A complete systems language. Proof-grade when you need it.

Sum types and exhaustive matching, protocols and generics, structured async, memory safety without a garbage collector, and a batteries-included standard library built on nothing but syscalls — that is the everyday language. Then, in the same file, the ceiling rises: refinement types when invariants matter, contracts when correctness pays, machine-checked proofs when it is load-bearing. Each layer costs nothing until you ask for it.

Verum

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.

All six platforms and checksums →

terminal
# 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

SQL engine (sqlite, in Verum)postgresmysqlredisjsonprotobufencodingcompressstorage

Network

http/1.1 · 2 · 3tls 1.3quicwebsocketdnsurl · uri-templateproxyweft framework

Security

x509aead · hpke · kdfpost-quantumzero-knowledgejwt · oidc · webauthnsigstore · tufconstant-time subtle

Compute

tensors + GPU loweringautodiffsimdmathrandomhashsearch

Runtime

asyncsync · concurrencymem · arenastimeio · fssignaltracing · metrics

Surface

terminal UI (widgets, layout)shell DSLcli argstext · fmtconfigmoneyid

Browse the standard library →

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.

0.93 ns

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.

1.4 M

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.

0

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.

VerumRustGoC / C++
Memory safetyGenerational references, three tiers — no lifetime annotations in typesOwnership + borrow checker, lifetimes in signaturesGarbage collectorManual
Formal verificationIn the language: refinements → SMT → kernel-checked certificates, one dialExternal tools (Kani, Prusti, Creusot)External tools (Frama-C, CBMC)
ConcurrencyStructured async in the stdlib; select, channels, supervisionLibrary executors (tokio, async-std)Goroutines on a managed runtimeThreads + libraries
Standard librarySQL engine, TLS 1.3/QUIC, terminal UI, tensors — in the boxLean core, rich crates.io ecosystemBroad stdlibMinimal, per-platform
Development loopOne binary: instant interpreter and native AOT on the same bytecodeCompile-firstFast compileCompile-first
Embedded / no-libcFirst-class: no runtime, raw syscalls, bare-metal targetsno_std, matureNeeds the runtimeFirst-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.