Skip to content
Testing
Skill

/tlaplus

Use to model-check real code or a design with TLA+ and TLC. Model retries, locks, async flows, protocols or state machines as written, check invariants over every interleaving, and reproduce any counterexample trace as a failing test. Dispatched by /engineer.harden for

From plugin
atdd
16328 skills8 agents4 commands2 hooks

Claude Code

$ npx -y skills add swingerman/engineer --skill tlaplus --agent claude-code

SKILL.md

tlaplus.SKILL.md
name: tlaplus
description: Use to model-check real code or a design with TLA+ and TLC. Model retries, locks, async flows, protocols or state machines as written, check invariants over every interleaving, and reproduce any counterexample trace as a failing test. Dispatched by /engineer.harden for concurrency- and ordering-shaped risks; also usable directly, including to spec a design before building it. Triggers — "/engineer.tlaplus", "use TLA+ to verify X", "model-check X for races/deadlocks", "write a TLA+ spec for this protocol".

TLA+

TLA+ earns its keep by finding the counterexample you didn't think of. Don't write a spec and declare victory without actually running TLC — an uncompiled/unchecked spec is just prose with extra syntax.

Setup check

`java -version` (TLC needs a JVM 11+; if it's missing, tell the user rather than installing one). The model checker jar (`tla2tools.jar`, pinned to v1.7.4) auto-downloads on first run via `${CLAUDE_PLUGIN_ROOT}/skills/tlaplus/scripts/tlc.sh`, no separate install step needed.

Translating an informal design into TLA+

When the user describes a protocol/state machine in plain language, structure the spec around these pieces — this is the actual translation work, not boilerplate:

1. **`VARIABLES`** — the pieces of state that change. Keep this minimal; every variable multiplies the state space TLC has to explore. 2. **`Init`** — the starting state predicate. 3. **Actions** — one predicate per state transition (e.g. `SendMsg`, `Crash`, `Receive`). `Next == SendMsg \/ Receive \/ Crash \/ ...` 4. **Invariants** — the safety properties that must hold in *every* reachable state (e.g. `NoDataLoss`, `MutualExclusion`). These are what TLC actually checks — a spec without invariants can't find bugs. 5. **(Optional) Temporal properties** — liveness, e.g. `EventuallyDelivered`, checked separately from safety invariants and much more expensive.

Ask the user what actually must never happen (safety) before modeling — that answer is the invariant, and it's the one thing you can't infer from the protocol description alone.

Workflow

1. Write `Spec.tla` (the spec/module) and `Spec.cfg` (which invariants to check, `CONSTANTS` values, and state-space bounds like a max number of processes — TLC exhaustively explores states, so unbounded constants mean it never finishes). 2. Run: `bash ${CLAUDE_PLUGIN_ROOT}/skills/tlaplus/scripts/tlc.sh Spec.tla Spec.cfg` 3. **Read the output precisely.** TLC either says the invariant holds (`Model checking completed. No error has been found.`) or prints a counterexample trace — the exact sequence of states that breaks the invariant. That trace is the whole value of doing this: don't summarize it away, show the state-by-state trace so the actual bug is visible. 4. Fix the spec (or realize the invariant was wrong) and rerun. A "violation" is sometimes the invariant being stated too strongly — check which one is actually wrong before patching either. 5. If TLC times out or the state space is too large, narrow `Spec.cfg` constants (fewer processes/values) first — that's usually cheaper than restructuring the spec, and still finds most bugs since TLA+ bugs are rarely scale-dependent.

Verifying real code ("use TLA+ to verify X")

This is a different job from writing a spec from scratch: the goal is finding real concurrency/protocol bugs in real code and getting them fixed. The `.tla` files are scaffolding, not the deliverable — nobody merges them, they merge the PRs the counterexamples led to. TLA+'s specific strength here is interleavings: races, missed locks, out-of-order delivery, retry/timeout interactions — the class of bug that's nearly impossible to hit with a unit test because it depends on *when* two things happen relative to each other. Reach for TLA+ over Lean when the suspected bug is about concurrent/ interleaved behavior; reach for Lean when it's about a pure functional transformation or an unbounded data invariant. Structure the work as a todo list and post progress as you go — this runs long.

1. **Split the target into independent state machines**, same as for a from-scratch spec — read the real source and model each orthogonal subsystem (retry logic, session lifecycle, a message queue, a lock protocol) as its own small `.tla` module. 2. **Model from the code as written, not as intended.** States, actions, and guards must mirror the actual implementation including its bugs, or every check is vacuous. Cite the file/line each action is based on. 3. **State the invariants a reviewer would actually care about** (mutual exclusion, no lost message, bounded retries, no state stuck unreachable) and check them with TLC. TLC's exhaustive search over the bounded state space in `Spec.cfg` is doing the same job proof search does in Lean, but it's automatic — you don't have to find the counterexample yourself, TLC does, which is exactly why this is a good fit for "does this race exist." 4. **Review each model independently against the real code before trusting its results.** A clean TLC run on a wrong model proves nothing about the real system. 5. **When TLC reports a violation, don't report the abstract trace as the finding — reproduce it against the real code.** Translate the state-by-state trace into a concrete interleaving/input sequence and confirm it against the actual implementation (a test, a script forcing the interleaving, or a careful read of the code path). If it doesn't reproduce, the model diverged from reality — fix the model, not the code. 6. **For every confirmed bug, pin it with a test that fails before the fix and passes after.** State it in those terms: the test is what proves the bug was real and the fix works. Opening a PR is an external write. Propose the draft PR and wait for the human's OK (`${CLAUDE_PLUGIN_ROOT}/references/handoff-dispatch.md`). When `/engineer.harden

Read more
@swingerman
Ships withatdd

A methodology kit for engineering-led AI development — spec-driven, test-driven, charter-bound. ATDD + mutation testing + deterministic guardrails. AI agents do the typing. Engineers stay in charge of architecture, behavior contracts, and verification.

16328 skills8 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
163
Star history of swingerman/disciplined-agentic-engineering on GitHub, a chart by star-history.com

Other skills on atdd.

crap-analyzer

crap-analyzer

Use to produce a risk-based refactor + test plan for recently-changed code on a diff/branch/PR by computing CRAP (complexity ×…

@swingerman@swingermanInstall Skill
arch-check

arch-check

Use to check a feature's code against the charter's architecture rules — dependency layering, cycles, forbidden patterns, file…

@swingerman@swingermanInstall Skill
atdd

atdd

Use to drive feature work through the Acceptance Test Driven Development workflow — Given/When/Then specs before code, a…

@swingerman@swingermanInstall Skill
clarify

clarify

Use when a single DAE artifact has ambiguities to resolve. Triggers — "/engineer.clarify", "clarify this spec", "resolve…

@swingerman@swingermanInstall Skill
consistency-check

consistency-check

Use to validate DAE artifacts for schema correctness and cross-artifact consistency. Triggers — "/engineer.consistency-check",…

@swingerman@swingermanInstall Skill
discover-acs

discover-acs

Use when a Ready feature needs its acceptance criteria discovered before specs are written. Triggers — "/engineer.discover-acs",…

@swingerman@swingermanInstall Skill

More skills from other plugins.

api-review

api-review

Produce the "Playwright 1.xx API Review" artifact for a range of commits - the public API additions and the breaking or behavior…

playwrighttoday100k
@microsoft@microsoftInstall Skill
add-e2e-selectors

add-e2e-selectors

Add reliable @grafana/e2e-selectors to interactive elements and key containers in the Grafana frontend. Use when adding e2e…

grafanatoday78k
@grafana@grafanaInstall Skill
promptfoo-evals

promptfoo-evals

Write, refine, run, and QA promptfoo evaluation suites: promptfooconfig.yaml, prompts, providers, vars, tests, assertions,…

@promptfoo@promptfooInstall Skill
deepeval

deepeval

DeepEval evaluation workflow for AI agents and LLM applications. TRIGGER when the user wants to evaluate or improve an AI agent,…

@confident-ai@confident-aiInstall Skill

Questions about tlaplus.

Which coding agents can use tlaplus?
tlaplus installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.