The language where LLM edits survive.
Playground · Cheatsheet · Specification · Why · Quick start · Evidence · How it works · Status
Almide is a statically-typed language built for one metric: modification survival rate — how often code still compiles and passes its tests after a series of AI-driven edits. It compiles to native binaries (via Rust) and to WebAssembly, and the two produce byte-identical output.
The metric in one screen. A model adds a case to a type and, as models do, touches nothing else:
type Shape =
| Circle(Float)
| Square(Float)
| Triangle(Float, Float) // the edit
fn area(s: Shape) -> Float =
match s {
Circle(r) => 3.14159 * r * r
Square(w) => w * w
}
error[E010]: non-exhaustive match: missing Triangle(_, _)
--> shape.almd:7:9
in match
here: match s {
hint: add arms for Triangle(_, _):
Triangle(arg1, arg2) => _
Or use `_ => todo()` to compile incrementally.
The compiler names the missing case at the site, spells out the arm to add, and offers a way to keep compiling while the rest is written. The model's next turn is Triangle(b, h) => 0.5 * b * h; the program then runs natively and on wasm and prints the same bytes. That loop — an edit, a diagnostic that is itself the fix, a passing build — is what every decision below serves.
- Predictable — One canonical way to express each concept, reducing token branching for LLMs
- Local — Understanding any piece of code requires only nearby context
- Repairable — Compiler diagnostics guide toward a specific fix, not multiple possibilities (as above)
- Compact — High semantic density, low syntactic noise
The full rationale: Design Philosophy. The frozen surface and the breaking-change policy: STABILITY.md (declared 2026-08-20) — anything in the Cheatsheet or llms.txt keeps meaning what it means.
Try it in your browser → — no installation.
curl -fsSL https://raw.githubusercontent.com/almide/almide/main/tools/install.sh | sh # macOS / Linux
irm https://raw.githubusercontent.com/almide/almide/main/tools/install.ps1 | iex # Windows (PowerShell)From source, with Rust 1.94+ (the binary embeds the wasmtime host): cargo build --release && cp target/release/almide ~/.local/bin/.
fn main() -> Unit = {
println("Hello, world!")
}
almide run hello.almd # native
almide run hello.almd --target wasm # same bytes, on wasmtime- Multi-target — Same source compiles to a native binary (via Rust) or WebAssembly (direct emit, no LLVM)
- Generics — Functions (
fn id[T](x: T) -> T), records, variant types, recursive variants with auto Box wrapping - Pattern matching — Exhaustive
matchwith variant destructuring - Effect functions —
effect fnfor explicit error propagation:expr!propagates, a bare fallible call is an error, never silent - Bidirectional type inference — Annotations flow into expressions (
let xs: List[Int] = []) - Codec system —
Type.decode(value)/Type.encode(value)with auto-derive - Map literals —
["key": value],m[key],for (k, v) in m - Fan — structured concurrency:
fan { a(); b() }on real threads natively, sequential on wasm;fan.map/fan.anydeterministic by list order on both - Pipeline operator —
data |> transform |> output - Module system — Packages, sub-namespaces, visibility control, diamond dependency resolution
- Standard library — self-hosted
.almdmodules: string, list, map, json, http, fs, and more (reference; the count is derived under Project Status) - Built-in testing —
test "name" { assert_eq(a, b) }withalmide test
Every claim in this section is either derived by a script or carries the date it was measured; scripts/check-readme-numbers.sh refuses a bare number in CI.
Measured by almide-dojo across 30 tasks (basic / intermediate / advanced) on 2026-04-12; later runs are on the live dashboard:
| Model | Pass Rate | 1-Shot Rate |
|---|---|---|
| Claude Sonnet 4.6 | 100% (30/30) | 47% |
| Llama 3.3 70B | 61% (17/28) | 33% |
The most recent same-model comparison is the MiniGit bench: Sonnet 5 × 20 trials on 2026-07-15, 100% pass, the most concise of 5 languages (233 LOC), and the fastest agent wall-clock against Gleam and MoonBit — an LLM-writability number, measured under 6–9× self-parallelism, not generated-code speed (chart · method · upstream).
Every program that compiles for both targets produces byte-identical observable output — stdout, stderr, exit code — whether it runs as a native binary or as WebAssembly. Native is the oracle; native == wasm is a hard invariant, not a "target difference" to be documented around.
The guarantee is continuous, with an explicit, ledger-managed scope: "byte-identical" means the execution output, not the compiled artifacts; inherently nondeterministic sources certify deterministic invariants instead of exact bytes; APIs not yet implemented on wasm are compile- or run-time refusals — never wrong bytes; and exactly two fns are exempt because their job is to report the host — env.os() and env.temp_dir(), bounded by C-189, since making them agree across targets would be the defect rather than the guarantee.
This claim is not prose. Every observable promise is a named contract in the behavior-contract ledger, each traceable to executable evidence, and the numbers below are regenerated from the ledger (scripts/gen-claims.sh, enforced by scripts/check-contracts.sh in CI):
Ledger: 347 contracts — 347 active, 0 flagged-for-revision.
Divergences awaiting a fix: none. Every contract in the ledger is
active, carrying executable evidence of class >=fixture. The one by-design carve-out in the law — the platform-reporting fnsenv.osandenv.temp_dir— is bounded by C-189.
Scope, ledger mechanics, and the evidence stack (contract ledger, cross-target fixture gate, differential fuzz, emit-time Σ-probes, Lean belt, org-wide byte-verify sweep): docs/design/EQUIVALENCE.md.
You write no ownership annotations, no lifetimes, no free: Perceus-style ownership inference in the compiler decides where every heap value is introduced, duplicated, and consumed — garbage-collector-free, pause-free. On the incumbent wasm leg that decision ships with a per-build ownership certificate a kernel-proven checker re-verifies (Rocq/Coq spine, 96 audited theorems and lemmas, axiom-clean, independently re-checked by coqchk; the count is asserted by proofs/check.sh). The structural wasm leg (the default since #1599) and the native leg are trusted, not proven: their evidence is differential — byte-identical output against the certified leg on the contract corpus, held by a grow-only floor and a semantic-mutation net. The Built … line names the leg that produced your bytes. The boundary, stage by stage: proven-vs-trusted.md; the full account, including the Lean 4 Perceus belt the design started from: docs/design/MEMORY-SAFETY.md.
No runtime, no GC, no interpreter — native compiles through Rust to machine code, and WASM is emitted directly as self-contained modules.
Program (almide build --target wasm, verified, as shipped) |
incumbent v1 leg | structural leg |
|---|---|---|
| Hello, world | 1,096 B | 1,337 B |
Measured on almide 0.62.0, 2026-09-08, from docs/benchmarks/wasm-size.txt; no post-hoc optimizer touches the shipped bytes (--wasm-opt is opt-in and its output is not the verified module).
Rust on the same wasm target is 40 KB+ for Hello, world even fully size-tuned; the native minigit CLI binary is 418 KB stripped with 0 dependencies. The byte-by-byte dissection, measured 2026-07-23 on the incumbent leg: docs/wasm/WASM-OUTPUT.md.
Against handwritten Rust the arithmetic kernels sit at parity (n-body, spectral-norm 1.00×; the ratchet's anchored rows). Where Almide has information Rust does not — a tree whose whole lifetime is one check(make(depth)) expression, proven by the effect system — it is faster than the ordinary Rust for the same program:
Workload (bench.py, median of 9, interleaved) |
optimization | Almide / ordinary Rust | without it (ALMIDE_REGION_OFF=1) |
CI runner |
|---|---|---|---|---|
| binarytrees | region window (#1991) | 0.35 (d17) / 0.32 (d19) | 1.25 | 0.61 |
| treealloc | region window (#1991) | 0.30 (d20) / 0.30 (d21) | 1.10 | 0.61 (est.) |
Two ratios per row are the two input sizes (the win holds at both); the Rust side is the ordinary program a person writes for it — a Box per node, one thread, no arena, no unsafe, no SIMD — compiled with the same rustc flags, and the "without it" column is the same Almide source with the region window turned off, so the whole gap is that one optimization. The absolute ratio is allocator-dependent (the CI runner frees a Box cheaper), the direction is not: the perf-ratchet job fails if either row reaches 1.0 or the ablation stops paying. Declaration and methodology: docs/project/BENCHMARKS.md. Ledger: docs/benchmarks/native-victory.txt (almide 0.62.0, 2026-09-08).
Measured on almide 0.59.1, arm64 Darwin, examples/lisp.almd (268 lines), 2026-08-27. Every row is an N-run MEAN —
a single run of a 30ms process is scheduler noise. Cold clears BOTH $TMPDIR/almide-run
and the dependency cache before each repetition; clearing only the latter measures a warm
build. Regenerate with almide run tools/almide-gates/src/main.almd -- bench; the ratchet
(-- bench --check) fails CI at 1.5x.
| scenario | time | runs |
|---|---|---|
almide check |
15.2 ms | 20 |
| build, warm (content-cache hit) | 237.2 ms | 5 |
| build, cold | 635.3 ms | 3 |
build, cold, --target wasm |
61.7 ms | 3 |
almide check scales linearly: over a 2k → 30k-line ladder of this repo's own stdlib the log-log slope of check time against project lines is 1.13 (1.0 is linear, 2.0 quadratic) and the 10k-line rung costs 4.4× the empty-project floor — measured 2026-08-13, held by scripts/check-edit-loop-scale.sh, table in BENCHMARKS.md. Native runtime against handwritten Rust: 1.00× on n-body and spectral-norm, 1.16–1.18× on fasta and FFT, ~1.6× where the workload is list materialization (#1004), CI-gated ratio ratchet (scoreboard). Wasm runtime, measured and gated (#1701):
Benchmark (almide bench, verify-then-time, median of 5) |
wasm/native ratio |
|---|---|
| nbody | 2.69× |
| spectralnorm | 2.65× |
| binarytrees | 0.93× |
| treealloc | 0.41× |
| fft | 4.02× |
| strchurn | 1.15× |
| listbuild_append | 3.33× |
| listbuild_combinator | 3.79× |
| listbuild_prealloc | 3.54× |
| mapbuild | 1.16× |
Embedded wasm host (Perceus RC in linear memory) against the native binary, same machine, same run. Cross-engine ratios do NOT cancel hardware (a 2-core CI runner measures nbody ~10x worse), so the ratio verdict runs on the stamping machine class and CI gates the STATUS taxonomy below (scripts/check-wasm-runtime-ratio.sh). binarytrees runs its fan arms on the embedded host's thread pool, which is why wasm WINS there. The unmeasured corpus cells stay honest instead of estimated: 3 route to the incumbent artifact, 1 wall on the wasm build path, 0 exhaust the embedded heap (#1729) — each re-measured every gate run, so a cell that starts benching fails the gate until its row is promoted. Ledger: docs/benchmarks/wasm-runtime.txt (almide 0.62.0, 2026-09-08).
One frontend, one IR, three renderers behind two targets:
flowchart LR
SRC([".almd"]) --> FE["Lexer → Parser → Type Checker → Lowering"] --> IR(["IR"])
IR --> NANO["Nanopass Pipeline<br/>semantic rewrites"] --> TMPL["Template Renderer<br/>TOML-driven"] --> RS([".rs → native binary"])
IR --> ROUTER{"router"}
ROUTER --> STRUCT["structural leg<br/>commissioned engine, direct emit"] --> WASM([".wasm"])
ROUTER --> INCUMB["incumbent v1 leg<br/>certified MIR, direct emit"] --> WASM
Native. The Nanopass pipeline applies target-specific transformations — ResultPropagation (Rust ?), CloneInsertion (Rust borrow analysis), LICM (loop-invariant code motion). The Template Renderer is purely syntactic: every semantic decision is already encoded in the IR.
WebAssembly. Since commissioning (#1599) two verified renderers sit behind one router (render_wasm_module_routed in src/cli/build.rs). The structural leg — the commissioned engine, almide::wasm_leg front + crates/almide-wasm emitter — takes every program with a main, no external packages, and no host-variant I/O on the build path; it was accepted at 610/610 byte-identical to native on the wasm_cross corpus, and its build artifacts ship in the WASI form (#1588) so they run on stock runtimes. The incumbent v1 leg — the certified MIR trust spine in crates/almide-mir — takes main-less library modules, dependency-bearing projects, host-variant programs, and any shape the structural leg walls on: a verified-to-verified handover, never the retired unverified emitter, and a program neither leg lowers is an honest error. ALMIDE_WASM_INCUMBENT=1 forces the incumbent; ALMIDE_VERIFIED_DEBUG=1 narrates the routing.
almide run app.almd # Compile + execute (native)
almide build app.almd --target wasm # Build WebAssembly (WASI)
almide test # Find and run all test blocks (recursive)
almide check app.almd # Type check only
almide check app.almd --target wasm # + the wasm build route: E081/E082 at check time (#1922)
almide fmt app.almd # Format source codeRun almide --help for the full command list (compile, add, deps, clean, …). Pipeline and module map: docs/ARCHITECTURE.md; the two wasm legs in detail: docs/wasm/.
The Perceus proof above proves one compiler pass, once. v1 generalizes that principle to the whole pipeline — instead of proving the 100k-line compiler, it proves a tiny checker and has the compiler emit a certificate on every build that the checker re-verifies. If the checker accepts, the artifact has the property — a theorem that never mentions the compiler's internals. That collapses the trusted base from ~100,000 lines to the extracted checker (~1,400 lines of OCaml, machine-derived from the proofs), and asks a harder question than testing ever can: not "do the tests pass?" but "can a machine prove the output is correct?" The architecture, the receipts (C-SAFE / C-REPRO / C-FAITHFUL / C-PROVEN), and why builds are slower on purpose: docs/TRUST-SPINE.md.
| Category | Status |
|---|---|
| Maturity | Pre-1.0, under active development on develop; the LLM-facing surface is frozen by STABILITY.md (declared 2026-08-20) |
| Support | Latest release line only, pre-1.0 — policy and versioning guarantees: SUPPORT.md · vulnerabilities: SECURITY.md |
| Compiler | Pure Rust, single binary, 0 ICE |
| Targets | Rust (native), WASM (direct emit — two verified legs behind one router, see How It Works) |
| Verified codegen | Incumbent v1 leg: PCC certificates re-verified on every build since 0.29.0 (--no-verified opts out). Structural leg: byte-exact corpus and mutation gates, no certificate yet |
| Codegen | Rust: Nanopass + TOML templates; wasm: structural engine or certified MIR → direct emit (the unverified v0 emitter is retired — a wall is an error, never a fallback) |
| Artifacts | .almdi module interface files via almide compile |
| Playground | Live — the compiler runs as WASM in the browser |
| Derived count | Value |
|---|---|
| Stdlib | 985 functions across 43 modules — self-hosted .almd, signature indexes regenerated from the compiler by tools/gen-stdlib-doc-index.py |
| Tests | 436 .almd test files under spec/ (almide test spec/) + the 347-contract cross-target ledger |
- almide-grammar — the single source of truth for syntax (keywords, operators, precedence, TextMate scopes), written in Almide; the compiler generates its lexer keyword table from it at build time, so compiler and tooling cannot drift
- vscode-almide · tree-sitter-almide (Neovim, Helix, Zed) · playground
- docs/CHEATSHEET.md — quick reference for AI code generation · docs/SPEC.md — the language specification · docs/GRAMMAR.md — EBNF grammar + stdlib reference
- docs/design/DESIGN.md — design philosophy · docs/design/EQUIVALENCE.md — the byte-identity claim · docs/design/MEMORY-SAFETY.md — the proven/trusted account · docs/TRUST-SPINE.md — v1
- docs/contracts/ — behavior-contract ledger · docs/stdlib/ — standard library, per module · docs/project/BENCHMARKS.md — sizes, runtime, edit-loop scale · docs/roadmap/ — evolution plans
Issues and pull requests are welcome on GitHub. After cloning, install the git hooks (brew install lefthook && lefthook install); commits must be in English (enforced by the commit-msg hook). Project conventions: CLAUDE.md.
Licensed under either of MIT or Apache 2.0 at your option.
