quint-co/quint/quint-modeling
Claude Code and agent skill by quint-co/quint
- community
Checking that the SKILL.md file is still in the repository.
Build a Quint model of a system, protocol, or algorithm. Use whenever the user wants to model, spec out, formally describe, model-check, or verify a system in Quint — e.g. "model this protocol in Quint", "spec out this design", "translate this TLA+", "formally check this Rust code" — even if they never say "specification." If the goal is to verify or model-check a design and no Quint model exists yet, writing it is the required first step, so start here. It generates the spec from whatever the user has — an idea, requirements, source code (Rust, Go, TypeScript, etc.), or an existing TLA+ spec — and walks the modelling flow (state, actions, invariants), adapting to the source. Also use this to **review or audit an existing Quint spec** — "review my .qnt", "is this model any good" — it carries the review checklist. For pure Quint syntax/CLI/debugging questions with no new model to build, use quint-lang instead.
Install
npx vskill@latest install quint-co/quint/quint-modelingSKILL.md
Quint Modelling
Produce a Quint specification from whatever the user starts with. This skill owns the shared modelling discipline (below) and routes to a flow-specific guideline for the intake — the part that turns a particular kind of input into the understanding the shared steps build on.
For language syntax, operators, the CLI, and basicSpells, defer to the quint-lang reference. This skill is about how to model, not Quint syntax.
Pick the flow
Identify what the user is starting from, then read the matching guideline. The guideline handles intake — extracting the system's state, operations, and assumptions from that source. After intake, everyone converges on the Shared modelling spine below.
| Starting point | Flow | Guideline | |
|---|---|---|---|
| Only an idea / informal proposal, built interactively with the user | from nothing | guidelines/from-nothing.md | |
| A written requirements / functional-spec document | from requirements | guidelines/from-requirements.md | |
| Source code (Rust, Go, TypeScript, …) | from code | guidelines/from-code.md | |
| An existing TLA+ specification | from TLA+ | guidelines/from-tlaplus.md | |
| A finished `.qnt` spec to audit, not build | review | guidelines/review.md |
The first four are build flows: intake → the Shared modelling spine below. The review flow is different — there is no new model to produce; you audit an existing spec against a checklist and report findings. It does not use the spine; read guidelines/review.md and follow it directly.
If the starting point is ambiguous (e.g. "a design doc with some pseudocode"), ask the user which source is authoritative before picking — the intake differs materially.
Shared modelling spine
Every flow lands here. Intake (flow-specific) produces an understanding of the system: its entities, the operations they perform, the state each operation reads and writes, and the system-model assumptions (communication, failures, time, participants). The spine turns that understanding into a verified Quint spec.
Two principles hold throughout:
- Executable from the first line. Quint specs run immediately — you validate design
decisions as you make them, not at the end. Never build more than one step without verifying the previous one: quint typecheck, then `quint run`. Typecheck is not enough — a spec can typecheck and still fail to execute, which defeats the whole point of an executable spec. The trap to watch for: a `const` not given a value typechecks but cannot run — quint run fails with Uninitialized const. To make the spec runnable, instantiate the const in a concrete instance module — module spec_3 { import spec(C = Set(1,2,3)).* } — and run that module. (assume documents a premise; it does not supply a value — see Step 1 and quint-lang's guidelines/simulations.md.) After each addition, actually run it — if you can't quint run the module, it isn't done. Use `quint run` only — never `quint verify`. This holds for the whole skill: building, iterating, reviewing, sanity-checking invariants — every step uses sampled quint run, not once quint verify, not even as a final pass. verify is exhaustive bounded model checking (Apalache): far slower (minutes to hours) and not part of the modeling workflow. It is a model-checking tool, documented in quint-lang (guidelines/cli.md, guidelines/simulations.md) — reach for it only when the user explicitly asks to model-check the spec, never on your own.
- What, not how. Model observable state transitions and their effects. Abstract away
implementation detail (serialization, memory management, retry plumbing). If a detail doesn't affect an invariant you care about, it doesn't belong in the spec.
Reference examples
Two complete, runnable specs are bundled in examples/, one for each of the two ways components coordinate — by passing messages or by sharing state. Almost any system maps onto one of them; pick by that question, not by domain label, and read the closer match as a worked instance of the spine patterns (Step 2 state-shaping, Step 4 guarded actions, Step 5 witnesses + invariants) — to see how the pieces compose into a whole spec. (They are canonical shapes to learn from, not the only valid ones.)
| Example | Coordinates by… | Read it when modelling… | |
|---|---|---|---|
examples/tendermint/ | message passing (choreo:: broadcast/send; real BFT consensus) | any distributed protocol where parties exchange messages — consensus, BFT, replication, atomic commit, leader election, reliable broadcast/gossip, request/response, a mempool. This is the default reference for distributed systems. Shows: grouped Id -> LocalState (Step 2), guarded transitions (Step 4), choreo::cue listen/act split, safety invariants (agreement/validity) + an accountability/liveness angle + a counterexample demo (Step 5), const-instantiation, and test separation. Its banner has a "quick read" path so you needn't read all ~760 lines. See also Step 2's "When to use Choreo" and ../quint-lang/guidelines/choreo.md. | |
examples/ewd426.qnt | shared state (no messages) | systems whose parts coordinate through common state rather than messages — mutexes/locks, token rings, shared registers, self-stabilization, anything where a process reads its neighbours/the environment directly. Shows: grouped-map state (Step 2), guarded step (Step 4), const-instantiation, and temporal liveness properties (Step 5). |
If a system has both (e.g. message-passing nodes that also touch a shared ledger), start from tendermint (the message-passing structure dominates) and add shared state as its own var, per Step 2. Plain message soup (Set[Msg]) without the Choreo framework isn't a separate file — Choreo's broadcast is soup underneath, so tendermint/ is also the reference for that shape (read the state decls + a guarded transition; the choreo:: wrapper is the only added layer).
Step 1 — Separate concerns
Partition the understanding into three layers. Keeping them apart is what makes a spec testable; mixing them is the most common source of untestable specs.
- State machine — variables, initialization, transitions →
var,init, actions - Functional logic — pure computations: guards, quorum checks, state updates →
pure def - Properties — what must always hold, what must be reachable, what must eventually happen →
val invariants + witnesses, plus temporal properties for liveness (Step 5; quint-lang has the detail)
Also pin down the system-model assumptions — they shape every invariant built on top. Encode them as `const` declarations. To actually check an assumption (e.g. a quorum condition like 2 * f < n), write a `run` test that asserts it — the assume keyword documents a premise but is not enforced, so don't rely on it as a check (see quint-lang's ## Assume for why and the run-test pattern). Each flow's intake fills this in from its own source (interview, requirements doc, code, or TLA+); the checklist is the same regardless:
| Concern | Questions to answer | |
|---|---|---|
| Communication | How do the actors communicate — messages or shared state? If messages: reliable or lossy? ordered or unordered? broadcast or point-to-point? (The other shaping question — answer it right after actors; it picks the message medium in Step 2 and, with the actor count, settles the Choreo decision.) | |
| Failures | Crash-stop? Crash-recovery? Byzantine? What fraction f of n? | |
| Time | Synchronous? Asynchronous? Partial synchrony? Are timeouts modelled? | |
| Actors / Participants | Who are the actors and roles, and what local state does each hold? (This is the most concrete intake question — answer it first; it feeds Step 2's Id -> LocalState shaping directly.) Fixed membership or dynamic? How many processes? |
If an assumption is wrong, every property built on it is wrong — surface them before building.
Step 2 — Shape the state
Start from the two questions you answered in Step 1 — *who the actors are* and *how they communicate*. Together they drive every structural decision this step makes. They are not just background; they pick the shape, the message medium, and the framework:
- How many actors → the state shape. One actor → a single
var s: Record. N actors of the
same kind → one Id -> LocalState map (the record describes one actor; see "Scaling to N" below). Distinct roles → either a field on LocalState (e.g. role: Coordinator | Participant) or separate maps. Get the actor count/roles right and the shape falls out.
- How actors communicate → the message medium. Messages → a separate
varfor the medium,
not crammed into LocalState: unordered Set[Message] soup (the default), or ... -> List[Message] ordered per-pair queues only when delivery order is load-bearing. No messages, coordination through common state → shared memory (no medium var; see examples/ewd426.qnt). This is the "Communication shapes" choice detailed just below.
- Actors + communication → Choreo or not. Multiple actors coordinating by **exchanging
messages → default to Choreo (see "Default to Choreo" below). A single actor, or actors coordinating through shared state** → plain Quint. So answer "who, how many, and how do they talk?" first, and all three decisions below are mostly settled before you write a type.
Group cohesive state into a record and let the functional layer operate on that record — this is the recommended shape, because most of the time the variables that describe one entity are cohesive, and grouping keeps the functional layer clean and the invariants readable. Keeping variables flat is the deliberate exception, not a co-equal default:
- Group into a record when the fields are the local state of one entity (a node's phase + log +
vote), are always passed together, or an invariant relates several of them. This is the usual case.
- Keep flat (separate `var`s) only when the variables are genuinely independent concerns that
change on their own, or the spec is small enough that grouping adds no clarity. (Some canonical examples, e.g. ewd840, keep per-field maps flat because the fields don't form an obvious unit.)
The cohesive case — one unit:
The apply… pure functions take and return State; actions assign the next-state record directly (state' = applyTransfer(state, …)). No per-field reassembly.
Scaling to N instances — when there are N actors, the record describes one actor's local state, and the variable becomes a map keyed by actor id. The pure functions are unchanged — they still operate on a single LocalState; only the wiring around them changes:
| One instance | N instances | ||
|---|---|---|---|
| state var | var state: State | var nodes: NodeId -> LocalState | |
| pure fns | can…(State, …): bool + apply…(State, …): State | can…(LocalState, …): bool + apply…(LocalState, …): LocalState — same shape | |
| action read | reads state | nodes.get(id) | |
| action write | state' = applyOp(state, …) | nodes' = nodes.set(id, applyOp(nodes.get(id), …)) | |
init | one record literal | NODES.mapBy(_ => <record>) |
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 95 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/quint-modeling/SKILL.md
Popularity
- 7-day trend score
- 0
Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/quint-co/quint/quint-modeling)