Getting Started
A 60-second tour of installing Resilient, running your first program, and picking the right backend for your workload.
Table of contents
Try without installing
The fastest way to see Resilient run is the in-browser 🛝 playground — a WASM build of the compiler, no install required. Edit, run, and share examples directly from your browser.
Install
The shipped CLI is rz. Three install paths, pick whichever
matches your setup:
One-liner — downloads the latest pre-built binary into ~/.rz/bin/rz:
curl -fsSL https://raw.githubusercontent.com/EricSpencer00/Resilient/main/scripts/install.sh | bash
# Then put ~/.rz/bin on $PATH (the script prints the line for your shell).
From source via cargo install — if you have Rust installed:
git clone https://github.com/EricSpencer00/Resilient.git
cd Resilient
cargo install --path resilient
# `rz` lands in ~/.cargo/bin/rz
From source via cargo build — typical contributor workflow:
git clone https://github.com/EricSpencer00/Resilient.git
cd Resilient
cargo build --release --manifest-path resilient/Cargo.toml
# Binary lands at: resilient/target/release/rz
There are four feature configs depending on what you need:
| Build | Adds | Use when |
|---|---|---|
| default | interpreter + bytecode VM | Day-to-day development |
--features z3 |
Z3-backed contract proofs | You have hard requires/ensures clauses |
--features lsp |
Language Server Protocol | Editor integration (red squiggles) |
--features jit |
Cranelift JIT | Hot-loop / long-running workloads |
You can stack them with cargo install:
cargo install --path resilient --features "z3 lsp jit".
Hello, world
// hello.rz — Resilient source extension is .rz
println("Hello, Resilient!");
Run it:
rz hello.rz
# → Hello, Resilient!
A real program
Two functions, a contract, a live block, and an assert. Save
as safe_div.rz:
fn safe_divide(int a, int b)
requires b != 0
ensures result * b == a
{
return a / b;
}
fn main() {
live {
let r = safe_divide(100, 5);
println("100 / 5 = " + r);
}
assert(safe_divide(50, 5) == 10, "math is broken");
}
main();
Note the divisor in the live block is 5, not 7 — the ensures
result * b == a contract is exact integer equality, so the example
needs a divisor that divides evenly. (Try changing it to 7 and
running again: the live block detects the contract violation and
retries up to 3 times before propagating the error. That’s the
self-healing path in action — but the contract is wrong for the
inputs, so retry can’t save it.)
Run normally (interpreter):
rz safe_div.rz
# 100 / 5 = 20
Run with the audit pass to see what the verifier proved at compile time vs left as runtime checks:
rz --audit safe_div.rz
With --features z3, the b != 0 precondition becomes a
discharged proof obligation rather than a runtime check on
every call.
Mission-critical example projects
Reading the syntax page is one thing — seeing the language used end-to-end on the kind of system it was designed for is another. The companion repo EricSpencer00/Resilient-examples contains six full mission-critical demos:
| # | Project | Headline features |
|---|---|---|
| 01 | pacemaker | live invariant, recovers_to, contract-checked decision logic |
| 02 | infusion-pump | actor always:, cumulative-dose ceiling, parse_int Result chain |
| 03 | abs-brake-controller | forall i in lo..hi, saturating clamp, per-wheel ensures |
| 04 | traffic-light-interlock | cluster_invariant proves never-both-green |
| 05 | reactor-coolant-monitor | actor envelope [0, 250] kPa, live over a sensor stream |
| 06 | can-bus-parser | bytes literals, Result chain, match arm guards |
Each project has its own README documenting the safety property
under proof, the language features it exercises, and any
compiler limitations. Run ./run_all.sh from that repo to diff
every program against its golden output.
Pick a backend
Resilient ships three execution backends. All accept the same source — pick based on workload shape:
# Tree walker — fast to start, slow per-instruction.
# Best for one-shot scripts and during dev/test.
rz prog.rz
# Bytecode VM — ~12× faster than the tree walker on fib(25).
# Best for medium workloads where you want fast startup AND
# decent throughput.
rz --vm prog.rz
# Cranelift JIT — ~12× faster than the VM. Compile time is
# real, so use this for hot loops and long-running programs
# where compile cost amortizes.
cargo install --path resilient --features jit # one-time
rz --jit prog.rz
See the performance page for the actual numbers and the JIT’s current limitations (no closures/structs/while loops yet — interp/VM accept all of those).
Use cases
Embedded / safety-critical
This is what Resilient was built for. The sibling
resilient-runtime crate is #![no_std]-friendly
and cross-compiles to thumbv7em-none-eabihf (Cortex-M4F class
MCU). The Value enum carries Int, Bool, and (with
--features alloc) Float, String. The host build uses the
full interpreter + VM; the embedded build uses just the runtime
value layer + ops.
The live { } block is the headline feature for this
target — when a sensor read returns a corrupt frame, an I2C
transaction times out, or a divide-by-zero would crash, the
runtime restores the block’s state and re-runs it instead of
panicking.
Verified utilities
Use the contract layer (requires / ensures) for code where
“it works on the inputs we tested” isn’t good enough. Z3 backs
the verifier (--features z3); proofs that succeed don’t emit
runtime checks. For compliance / certification:
--emit-certificate ./certs prog.rz writes one SMT-LIB2 file
per discharged obligation, each independently re-verifiable
under any compatible solver.
rz --emit-certificate ./certs resilient/examples/cert_demo.rz # binary built with --features z3
z3 -smt2 ./certs/ident_round__decl__0.smt2
# unsat ← the proof: negation is unsatisfiable, so the original holds
Bytecode-VM scripting
If you don’t need verification or live-block recovery and just want a fast, simple scripting language, the bytecode VM is competitive with Python on tight numeric loops while giving you a real type system and contracts when you want them.
JIT hot loops
The Cranelift JIT (Phases B–H) compiles arithmetic + control
flow + recursion + function calls + let bindings to native
code. On fib(25) it’s within ~1.4× of native Rust. For
loop-heavy or recursion-heavy workloads, this is the right
backend.
What the JIT doesn’t yet compile: reassignment (x = x + 1),
while loops, closures, structs, arrays, live { } blocks.
Use the VM for those (it accepts all of them) until the
relevant JIT phase ships.
REPL
rz
> let x = 5;
> x + 10
15
> :examples # show a few canned examples
> :exit
The REPL also accepts :typecheck to toggle static type
checking.
Editor integration
Run the LSP server (built with --features lsp):
rz --lsp
For Neovim with nvim-lspconfig, see
LSP.md
for the config snippet. VS Code needs a thin extension that
points at the binary with --lsp.
The server publishes did_open + did_change diagnostics
plus three cursor-aware features:
- Hover — shows the type of any literal under the cursor
(
int,float,string,bool). - Go-to-definition — jumps from a call site to the top-level function or struct declaration.
- Completion — offers all built-in functions (alphabetical) followed by every top-level declaration in the current file.
See the LSP guide for editor-specific setup.
Where next?
- Design Philosophy — why the language looks the way it does
- Syntax Reference — the full grammar in one page
- Performance — the bench numbers and methodology
- Editor Integration (LSP) — hover, completion, and go-to-definition
- no_std Runtime — embedding on a Cortex-M