Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Installation & Quick Start

Install

# macOS (Homebrew)
brew tap charly-vibes/charly
brew install specodelic

# Linux / macOS (binary download — all five release targets, see checksums.txt)
# Grab the archive matching your platform from:
# https://github.com/charly-vibes/specodelic/releases/latest
#   specodelic_{VERSION}_linux_{amd64|arm64}.tar.gz · specodelic_{VERSION}_darwin_{amd64|arm64}.tar.gz
tar xz specodelic_*_linux_amd64.tar.gz && sudo mv specodelic spk /usr/local/bin/

# Windows (Scoop)
scoop bucket add charly https://github.com/charly-vibes/scoop-charly.git
scoop install specodelic

# Any platform (Cargo)
cargo install specodelic

(Rust stable toolchain; published on crates.io.) Installs two binaries: specodelic and its alias spk.

Quick start

All output below was captured verbatim from specodelic 0.11.0. On a TTY the tool prints human-readable text (shown here); when stdout is piped it emits a JSON envelope instead.

# Scaffold a spec — the template teaches its own tables
spk new order.cancel --file order.cancel.md
created order.cancel.md
→ Run: specodelic lint order.cancel.md

(--file picks the target path; without it the scaffold lands in the openspec tree at openspec/specs/<cap>/spec.md, which must already exist.)

# Lint it — findings carry their own rule id + semantics
spk lint order.cancel.md
lint: 1 file(s) linted, 0 finding(s), 0 advisory warning(s)
→ Run: specodelic graph

What a finding looks like. A typical first edit — replacing the file-qualified wiki-link in the traces_to column with bare text — is a real mistake, and lint reports it:

spk lint order.cancel.md
lint: 1 file(s) linted, 1 finding(s), 0 advisory warning(s)
  order.cancel [linter.single_root_reachable] 4 row(s) unreachable from any intent row — an orphaned island (traces_to/derives_from/guard/from-to/emits): order.cancel.c1, order.cancel.initial, order.cancel.p1, order.cancel.t1
→ Run: fix the reported invariants — each rule's semantics: spk explain lint-rules

That is linter.single_root_reachable hard-failing: every row must reach its file’s own intent row through own-file typed links, and bare text is not a wiki-link — so c1 loses its reachability path and drags the state, transition, and property hanging off it down as one orphaned island.

# Derive the reference graph (fan-in/out, dangling links)
spk graph order.cancel.md
graph: 1 file(s), 5 node(s), 5 edge(s), 0 dangling, 0 typing violation(s), 0 supersedes cycle(s), 0 external boundary(ies)
→ Run: specodelic lint
# Compile to artifacts: TOML + proptest scaffolding + TLA+ module
spk compile order.cancel.md --out-dir specodelic/
compile: 1 compiled, 0 failed
  order.cancel.md [order.cancel] → specodelic/order.cancel.toml, specodelic/order.cancel_props.rs, specodelic/order.cancel.tla
→ Run: specodelic verify (consumes the *_props.rs artifacts)
# Model-check the compiled module (embedded stateright backend)
spk model-check order.cancel.md
model-check: 1 checked, 0 failed
  order.cancel.md [order.cancel]: exploration_only (1 states explored) → specodelic/order.cancel.check.json
    claims: 0 evaluated, 1 unchecked, 0 blocking
      unchecked: c1
→ Run: specodelic verify (consumes the *.check.json reports)

In an existing workspace

spk doctor        # diagnose the workspace (self-hosting vs consumer mode)
spk init          # write the SPECODELIC managed block into AGENTS.md
spk explain       # the embedded format guide — ten topics, no repo access needed
spk feedback      # send feedback about the tool

Self-hosting

This repo’s own corpus (openspec/specs/ — the single tree, specodelic-jf1) is linted by the tool itself:

just lint-specs   # spk lint openspec/specs
just ci           # fmt-check + clippy + tests + release build + openspec gates