| name | tlaplus-systems-engineer |
| description | Specify and verify concurrent, distributed, and agentic systems with TLA+, PlusCal, TLC, Apalache, and TLAPS. Covers state-machine modeling, invariants, fairness, counterexample analysis, refinement, and state-space explosion control. Use when the user mentions TLA+, TLA, TLC, PlusCal, Apalache, formal verification, model checking, concurrency, distributed protocols, nondeterminism, invariants, liveness, fairness, or wants to verify a design before writing code. |
TLA+ Systems Engineering
Use this skill when the problem is behavioral correctness, not syntax or implementation detail.
Think like a formal methods engineer: extract the state machine, bound the model, verify safety first, and only then translate the verified design into code.
What This Skill Does
- Turns requirements, pseudocode, or source code into an abstract TLA+/PlusCal model
- Defines
Init, named sub-actions, Next, TypeOK, safety invariants, and liveness properties
- Uses
TLC for finite exhaustive search, simulation for cheap exploration, and Apalache/TLAPS when exhaustive TLC is the wrong tool
- Detects and mitigates state-space explosion before it wastes time
- Interprets counterexamples as design bugs, missing assumptions, or over-strong properties
- Maps verified specs back into implementation plans and runtime assertions
Operating Rules
- Model the system, the environment, and the scheduler separately.
- Abstract aggressively. If a detail does not affect the property, remove it.
- Bound everything for TLC: finite constants, small sets, short sequences, explicit limits.
- Write
TypeOK early. Many "behavior" bugs are malformed state.
- Define small named sub-actions, then compose
Next from them.
- Add fairness only after safety is stable.
- Apply fairness to specific actions when possible;
WF_vars(Next) is often too coarse.
- Treat state-space explosion as a modeling problem first and a tooling problem second.
- When a step is too atomic, split it with a program counter or PlusCal labels.
- Keep the spec more abstract than the code; refinement should add detail, not change intent.
Quick Start
- Identify:
- system actors and processes
- shared state
- environment actions and failures
- safety invariants
- liveness expectations
- Choose representation:
- Use
PlusCal for algorithmic workflows, retries, loops, and process-local control flow.
- Use raw
TLA+ for declarative protocols, relation-heavy state, or highly abstract specs.
- Build the skeleton:
---- MODULE Spec ----
EXTENDS Integers, FiniteSets, Sequences, TLC
CONSTANTS ...
VARIABLES ...
vars == <<...>>
TypeOK == ...
Init == ...
ActionA == ...
ActionB == ...
Next == ActionA \/ ActionB
Spec == Init /\ [][Next]_vars
====
- Add the smallest useful model:
N = 2, not N = 10
- a two-message queue, not an unbounded history
- two agents and one adversarial environment step
- Run TLC or simulation.
- If TLC explodes, reduce state width before touching liveness.
- Once safety holds, add fairness and liveness.
- Only then translate to production code.
Core Workflows
1. Modeling a New System
- Restate the system boundary in plain English.
- Extract actors, shared state, environment actions, and failure modes.
- Choose
PlusCal or raw TLA+ based on control-flow vs protocol shape.
- Write
TypeOK, Init, named sub-actions, Next, and Spec.
- Run the smallest useful TLC model first.
- Check safety before any liveness work.
2. Debugging a Counterexample
- Explain the trace as a short story.
- Identify the first irreversible bad transition.
- Classify the issue as a design bug, missing assumption, bad abstraction, or overly strong property.
- Apply the smallest fix that preserves the original intent.
- Re-run TLC before changing anything else.
3. Recovering from State Explosion
- Shrink constants and domains.
- Remove irrelevant payload detail.
- Replace ordered structures when order is not part of the property.
- Split oversized actions with
pc or PlusCal labels.
- Add symmetry or checker reductions only after the model itself is clean.
- Move to simulation or
Apalache only if the abstraction is already disciplined.
4. Translating a Verified Spec into Code
- Map each state variable to an implementation state holder.
- Convert invariants into assertions, validations, or tests.
- Preserve guards and preconditions explicitly.
- Document fairness assumptions as operational dependencies, not code guarantees.
- Call out what the spec intentionally did not model.
Decision Guide
Choose the representation
- Use
PlusCal when the user describes steps, labels, retries, loops, or per-process programs.
- Use raw
TLA+ when the user describes relations, constraints, ownership, messages, or protocol states.
Choose the checker
- Use
TLC for finite, explicit-state bug hunting and invariant checking.
- Use TLC simulation when the model is too large for exhaustive search but you still want fast counterexample hunting.
- Use
Apalache for bounded symbolic checking, arithmetic-heavy models, or larger parameter spaces.
- Use
TLAPS when the property must hold beyond any reasonable finite instance and you need proof, not search.
State-Space Explosion Playbook
When TLC starts drowning in states, do these in order:
- Shrink constants and domains.
- Replace data payloads with symbolic tags.
- Replace sequences with sets when order is irrelevant.
- Model one shared resource instead of many equivalent copies.
- Add symmetry where processes are interchangeable.
- Split oversized actions with
pc.
- Add state constraints only if they preserve the behaviors relevant to the property.
- Move from exhaustive TLC to simulation or Apalache only after the model is already clean.
Output Standards
Spec Brief
## TLA+ Spec Brief
- System: [what is being modeled]
- Actors: [processes, environment, scheduler]
- State: [variables and meaning]
- Safety: [invariants]
- Liveness: [eventual properties]
- Abstractions: [what was intentionally omitted]
- Model bounds: [constants and limits]
Counterexample Report
## Counterexample Report
- Property violated: [invariant or liveness condition]
- Short trace story: [plain-English explanation]
- First bad transition: [which action caused divergence]
- Root cause: [design error vs missing assumption vs overly strong property]
- Fix options: [1-3 concrete changes]
Translation Plan
## Verified-to-Code Plan
- Preserved state variables: [spec -> code mapping]
- Preserved invariants: [assertions and guards to keep]
- Concurrency assumptions: [scheduler, retries, timeouts]
- Gaps not modeled: [I/O, latency, auth, persistence details]
Companion Skills
If official TLA+ companion skills are installed, use them as focused helpers:
tlaplus-from-source for extracting a first model from code
tlaplus-split-action for reducing atomicity and clarifying interleavings
tlaplus-add-variable for safe spec extensions
The TLA+ VS Code/Cursor extension is also useful for syntax, TLC integration, and MCP-backed knowledge if available.
Progressive Disclosure References
- tla-foundations.md: semantics, stuttering, fairness, refinement, and the mental model behind TLA+
- verification-workflow.md: TLC internals, simulation, Apalache, TLAPS, model configs, and trace interpretation
- modeling-patterns.md: reusable patterns for queues, locks, retries,
pc-based actions, message passing, and symmetry
- agentic-systems.md: how to model LLM agents, tool calls, human approvals, partial failure, and verified code generation