Skip to content

Commit a17ac42

Browse files
committed
docs: README polish + migration-guide TransitionBudget callouts
README fixes: - Bump Go requirement 1.24 → 1.25 (matches go.mod). - Standardize on `defer interp.Close()` everywhere (was mixed Stop/Close/none across Quick Start, hierarchical, delayed, parallel examples). - Refresh "Additional Packages" table — adds ai, aiplugin, mcp tier notes, replaces "XState JSON exporter" with "Native + XState v5 JSON exporters", points generate at Native JSON. - Refresh "Design Philosophy" bullets — drops the "XState compatibility for free tooling" framing (taken naming space) in favor of statecharts + visualization + determinism + tier model. - Add MCP server "Inverting the loop" callout for the v1.4.0 ExposeInterpreter helper. Migration guides: - looplab/fsm guide adds explicit callouts to issues #40 (snapshot serialization) and #115 (cancellation recovery), plus a TransitionBudget reference. - qmuntal/stateless guide adds TransitionBudget reference for the runaway-halt pattern (#77). No code changes; tests still 33/33 green.
1 parent e845fc5 commit a17ac42

3 files changed

Lines changed: 20 additions & 9 deletions

File tree

README.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ These ship in v1.0 but reserve room to iterate within v1.x:
8989
go get github.com/felixgeelhaar/statekit
9090
```
9191

92-
Requires Go 1.24 or later.
92+
Requires Go 1.25 or later.
9393

9494
## Quick Start
9595

@@ -110,6 +110,7 @@ func main() {
110110
Build()
111111

112112
interp := statekit.NewInterpreter(machine)
113+
defer interp.Close()
113114
interp.Start()
114115

115116
fmt.Println(interp.State().Value) // "green"
@@ -135,6 +136,7 @@ machine, _ := statekit.NewMachine[struct{}]("editor").
135136
Build()
136137

137138
interp := statekit.NewInterpreter(machine)
139+
defer interp.Close()
138140
interp.Start()
139141

140142
fmt.Println(interp.State().Value) // "idle"
@@ -183,9 +185,9 @@ machine, _ := statekit.NewMachine[struct{}]("loading").
183185
Build()
184186

185187
interp := statekit.NewInterpreter(machine)
188+
defer interp.Close() // Always clean up timers
186189
interp.Start()
187190
// Timer starts automatically, canceled if LOADED received
188-
defer interp.Stop() // Always clean up timers
189191
```
190192

191193
## Parallel States
@@ -208,6 +210,7 @@ machine, _ := statekit.NewMachine[struct{}]("editor").
208210
Build()
209211

210212
interp := statekit.NewInterpreter(machine)
213+
defer interp.Close()
211214
interp.Start()
212215
interp.Send(statekit.Event{Type: "TOGGLE_BOLD"})
213216
// bold: on, italic: off (independent regions)
@@ -323,20 +326,24 @@ go install github.com/felixgeelhaar/statekit/cmd/statekit-mcp@latest
323326
| `validate_machine` | Validate a definition using lint rules |
324327
| `export_machine` | Export as JSON, Mermaid, or ASCII |
325328

329+
**Inverting the loop:** if you already have a typed `*statekit.Interpreter[C]` running in your service, `mcp.ExposeInterpreter` registers `<prefix>.send_event`, `<prefix>.get_state`, `<prefix>.get_context`, and `<prefix>.matches` so an MCP-speaking agent can drive your machine from outside.
330+
326331
The `visualize_machine` tool includes an interactive Vue.js + Cytoscape.js visualizer that MCP Apps hosts render inline — with dark mode, transition animations, and a full state history log. All JS dependencies are bundled inline for CSP-compatible rendering in any MCP host.
327332

328333
## Additional Packages
329334

