XState JSON, unmodified
Export from Stately and run it. Nested, parallel, history, guards, delays, invoke, actors, tags, meta.
from xstate_statemachine import create_machine, Interpreter
machine = create_machine(json.load(open("order.json")))
interp = await Interpreter(machine).start()
One algorithm, two engines
Interpreter for asyncio, SyncInterpreter for everything else. Same core; cannot drift.
actionErrorPolicy: "rollback" restores state and context. strict refuses an undeclared event at the call site; strict_config refuses a misspelled key anywhere in the config. A runaway self-send chain is cut and stays on the record. Every policy, with a runnable example →
Time you control
Inject a Clock. SimulatedClock fires a 30‑second timeout in microseconds.
Ask, don't poll
await send("SUBMIT", wait=True) hands you a Receipt the moment the step has run. send_priority jumps the queue; the inbox is bounded with backpressure.
Receipt
state_ids={'submitted'}
changed=True
error=None
deferred=False
denied=False
Built-in MemoryStore / FileStore / SQLiteStore (Redis as an extra) behind one persisted() loop: optimistic or fenced locks so two workers never lose an update, an idempotency inbox that answers a replayed webhook with the original receipt, durable after timers a scanner wakes after a restart. What is exactly-once and what is not is written down on the Guarantees page.
[fastapi], [starlette], [litestar], [flask] (with its Quart shim), [django], [channels] and [drf] turn a chart into routes: one POST per event (OpenAPI from your Pydantic events on FastAPI and Litestar, drf-spectacular on DRF), receipts mapped to 200/409/422, SSE, WebSocket and Django Channels streams, a Django admin with CSRF-protected transition buttons, [sqlalchemy] columns and stores. authorize= is required, error bodies never leak exception text, and the core stays zero-dependency.
CloudEvents envelopes, a transactional outbox that commits with the snapshot, an inbound dispatcher with per-subject order and inbox dedup, dead letters with xsm dlq, sagas and choreography. Adapters for Redis Streams, Kafka, RabbitMQ, NATS and SQS, plus a Celery bridge for invoked tasks, Beat-driven durable timers and worker helpers.
[observability] emits OpenTelemetry spans and Prometheus metrics with label hygiene, structlog/loguru/Sentry hooks; a stdlib live inspector speaks the Stately wire protocol. [testing] ships pytest fixtures, state and transition coverage, Hypothesis strategies and replay() for audit logs.
Typed context
context_type=MyCtx flows a TypedDict to interp.context. A typo'd key is a checker error.
xsm generates typed Python (plus recorded tests, typed context, a plugin skeleton), inspects, simulates, diagrams and documents your machines. An interactive launcher on a terminal, plain text when piped — still zero dependencies.
Docs that run
Every Python block in the guide and the README is executed in CI. Every link is resolved. 78 runnable examples.
LLM agents, governed
The model proposes, the machine decides: per-state tool allow-lists, budgets, timeouts and durable human approval. Agents guide · vs LangGraph