Model-check specifications. Find counterexamples. Check certificates.
A from-scratch model checker in Rust for TLA+, Petri nets, and hardware designs — a TLC replacement whose verdicts come with independently re-checkable proofs.
Quick start · Check the answers · What ty checks · Use ty · Architecture · Soundness · Migrating from TLC
ty takes a specification and a property and tells you whether the property can
ever be violated. One binary model-checks TLA+ specs (a TLC replacement),
runs Model Checking Contest (MCC) examinations on PNML Petri nets, and
checks AIGER and BTOR2 hardware designs. You supply the model and the
property; ty returns one of:
| Answer | Meaning | Artifact |
|---|---|---|
| holds | The property holds over every reachable state. | On certifying paths, a re-checkable safety certificate. |
| counterexample | The property can be violated. | The exact trace of states that reaches the violation, replayable against the spec. |
| cannot compute | ty cannot settle it within its methods or limits. |
The reason — never a guess. |
ty is soundness-first: an engine commits only a verdict it can justify.
When in doubt it abstains, falls back, or crashes rather than emit a wrong
result. The frontends share one core — a parallel explicit-state engine,
symbolic engines (BMC, k-induction, IC3/PDR, CHC) on the
ay SAT/SMT solver, native compilation
of hot paths, and a certifying pipeline that emits independently re-checkable
certificates.
Status — not yet buildable from this repo alone. The workspace still depends on unpublished sibling repos:
trust-ir/trust-cg(the native-compilation IR and codegen) andclean(the CIC proof kernel). Its SAT/SMT/CHC backend,ay, is already published. Until the rest land,cargofails at dependency resolution, so this snapshot is for reading and review; the dependency repos are being released to make it buildable end-to-end.
Once the dependency repos above are published, build ty from source with a
current stable Rust toolchain:
cargo build --release -p tla-cli # → target/release/ty
export PATH="$PWD/target/release:$PATH"examples/DieHard.tla is the Die Hard 3 water-jug puzzle: a 3-gallon and a
5-gallon jug, and the goal of measuring exactly 4 gallons. The spec asserts the
invariant NotSolved == big # 4 ("the big jug never holds 4 gallons"). That
invariant is false — the puzzle is solvable — so model-checking it turns the
solution into a counterexample:
ty check examples/DieHard.tla --config examples/DieHard.cfgty reports Invariant NotSolved is violated and prints the counterexample
trace — the exact sequence of states that reaches 4 gallons, each labelled with
the action that produced it:
Error: Invariant NotSolved is violated.
State 1: big = 0, small = 0 (initial)
State 2: big = 5, small = 0 FillBig
State 3: big = 2, small = 3 BigToSmall
State 4: big = 2, small = 0 EmptySmall
State 5: big = 0, small = 2 BigToSmall
State 6: big = 5, small = 2 FillBig
State 7: big = 4, small = 3 BigToSmall ← big = 4
That last state is the solution, and ty exits 1. A property that holds
instead reports the distinct states explored (States found: N) and exits 0.
Add --output json for machine-readable results, --workers N to parallelize,
and --require-exhaustive to make a non-exhaustive run fail (a CI gate).
New to model checking? ty tutorial is an interactive walk through the same
ideas — ty tutorial demo runs this exact check for you.
ty's verdicts are backed by evidence you can replay with a checker that never
ran the search:
- A counterexample is a concrete trace.
tyreplays it step by step against the original spec before reporting it, and you can inspect or re-run it yourself — export it as a graph withty graph(DOT/Mermaid). - A safety verdict can be certified.
ty certifyemits a re-checkable safety certificate;ty cert-checkreplays it through an independent checker — a CIC proof kernel on the explicit-state lane, anday's audited proof checker (with Carcara as a second, independent Alethe checker) on the symbolic lane.
ty certify examples/Mutex.tla --config examples/Mutex.cfg --out Mutex.cert.json
ty cert-check Mutex.cert.json # independent re-check; shares none of ty's search statety prove proves inductive safety symbolically, re-checks the emitted
certificate, and corroborates it with a second independent first-order kernel
(tla-zenon tableau prover + tla-cert checker). ty refine-certify /
ty refine-check emit and re-check kernel-checked refinement certificates.
ty tcb-census lists the axioms and trust markers behind any
kernel-certified verdict, so the trusted computing base is never implicit.
- TLA+ model checking — parallel BFS built to match TLC's verdicts and
state counts. Liveness (tableau + SCC), symmetry reduction, partial-order
reduction. Migrating from TLC is a flag-for-flag move — see
MIGRATING.md. - Native compilation — TLA+ compiles to bytecode, lowers to trust-ir (an SSA IR with instruction semantics modeled on LLVM's, no dependency on the LLVM project), then to machine code via the external trust-cg toolchain. Admission is conservative: the interpreter stays the soundness fallback.
- Certified proofs —
ty certify/ty proveemit independently re-checkable safety and inductive-safety certificates (see above). - Petri nets / MCC — every standard MCC examination (state space, upper
bounds, reachability, LTL, CTL, one-safe, stable marking, (quasi-)liveness)
directly on PNML models, with decision-diagram, symbolic, and structural
engines run in cost order. In our MCC 2025 runs against the consensus oracle
(verdicts at least two competing tools agree on), ty produced no wrong
answers across all 13 categories. Unsolvable queries return
CANNOT_COMPUTE, not a guess. - Hardware model checking — AIGER (IC3/PDR + BMC + k-induction) and BTOR2 (bad-state reachability via CHC/SAT) frontends.
- Tooling — a language server (
ty lsp), TLA+→Rust code generation, simulation, coverage analysis, counterexample-graph export, and side-by-side TLC comparison (ty supremacy compare).
# TLA+
ty check MySpec.tla --config MySpec.cfg # model-check
ty check MySpec.tla --config MySpec.cfg --output json --workers 4
ty certify MySpec.tla --config MySpec.cfg --out MySpec.cert.json # re-checkable certificate
ty prove MySpec.tla # inductive proof + independent re-check
# Petri nets (Model Checking Contest)
ty mcc ./model-dir --examination StateSpace
ty petri ./model-dir --examination ReachabilityDeadlock
# Hardware
ty aiger circuit.aig --timeout 60
ty btor2 design.btor2 --timeout 60Other entry points include ty parse, ty typecheck, ty simulate,
ty codegen, ty explain, ty coverage, ty graph, ty repair, ty lsp,
ty cert-check, and ty diagnose; run ty --help for the full list.
The default build ships the full surface: explicit-state checking, Petri/MCC,
AIGER/BTOR2, the symbolic engines, and the certifying commands. For a lean,
explicit-state-only build: --no-default-features --features mimalloc. On
macOS, if a build reports a missing GNU m4 (needed only by some optional
features): brew install m4 && export PATH="$(brew --prefix m4)/bin:$PATH".
ty is a multi-crate Rust workspace:
| Layer | Crates | Purpose |
|---|---|---|
| Frontend | tla-core, tla-tir, tla-value |
Parser, typed IR, value types |
| Evaluation | tla-eval |
Tree-walking interpreter (the correctness oracle) |
| Model checking | tla-check, tla-mc-core, tla-backend |
BFS, liveness, symmetry, engine selection |
| Symbolic | tla-ay |
BMC, IC3/PDR, k-induction, CHC via ay |
| Compilation | tla-trust-cg, tla-ir, tla-codegen, tla-runtime |
Native backend (TIR→trust-ir lowering), TLA+→Rust codegen |
| Proofs | tla-zenon, tla-cert |
First-order tableau prover, certificate checking |
| Hardware | tla-aiger, tla-btor2 |
AIGER/BTOR2 model checking (HWMCC) |
| Petri nets | tla-petri, pnml-tools |
MCC examinations, PNML I/O |
| Decision diagrams | tla-dd, tla-bdd, tla-mdd |
Native DD engines (Petri lane) |
| Tooling | tla-lsp, tla-cli |
Language server, CLI |
The workspace also vendors its dependency tree as tla-* forks of upstream
library crates — infrastructure for a zero-external-dependency posture, not part
of the verification surface.
- TLC is the behavioral oracle for explicit-state TLA+;
ty supremacy comparemeasures both tools on a given spec (requires TLC and Java). Don't assumetyis faster on your model — measure. - Symmetry is ignored under liveness checking by default: the orbit quotient
is unsound for temporal properties (TLC applies it anyway and can report wrong
verdicts).
tywarns and checks without it; pure-safety checking keeps it.TY_MATCH_DECLARED_SYMMETRY=1opts back into TLC's behavior — a loudly warned timing-parity lever whose liveness verdict inherits TLC's unsoundness. - Advanced paths carry evidence. The symbolic, hardware, and native-compilation paths ship by default, but back results on a given spec with parity evidence (the engine agrees with the interpreter on that spec) or backend-admission evidence.
ty tcb-censusprints the trusted computing base behind any certified verdict.
These commands require the sibling dependency repos (see Status) checked out alongside this one.
cargo test --workspace # run all tests
cargo clippy -p tla-cli --all-targets # lint the CLIty corpus fetch installs the TLC-comparison benchmark corpus to
~/tlaplus-examples. Both the default and lean builds must keep compiling;
scripts/check_ay_build_gate.sh gates the ay-enabled configurations (gates
run manually).
To compare against TLC you also need TLC itself and the TLA+ proof library:
ty install-tlc install --with-proof-library # TLC + CommunityModules + TLAPS library
ty corpus doctor # which specs are actually comparable, and whyThe proof library matters more than it sounds: 25 of the 141 comparable corpus
specs EXTENDS TLAPS / FiniteSetTheorems / NaturalsInduction, and TLC dies
in the parser without them. ty install-tlc proof-library fetches
tlapm's library/ at a pinned commit,
verified per file by sha256.
ty corpus doctor then reports, per spec, whether TLC can parse it, whether
exact state-count parity with TLC is even possible (it is not where TLC applies
a declared SYMMETRY to a liveness property — ty soundly refuses that orbit
quotient and explores the full space), and whether a ty measurement exists.
ty builds on decades of research in model checking, temporal logic, and formal
verification:
- TLC (Yu, Manolios, Lamport; MIT) — reference model checker.
- TLAPM (Chaudhuri, Doligez, Lamport, Merz; BSD) — TLA+ proof system architecture.
- Zenon (Bonichon, Delahaye, Doligez; BSD) — first-order tableau prover;
tla-zenonis a Rust port. - rIC3 (Yuheng Su; GPL-3.0) — primary reference for
tla-aiger. - IC3ref (Aaron Bradley; MIT) — original IC3 reference.
- Apalache (Konnov, Kukovec, Tran) — symbolic model checking for TLA+.
- ay (Yates; Apache-2.0) — SAT/SMT/CHC backend.
Full bibliography: REFERENCES.md.
Apache License 2.0. See LICENSE. Copyright 2026 Andrew Yates.
The vendored tla-* forks of upstream library crates under crates/ retain
their upstream licenses (MIT, Apache-2.0, BSD, and others — see each crate's own
license files).