Dev & Engineering xstatestate-machinestatechartllm-orchestrationworkflowtypescriptzodvercel-ai-sdk

Stately Agent

State-machine-powered LLM agents with XState: the machine owns control flow, the model only picks legal events, so invalid agent actions are impossible by construction.

FollowAgents review · FARS-2.1
Recommended
80/ 100 5-point scale 4.0 / 5
1 2 3 4 5 6
1Trust19 / 29 · 3.3/5

Least privilege: the machine admits only legal events and executors are plain functions; no elevated built-in permissions, score 2 (no demonstrated authz/tool-permission boundary for model callers). User confirmation: human-in-the-loop and approval states are referenced via docs/Chameleon, but no implementation shown in-sample — deducted. Data flow transparency: append-only journal with stateHash, mermaid architecture, machine never touches the model directly — score 3. Sensitive data handling: README does not address user data in prompts or key handling beyond tests forcing OPENAI_API_KEY empty — score 1. Dependency security: all extra peers optional with explicit ranges, CI uses frozen lockfile and minimal workflow permissions — score 2; no audit/SBOM. External effects: model calls and email sends live in app-level executors and tests avoid billed calls — score 2; no mandatory pre-send confirmation demonstrated. Rollback: snapshot migration and journal folding, failed appends leave the log untouched — score 2; no explicit rollback API. Source attribution: MIT LICENSE, clear author and repository fields — score 2; publisher unverified.

2Reliability12 / 14 · 4.3/5

Self-consistency: README, package., examples and tests describe runAgent/setupAgent/executors coherently; install comments match peer ranges — score 3. Dependency availability: xstate is an alpha (v6 alpha.46+) and ai@^7 matching is explained, score 2; the core dependency itself is pre-stable, an objective deduction. Failure messages: tests assert 'does not apply' 400s, 500 instead of TypeError, structured 'Invalid JSON' errors, and refusal to fabricate events from unparseable model responses — score 3.

3Adaptability15 / 18 · 4.2/5

Audience and scenarios: three starting points target distinct audiences; examples span games, email drafting, triage — score 3. Capability boundaries: 'the machine owns control flow, the model only picks a legal event' is a clear boundary, but alpha-API instability is only noted up top — score 2. Trigger precision: allowedEvents, guard rejection with retry, and illegal events leaving state unchanged are all test-proven — score 3. Environment fit: Node 22.18+, dual ESM/CJS builds, native workerd tests; Next/TanStack hosts appear only as typecheck targets without run verification — score 2.

4Convention15 / 18 · 4.2/5

Information architecture: README is well-structured with complete doc links — score 3. Install notes: cover the prerelease channel, peer-mismatch pitfall, and Node version — score 3. Naming stability: export map is thorough but the package is 2.0.0-alpha.22 with declared API churn — score 2. Examples and FAQ: eight named examples plus patterns and a LangGraph comparison — score 3; no explicit FAQ. Known limitations: alpha status declared, but storage/concurrency limits undiscussed — score 2. License: full MIT, consistent with package. — score 3. Versioning/changelog: changesets workflow present but no CHANGELOG content in-sample — score 2. Maintenance responsibility: author, repo URL, OIDC trusted publishing visible; maintainer team and response channels not shown — score 2.

5Effectiveness12 / 13 · 4.6/5

Output usability: typed zod outputs, typed events, clear result.status/output — score 3. Marginal value: constraining LLM actions with state machines is a genuine differentiator; guard-rejection-with-retry is hard to get for free elsewhere — score 3. Cost benefit: keyless scripted-executor testing, usage metering, and no-billed-call test design show cost awareness; but the xstate-alpha + Node 22.18 requirement is an adoption tax — score 2.

6Verifiability7 / 8 · 4.4/5

Claim traceability: README claims link to docs/examples, and tests map to documented durability/replay/400/500 behavior — score 3. Cross-source corroboration: README, package., CI, and Cloudflare tests agree on versions, executors, and the conformance suite — score 3. Fact/inference separation: factual claims are mixed with marketing language ('deterministic, inspectable') that is supported by architecture and tests but not fully proven — score 2.

Evidence confidence: Low Reviewed Sep 08, 2026 Reviewed revision 4c39d3681ded
Before you use it
  • Core dependency xstate is alpha and the package itself is 2.0.0-alpha.22 with declared API churn; pin exact versions for production.
  • No documented policy for sensitive data or prompt content; assess compliance before sending user data to models.
  • Publisher identity is unverified; npm trusted publishing (OIDC) exists but supply-chain auditing remains your responsibility.
  • Machine guards constrain only event selection; least-privilege enforcement for tool/network access inside executors must be built at the application layer.
  • Human-in-the-loop is referenced only via docs in-sample; verify the actual confirmation flow before relying on it.
Review evidence [1][2][3][4][5][6][7][8]
See the full review method →

What does this agent do, and when should you use it?

