The crucible CLI
crucible is a headless command-line tool over a machine’s intermediate
representation (IR). It lints, renders, diffs, validates, and ejects a serialized
IR JSON document without running a single transition. It is the tooling face of
the serialization split: structure is data, so a
tool can reason about a machine’s shape from the IR alone.
Every command reads an IR JSON file path, or - to read from stdin. So a
machine written in Go becomes a CI gate: emit its IR with ToJSON, write it to a
file, and hand that file to the CLI.
m, err := state.ForgeFor[OrderContext]("order"). // ... states and transitions ... Quench()if err != nil { return err}
ir, err := m.ToJSON()if err != nil { return err}return os.WriteFile("order.json", ir, 0o644)Install
Section titled “Install”The CLI lives in the cmd/crucible module, versioned independently of state.
Build it from source with the Go toolchain:
go install github.com/stablekernel/crucible/cmd/crucible@latestOr build a local binary from a checkout:
go build -o crucible ./cmd/crucibleBehavior-free operation
Section titled “Behavior-free operation”A serialized IR carries behavior references by name only; the kernel binds those
names to real implementations when it assembles a machine. The commands that need
an assembled machine (lint, render, validate) do not have the host’s real
guards, actions, reducers, and services. They register a deterministic no-op stub
for every referenced name first, so the machine assembles from its structure
alone. The stubs never run — no instance is cast and no event is fired — so the
structural view is exactly what the IR describes.
Commands
Section titled “Commands”crucible lint order.jsonRuns every static analysis check and prints the findings. Exits non-zero when the analysis reports any finding, so it gates CI.
render
Section titled “render”crucible render order.json -format mermaidcrucible render order.json -format dot | dot -Tsvg -o order.svgRenders the machine as a Mermaid stateDiagram-v2 (the default) or as Graphviz
DOT. -format selects between mermaid and dot; the flag may appear after the
IR path. Output is text — pipe the DOT through Graphviz for an SVG.
crucible diff order-v1.json order-v2.jsonClassifies the changes between two serialized IRs, prints the recommended semver
bump (major, minor, or patch), and lists the breaking and additive changes
separately. This is the evolution check on the
command line: treat a machine definition as a schema and let the diff decide the
bump.
validate
Section titled “validate”crucible validate order.jsonConfirms the IR loads and assembles cleanly. A malformed JSON document or a
structural defect exits non-zero with a message on stderr; a clean machine prints
ok: <name> and exits zero. It is the well-formedness gate.
crucible eject order.json -package order -o behaviors.goGenerates typed Go behavior stubs for every referenced guard, action, reducer,
and service, plus a Provide function that registers them against a
state.Registry. -package sets the generated package name (default machine),
and -o writes to a file (default stdout). See Eject for what the
generated file contains and how to fill it in.
version
Section titled “version”crucible versioncrucible -versionPrints the CLI version.
Exit codes
Section titled “Exit codes”0success1runtime or load error, and lint findings2usage error
A non-zero lint or diff makes the CLI a drop-in CI gate: a failing analysis
or an unexpected breaking change fails the build.