quint-co/quint/quint-modeling

Claude Code and agent skill by quint-co/quint

Trust tier 3
  • community
Source check pending

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-modeling

SKILL.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 pointFlowGuideline
Only an idea / informal proposal, built interactively with the userfrom nothingguidelines/from-nothing.md
A written requirements / functional-spec documentfrom requirementsguidelines/from-requirements.md
Source code (Rust, Go, TypeScript, …)from codeguidelines/from-code.md
An existing TLA+ specificationfrom TLA+guidelines/from-tlaplus.md
A finished `.qnt` spec to audit, not buildreviewguidelines/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.)

ExampleCoordinates 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.qntshared 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:

ConcernQuestions to answer
CommunicationHow 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.)
FailuresCrash-stop? Crash-recovery? Byzantine? What fraction f of n?
TimeSynchronous? Asynchronous? Partial synchrony? Are timeouts modelled?
Actors / ParticipantsWho 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 var for 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:

quint
type State = {
phase: str,
balances: NodeId -> int,
members: Set[NodeId],
}
var state: State

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:

quint
type NodeId = int
type LocalState = { phase: str, balance: int, voted: bool }
var nodes: NodeId -> LocalState // per-actor cohesive state
var messages: Set[Message] // genuinely global concern → its OWN var, not inside LocalState
One instanceN instances
state varvar state: Statevar nodes: NodeId -> LocalState
pure fnscan…(State, …): bool + apply…(State, …): Statecan…(LocalState, …): bool + apply…(LocalState, …): LocalState — same shape
action readreads statenodes.get(id)
action writestate' = applyOp(state, …)nodes' = nodes.set(id, applyOp(nodes.get(id), …))
initone record literalNODES.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

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
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/quint-co/quint/quint-modeling/badge)](https://verified-skill.com/skills/quint-co/quint/quint-modeling)

Something wrong with this skill or its page? Tell us.