Stately Agent (repository statelyai/agent, MIT licensed) is a TypeScript library that models agent logic as XState state machines. The machine defines what the agent can do; your application chooses the model, runs requests, and stores state, while the model can only propose an event the machine accepts — guards reject illegal choices and retry the decision. The core package does not depend on any AI SDK; pluggable executors connect it to models, with an official Vercel AI SDK executor and scripted executors for keyless testing. State is represented as native XState snapshots, which are inspectable, persistable, and migratable. Version 2 is in alpha and its APIs may change before the stable release.

You define models, Zod-validated context/input/output, and typed events with setupAgent, then author a machine with guards and requests using createMachine. At runtime, runAgent starts the machine: when it reaches a decision state, the invoke with src: "agent.decide" issues a model request through an executor (e.g. openai("gpt-5.4-mini")); the model's proposed event is validated by machine guards before the transition fires, and rejected proposals trigger a retry. createScriptedExecutors runs the whole machine end to end with no API key for testing; defineModels from @statelyai/agent/ai-sdk supplies a default Vercel AI SDK executor, and custom executors are supported. Native XState snapshots are persisted in application code and migrated via XState's version/migrate contract.

  1. Teams needing hard, code-level limits on model authority, e.g. a refund agent where the model may propose an automatic refund but the $100 cap is enforced by a machine guard
  2. Developers retrofitting a hand-rolled while-loop agent into a machine, keeping their existing SDK calls and retry code as executors (docs/from-a-loop.md)
  3. Teams needing deterministic tests without API keys, driven via createScriptedExecutors
  4. Developers adopting known agent patterns — ReAct, reflection, plan-and-execute, RAG, supervisor — each documented as a single runnable file
  5. Long-running, resumable agent workflows persisted with native XState snapshots and snapshot migration
  6. Teams migrating from LangGraph, supported by docs/langgraph-comparison.md

What are this agent's strengths and limitations?

Pros
  • Guards reject illegal model choices at the code level, making out-of-bounds actions (like an over-limit refund) structurally impossible rather than prompt-dependent
  • The machine never talks to the model directly; executors (AI SDK, scripted, custom functions) can be swapped without changing the machine
  • End-to-end testing requires no API key; testing, inspection, and visualization fall out of the state-machine model
  • Native XState snapshots provide persistence, versioned migration, and framework-agnostic storage that runs anywhere
Limitations
  • Version 2 is in alpha; APIs may change before the stable release, creating adoption and migration risk
  • Requires Node.js 22.18+ and XState v6 alpha.46+, with xstate itself installed from the alpha channel
  • Strict major-version pairing between ai and provider packages (ai@^7 with @ai-sdk/openai@^4); mismatches cause install or runtime failures
  • Adopting it means rewriting control flow into a machine, a real migration cost; the README provides no independent benchmark evidence of performance gains

How do you install or deploy this agent?

Requires Node.js 22.18 or newer. Install the core: pnpm add @statelyai/agent@alpha xstate@alpha zod. For the optional Vercel AI SDK executor: pnpm add ai@^7 @ai-sdk/openai@^4. Provider packages must match the ai major version (@ai-sdk/openai@^4 pairs with ai@^7); a bare @ai-sdk/openai resolves to @latest and can mismatch the peer. The package is ESM-first, with CommonJS builds also published so require() works.

How do you use this agent?

1) Declare models (via defineModels, e.g. openai("gpt-5.4-mini")), context/input/output as Zod schemas, and events in setupAgent. 2) Author the machine with agentSetup.createMachine: in a decision state, use invoke: { src: "agent.decide" } with allowedEvents, and constrain transitions with guards (e.g. only allow AUTO_REFUND when amount <= 100). 3) Call runAgent(machine, { input: {...} }) and read result.output when result.status === "done". For tests, pass executors: createScriptedExecutors({ decisions: [...] }) to run offline. Model provider credentials are configured per the chosen AI SDK provider package.

How does this agent compare with similar options?

The README ships a dedicated document, docs/langgraph-comparison.md, for developers coming from LangGraph, positioning this library as a state-machine-centric alternative to LangGraph-style agent construction.

FAQ

Am I locked into a model provider?
No. The core package does not import the AI SDK; executors are supplied by the host, with an official Vercel AI SDK executor (example uses @ai-sdk/openai) and support for custom executor functions, so other providers can be integrated.
How do I test without an API key?
Use createScriptedExecutors with preset decisions (e.g. { decisions: [{ type: "AUTO_REFUND" }] }); the machine runs end to end with zero model calls.
What happens if the model proposes a disallowed action?
Machine guards reject the choice and the decision is retried — for example, choosing AUTO_REFUND for an amount above $100 is rejected.
Is it production-ready?
Version 2 is in alpha; the README states APIs may change before the stable release, so evaluate API-change risk before adopting.
How is state persisted and migrated?
Agents use native XState snapshots, persisted in application code, with migration via XState's version and migrate contract (see the snapshot-migration example).

Compare agents like this one

The same FARS review applied across the shortlist this agent qualifies for.

Related agents