Quickstart: from git clone to a signed bench

Ten numbered steps. Each one is a real command with its real captured output. If any step does not behave like this on your machine, that's a bug.

This guide assumes Apple Silicon macOS (the primary target). For other hosts, see backends.md.


1. Clone


git clone https://github.com/zemo-g/rail
cd rail

You should now have a rail_native binary at the repo root — it's a ~1 MB ARM64 Mach-O checked into the repo. That's the seed compiler. There is no ./configure, no make, no cargo build.


file rail_native

rail_native: Mach-O 64-bit executable arm64

2. Run hello, world


./rail_native run examples/hello.rail

Compiling examples/hello.rail (244 chars)...
  as: OK
  ld: OK
hello, rail
3628800
42

run compiles to /tmp/rail_out and then executes it. The two OK lines are the assembler and linker; the three lines below are the program output ("hello, rail", factorial 10, double 21).

3. Inspect the program


cat examples/hello.rail

-- hello.rail — first Rail program (compiles natively)

double x = x * 2
factorial n = if n <= 1 then 1 else n * factorial (n - 1)

main =
  let _ = print "hello, rail"
  let _ = print (factorial 10)
  let _ = print (double 21)
  0

Ten lines including the comment. Functions are name args = body. main is the entry point; its return value is the process exit code.

4. Run the test suite


./rail_native test

... (long test log) ...
140/140 tests passed

The test suite covers parser, codegen, type inference, the runtime allocator, and the standard library. The count fluctuates a little if concurrent sessions race on /tmp/rail_out. 140 is the canonical green count — re-run if you see a lower number.

5. Self-compile


./rail_native self

The compiler compiles itself to /tmp/rail_self. On a clean checkout the first cycle may differ — the seed's shipped runtime asm doesn't always match what its own source emits. Install gen1 and re-run to confirm convergence at gen2:


cp /tmp/rail_self ./rail_native
./rail_native self
cmp rail_native /tmp/rail_self && echo "byte-identical"

byte-identical

This is the fixed-point property: the compiler's output is its own input. The bootstrap is a 2-cycle limit cycle — gen2 == gen3 == gen4 byte-identically. If cmp still differs after 3 cycles, codegen is non-deterministic and wants investigation. See notes/bootstrap_convergence_audit_2026-05-13.md.

6. Compile a real example


./rail_native run examples/quicksort.rail

Compiling examples/quicksort.rail (911 chars)...
  as: OK
  ld: OK
Input:
3 6 1 8 2 9 4 7 5
Sorted:
1 2 3 4 5 6 7 8 9

Larger list:
2 5 11 17 28 33 42 50 64 79 88 93

The source is 36 lines including comments. Cross-reference with examples/quicksort.md for the explanation.

7. Try the WebAssembly backend


./rail_native wasm examples/wasm/hello.rail

Compiling examples/wasm/hello.rail to WASM...
  WAT: 51277 bytes
  wat2wasm: OK
  Binary: /tmp/rail_out.wasm

./rail_native wasm emits a .wat file, runs the WebAssembly Binary Toolkit wat2wasm on it, and produces /tmp/rail_out.wasm (~12 KB). Load it in any WASM runtime that provides the env.print import (the live playground at ledatic.org does this).

You need wat2wasm on PATH for this step. On macOS: brew install wabt.

8. Try the Cortex-M4 backend


./rail_native cortexm examples/m4_uart_hello.rail

Compiling examples/m4_uart_hello.rail -> Cortex-M4 (Thumb-2)...
  Assembly: /tmp/rail_m4.s (1084 chars)
  as: OK -> /tmp/rail_m4.o
  startup as: OK
  ld: OK -> /tmp/rail_m4.elf

This produces a flashable Thumb-2 ELF at /tmp/rail_m4.elf. Run in qemu-system-arm -M mps2-an386 to see "Hi!" on the serial console.

You need clang with the thumbv7em-none-eabi target on PATH. On macOS: brew install llvm and the install will print the clang path.

9. Regenerate the stdlib reference


./rail_native run tools/docs/gen_stdlib_ref.rail

files processed: 80
wrote: docs/site/stdlib.md (124876 bytes)

The reference at stdlib.md is auto-generated from the actual stdlib source. The walker is a 250-line Rail program that reads each stdlib/*.rail, extracts top-level function signatures with their leading comments, and emits markdown. Read it: tools/docs/gen_stdlib_ref.rail.

10. Generate a signed provenance report

The provenance tier signs benchmarks with Ed25519 keys held on the fleet. The website endpoint is at https://ledatic.org/provenance — see the Provenance Tier session entry for the design.

For a local-only smoke equivalent: the LSP server at tools/lsp_server.rail and the test harness already include hash-based artifact verification. Running:


./rail_native test 2>&1 | tail -1

140/140 tests passed

is the local equivalent of a signed bench: the test suite is reproducible, deterministic, and the seed binary's SHA-256 is checked into rail_safe.sha256 for tamper detection.


You now have a working Rail toolchain on local hardware. Next steps:

Rail — self-hosted compiler · All docs · GitHub