machina-inspect
machina-inspect parses your FSM config (or a live instance) into a directed graph IR, then runs structural checks against it. It’s the engine behind both the ESLint plugin and machina-explorer — but it’s also a standalone tool you can use programmatically.
Install
Section titled “Install”machina >= 6.0.0 is a peer dependency.
Quick start
Section titled “Quick start”Pass a config object or a live Fsm / BehavioralFsm instance — both work.
Checks
Section titled “Checks”machina-inspect runs three structural checks:
Unreachable states
Section titled “Unreachable states”BFS from initialState. Any state with no inbound path is reported. Both "definite" and "possible" edges count — if there’s any path at all, the state is considered reachable.
_onEnter loops
Section titled “_onEnter loops”DFS cycle detection on the subgraph of _onEnter transitions. Only reports cycles where every edge is unconditional. Conditional bounces like if (ctx.error) return "failed" are intentional patterns, not bugs.
Missing handlers
Section titled “Missing handlers”Collects the union of all input names across all states, then flags states that don’t handle inputs present elsewhere. States with a * catch-all are excluded. This check is best-effort — only inputs visible as graph edges are included.
Two-step usage
Section titled “Two-step usage”When you need the graph IR for other purposes (visualization, custom analysis), build it once and run checks separately:
This is the pattern machina-explorer uses — build the graph once, then feed it to both the check runner and the mermaid diagram generator.
Graph IR
Section titled “Graph IR”The StateGraph is the intermediate representation downstream tools consume:
Confidence levels
Section titled “Confidence levels”"definite"— Unconditional. String shorthands (timeout: "yellow") and functions with a single top-level return."possible"— Conditional. Returns insideif,switch, ternary, logical expressions, ortryblocks.
Handler functions are analyzed via acorn AST parsing of handler.toString(). Non-string returns, template literals, and variable references are ignored — the analysis is best-effort, not exhaustive.
Child FSMs
Section titled “Child FSMs”_child declarations are followed recursively. Child graphs appear in StateGraph.children, keyed by the parent state name. Each child is analyzed independently with its own initialState and reachability scope.
See also
Section titled “See also”- machina-test — Jest/Vitest custom matchers built on machina-inspect’s graph analysis
- ESLint plugin — get these checks inline in your editor
- machina-explorer — paste-and-analyze browser UI