tlc.proc.io — hosted TLA+ model checking
A ground-up Rust rewrite of the TLA+ tools (SANY + TLC, safety subset), compiled to a 509 KB WebAssembly module and served from Cloudflare's edge. No JVM. No install. An MCP server your coding agent can call natively.
What it does
You write a TLA+ specification of your system and a small config; the
service exhaustively explores every reachable state, checking your
invariants and [][A]_v action properties on each transition.
If a property can be violated, you get the shortest counterexample
trace — the exact step-by-step scenario that breaks your design. If the
state space explodes, you get a per-level growth profile and a hint about
which constant to shrink, instead of a hung process.
Use it from Claude (MCP)
The service speaks the Model Context Protocol at /mcp
(Streamable HTTP, stateless). One command registers it in Claude Code:
claude mcp add --scope user --transport http tlc \
https://tlc.proc.io/mcp \
--header "Authorization: Bearer $TLC_API_TOKEN"
Two tools appear: tlc_check (full model check — pass the
module source and TLC config, get state counts, traces, diagnostics) and
tlc_parse (fast syntax + semantic + level check). Your agent
keeps the spec next to the code, updates it when the architecture changes,
and verifies every change in seconds — a formal-methods reviewer on tap.
Use it from anything else (REST)
curl -s https://tlc.proc.io/check \
-H "Authorization: Bearer $TLC_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"modules":[{"name":"Spec","source":"---- MODULE Spec ----\n..."}],
"config":"INIT Init\nNEXT Next\nINVARIANT TypeOK",
"timeoutSeconds":30}'
Response is JSON: status (ok,
invariant_violation, deadlock,
timeout, …), stats, a violation.trace
when something breaks, and a diagnostic with per-level state
growth when the space blows up.
Why this is cool
Model checkers have always meant "install a JVM, download a jar, babysit a process." This one is a stateless function at the edge: the entire checker — a hand-written parser faithful to SANY's column-sensitive junction-list grammar, a value system whose 64-bit fingerprints are bit-identical to Java TLC's, and a breadth-first search engine — boots in microseconds inside a V8 isolate near you.
Correctness isn't asserted, it's measured: every build is differentially tested against the reference Java implementation on a mined conformance suite, matching its verdicts, exact state counts, and counterexample depths. Where the two disagree, the discrepancy is documented and traced to an upstream bug, not shrugged off.
And because it's MCP, the checker composes with agents: "keep the spec in sync with the architecture and prove my invariants still hold" becomes a background loop, not a chore.
Scope
Safety subset: invariants, deadlock, box-action properties
([][A]_v), CONSTANT/CONSTRAINT, model values, EXTENDS-based
modules (Naturals, Integers, Sequences, FiniteSets, TLC, Bags built in).
Not supported: liveness/fairness, symmetry, parameterized INSTANCE,
ENABLED. Keep specs finite — small constant sets, bounded ranges.