330335
| Package | Description |
331336
|---------|-------------|
332-
| [`mcp`](./mcp) | MCP server for AI-assisted state machine management |
337+
| [`ai`](./ai) | LLM-driven transitions — `Drive` + `Tool` schema (Tier 2) |
338+
| [`aiplugin`](./aiplugin) | AI plugins — `TokenCounter`, `PromptRecorder`, `TransitionBudget` (Tier 2) |
339+
| [`mcp`](./mcp) | MCP server + `ExposeInterpreter` for agent-driven workflows (Tier 2) |
333340
| [`statetest`](./statetest) | Testing utilities: assertions, recorders, helpers |
334341
| [`debug`](./debug) | Runtime inspection and state graph analysis |
335342
| [`metrics`](./metrics) | Prometheus metrics for monitoring |
336343
| [`health`](./health) | Kubernetes liveness/readiness probes |
337344
| [`lint`](./lint) | Static analysis for detecting structural issues |
338-
| [`export`](./export) | XState JSON exporter |
339-
| [`generate`](./generate) | Go code generation from XState JSON |
345+
| [`export`](./export) | Native + XState v5 JSON exporters |
346+
| [`generate`](./generate) | Go code generation from Native JSON |
340347
| [`http`](./http) | HTTP handlers and middleware |
341348
| [`otel`](./otel) | OpenTelemetry tracing |
342349

@@ -376,9 +383,10 @@ statekit.NewInterpreter[C](machine) *Interpreter[C]
376383
## Design Philosophy
377384

378385
- **Go-first Execution** — Explicit, deterministic, testable
379-
- **Statecharts over FSMs** — Hierarchy enables complex behavior
380-
- **Visualization as a Feature** — XState compatibility for free tooling
381-
- **Small Surface Area** — Fewer features, better guarantees
386+
- **Statecharts over FSMs** — Hierarchy, parallel, history enable complex behavior without manual bookkeeping
387+
- **Visualization as a Feature** — Multiple renderers + XState v5 export for Stately Studio round-trip
388+
- **Determinism for tests** — Inject `FakeClock` to remove timer flakes
389+
- **Stable core, experimental edge** — Tier-1 surface follows semver; Tier-2 features (actor, persistent, distributed, MCP, AI) reserve room to iterate
382390

383391
## Documentation
384392

docs/migration-from-looplab-fsm.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,9 @@ When you exit `loading` (e.g., user cancels), the service's `context.Context` is
179179
- **Delayed transitions**`.After(30 * time.Second).Target("timeout")`. No goroutine bookkeeping.
180180
- **Visualization**`statekit viz door.json` (or via Go package) gives you a Mermaid / HTML / TUI diagram.
181181
- **Lint**`lint.Lint(machine)` reports unreachable states, dead ends, non-determinism, missing OnError on Invoke, etc.
182-
- **Snapshots** — pause/resume long-running workflows, persist them to a database.
182+
- **Snapshots** — pause/resume long-running workflows, persist them to a database. `Snapshot[C]` round-trips through `encoding/json` and `encoding/gob` (see [snapshot serialization tests](../snapshot_serialization_test.go)) — no more "FSM has no exported fields" pain ([looplab/fsm #40](https://github.com/looplab/fsm/issues/40)).
183+
- **Clean recovery from errors** — service errors route via `OnError`; the interpreter accepts events again immediately, no stuck `InTransitionError` ([looplab/fsm #115](https://github.com/looplab/fsm/issues/115)).
184+
- **Runaway prevention**`aiplugin.TransitionBudget` halts a misbehaving machine after N transitions.
183185
- **Test determinism**`WithClock(NewFakeClock(...))` removes timer flake.
184186

185187
## Step-by-step migration plan

docs/migration-from-qmuntal-stateless.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ Done().
182182
- **Lint** — catch structural bugs at build time.
183183
- **Visualization formats** — Mermaid, HTML, TUI, ASCII (not just DOT).
184184
- **MCP integration** — drive a running machine from a Claude / agent via tools.
185+
- **Runaway prevention out of the box**`aiplugin.TransitionBudget` halts a misbehaving machine after N transitions; addresses the pattern in [qmuntal/stateless #77](https://github.com/qmuntal/stateless/issues/77) directly.
185186

186187
## Migration plan
187188

0 commit comments

Comments
 (0)