State machines

The finite state machine is the oldest trick in reliable software: enumerate the states, enumerate the legal transitions, and make everything else impossible. Flat FSMs hit a wall as systems grow — the state count explodes combinatorially — which is exactly the problem Harel’s statecharts solved in 1987 (Harel 1987 (capture: clippings/harel87-statecharts.txt): state diagrams + hierarchy + concurrency + communication, turning diagrams into a compact, modular description language). SCXML is the W3C serialization of that idea; point an agent at it and the machine becomes locally reason-able — why @_dhamidi calls it the fix for distributed-systems pain and why the scxmljs demo rebuilds Pi Durable as statecharts-per-task (clippings/scxmljs-tinyactors-dev-demos-pi-durable-chapter-harness.md).

The library field (all captured)

  • xstate (OSS) (30.2k★, TS, MIT) — the reference implementation of the statecharts tradition: state machines + statecharts + actors for complex logic. Declarative machine definitions (states/events/guards/actions as data), hierarchical + parallel states, the actor model for machines-as-components, and actor-model persistence — the durable-execution angle. The JS ecosystem’s default; v5 moved hard toward the actor formalism. New (2026-10-02, @DavidKPiano announcement captured → clippings/x-2106046067858944010.md): a standalone XState FSM package is coming back (xstate@alpha) — minimal flat FSM at ~0.4 kB gzipped, strongly typed and visualizable. Notable as a scope reversal: after v5’s maximalist actor formalism, the author re-splitting a tiny core out is the transitions-style pragmatism arriving in the TS ecosystem — the full statechart when you need it, 0.4 kB when you don’t.
  • python-statemachine (OSS) (1.3k★, Python, MIT) — modern declarative/statechart-oriented Python: StateChart classes with compound states, parallel regions, history — the statecharts.dev feature set, sync and async, pythonic class-based declarations. Conceptually closest to XState: same declarative statechart model (states + events + guards + actions as first-class structure), different language.
  • transitions (OSS) (6.6k★, Python, MIT) — the pragmatic incumbent: “a lightweight, object-oriented FSM for Python with many extensions”. The architectural distinction: not a statechart language but a state-machine capability attached to your objects — Machine(model=YourClass) mixes states/transitions into existing instances; extensions (diagrams via graphviz, async support, hierarchies) bolt on. You think in your domain objects; the FSM is a feature of them, not the skeleton.

The architectural distinction (the reason both Python libs exist)

XState ↔ python-statemachine: the machine is the program — you declare a statechart as a standalone artifact (data), and it owns control flow. Benefits: serializable/introspectable definitions, formal statechart semantics (guards, actions, parallel regions), diagrams for free, and machine-as-data is what makes agent reasoning and persistence tractable.

transitions: the object is the program — your domain class keeps its identity and a state machine attaches to it. Benefits: zero rewrite cost for existing code, batteries-included pragmatism (6.6k★ of it), gradual adoption. Cost: the machine is structural convention, not a declared artifact — less introspectable, less statechart-formal.

Same split as declarative-vs-imperative everywhere: config-as-data (statecharts, Infrastructure as Code) vs code-with-behavior-mixed-in.

Why now (the agent angle)

The 1987 formalism is having a 2026 moment because explicit state is the agent bottleneck:

  • Local reasoning: a statechart is a closed, enumerable specification — an agent (or human) can determine “is this transition legal?” without simulating the program. Contrast implicit state scattered across flags and try-blocks.
  • Durable execution: Pi Durable’s “every task commits each step” is a statechart with storage; SCXML gives it a free, standard serialization.
  • Crosslinks: Musk engineering process step 1 (question requirements → fewer states) and step 2 (delete → fewer transitions) apply before any library choice; Agent tests — a state machine’s transition table is a ready-made property-test oracle; Performance engineering elimination ladder: the cheapest transition is the one you deleted.

The UI-workbench application (2026-10-11)

State enumeration escaped the backend: jakubkrehel skills (OSS)‘s /state-machine agent skill (7.8k★ repo, demo thread captured, 684❤) renders every state a component can be in on one throwaway page with mock data and a switcher — “the states are the branches the component already has” (loading/empty/error/typical/scrollable/mixed-pending, plan/role/flags), unreachable branches left out and listed. It is the same discipline this note is about, applied to component branches instead of protocol transitions: implicit state (scattered conditionals) made explicit and enumerable so a human works one state at a time with the rest a keypress away — and the workflow rule “re-check every state after each change, since a fix for one state often breaks another” is transition-table thinking in UI clothing.

Related: Markdown Slideshows-style “everything as reviewable artifacts” kin — machine-as-data diffs in a PR. Sources: clippings/x-2106041414874493256.md (Huntley) · clippings/x-2106036989032100153.md (_dhamidi) · clippings/harel87-statecharts.txt (paper OCR)