arabelatso/tlaplus-spec-generator
Automatically generate TLA+ specifications from source code (C/C++, Python) for formal verification of distributed systems. Use when users need to: (1) Generate TLA+ specs from program implementations, (2) Model distributed systems, consensus protocols, or concurrent algorithms, (3) Extract state variables, actions, and invariants from code, (4) Create formal specifications for model checking with TLC, (5) Verify safety and liveness properties of distributed systems. Particularly effective for message-passing systems, replication protocols, consensus algorithms, and distributed transactions.
npx skills add https://github.com/ArabelaTso/Skills-4-SE --skill tlaplus-spec-generator
Automatically generate TLA+ specifications from program implementations for formal verification of distributed systems.
This skill transforms imperative programs (C/C++, Python) into declarative TLA+ specifications. It analyzes program structure to identify state variables, actions, and system behavior, then generates well-structured TLA+ modules suitable for model checking with TLC.
Generate TLA+ specification from source files:
# Single file
python3 scripts/generate_spec.py program.py -o Spec.tla
# Multiple files
python3 scripts/generate_spec.py server.py client.py protocol.py -o Protocol.tla
# With module name
python3 scripts/generate_spec.py distributed_system.c -o System.tla --module-name DistributedSystem
The generator automatically:
For distributed systems, specify the number of processes:
python3 scripts/generate_spec.py consensus.py -o Consensus.tla --processes 3
This creates a constant N in the TLA+ spec representing the number of processes/nodes.
The generator produces two files:
1. Spec.tla - Complete TLA+ specification:
---- MODULE Spec ----
EXTENDS Naturals, Sequences, FiniteSets, TLC
CONSTANTS N \* Number of processes
VARIABLES
state,
messages,
committed
vars == <<state, messages, committed>>
TypeOK ==
/\ state \in [1..N -> {"Init", "Working", "Done"}]
/\ messages \in SUBSET Messages
/\ committed \in SUBSET Operations
Init ==
/\ state = [p \in 1..N |-> "Init"]
/\ messages = {}
/\ committed = {}
SendMessage(p, msg) ==
/\ state[p] = "Working"
/\ messages' = messages \cup {msg}
/\ UNCHANGED <<state, committed>>
Next ==
\/ \E p \in 1..N, msg \in Messages : SendMessage(p, msg)
Spec == Init /\ [][Next]_vars
====
2. Spec_mapping.txt - Explanation of program-to-TLA+ mapping:
The generated spec is a starting point. Refine it by:
Create a TLC configuration file (Spec.cfg):
CONSTANTS
N = 3
SPECIFICATION Spec
INVARIANT TypeOK
Run TLC model checker:
tlc Spec.tla -config Spec.cfg
Control the level of abstraction:
# Low abstraction (more detail, larger state space)
python3 scripts/generate_spec.py program.py -o Spec.tla --abstraction low
# Medium abstraction (balanced, recommended)
python3 scripts/generate_spec.py program.py -o Spec.tla --abstraction medium
# High abstraction (minimal states, protocol-level)
python3 scripts/generate_spec.py program.py -o Spec.tla --abstraction high
Medium abstraction (default):
Scenario: Implementing Raft or Paxos consensus algorithm.
Approach:
See: distributed_patterns.md
Scenario: Distributed system with processes communicating via messages.
Approach:
See: distributed_patterns.md
Scenario: Primary-backup or multi-master replication.
Approach:
See: distributed_patterns.md
Scenario: Implementing leader election algorithm.
Approach:
See: distributed_patterns.md
Extract only relevant functions:
python3 scripts/generate_spec.py system.py -o Spec.tla \
--focus-functions send_message receive_message commit_transaction
Explicitly specify state variables:
python3 scripts/generate_spec.py system.py -o Spec.tla \
--track-vars state messages committed_ops leader_id
Generated specs need refinement. Common refinements:
1. Complete action preconditions:
\* Generated (incomplete)
SendMessage(p, msg) ==
/\ messages' = messages \cup {msg}
\* Refined (with precondition)
SendMessage(p, msg) ==
/\ state[p] = "Active" \* Precondition
/\ msg \notin messages \* No duplicates
/\ messages' = messages \cup {msg}
/\ UNCHANGED <<state, committed>>
2. Add invariants:
\* Safety properties
SafetyInvariant ==
/\ \A p \in Procs : state[p] \in ValidStates
/\ Cardinality({p \in Procs : state[p] = "Leader"}) <= 1
\* Add to spec
INVARIANT TypeOK
INVARIANT SafetyInvariant
3. Add liveness properties:
\* Eventually reach consensus
PROPERTY <>[](\A p \in Procs : state[p] = "Committed")
\* Every request is eventually processed
PROPERTY \A req \in Requests : [](Submitted(req) => <>Processed(req))
4. Add fairness:
\* Weak fairness: continuously enabled actions eventually happen
Spec == Init /\ [][Next]_vars /\ WF_vars(ReceiveMessage)
\* Strong fairness: infinitely often enabled actions eventually happen
Spec == Init /\ [][Next]_vars /\ SF_vars(ElectLeader)
SYMMETRY Permutations(Procs) to reduce state spaceState explosion: TLC runs out of memory or takes too long.
Deadlock detected: TLC finds states with no enabled actions.
Invariant violated: TLC finds counterexample.
Spec too abstract: Properties are trivially true.
Take arabelatso/tlaplus-spec-generator from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.