statewright
- title
- statewright
- type
- toolbox
- summary
- Rust state machine that gates which tools an AI coding agent can call in each phase of its work
- tags
- rust, ai-agents, guardrails, mcp, claude-code
- language
- Rust
- license
- Apache-2.0 / FSL-1.1-ALv2
- created
- 2026-05-13
- updated
- 2026-05-13
Statewright is a Rust state-machine engine for AI coding agents that gates which tools are available in which phase. The agent declares a workflow (e.g. planning โ implementing โ testing โ completed); the engine enforces it per state. Tools outside the current state's allowed_tools are invisible to the model. Tagline: "Agents are suggestions, states are laws."
The thesis
Most agent failures are framed as model-quality problems and met with bigger models or longer prompts. Statewright argues the failure mode is the option space: a model with 40+ tools and an open-ended problem spends tokens on flailing instead of reasoning. Shrinking the available tool set per phase is the cheap intervention.
The research-results table in the README shows the effect on local models: in a 5-task SWE-bench subset, gpt-oss:20b (13.8 GB) and gemma4:31b (19.9 GB) both went from 2/10 to 10/10 with statewright constraints โ same hardware, same tasks. Below 13 GB models can call tools but can't hold enough file content for accurate edits, so the floor is set by the model, not the harness. Frontier models also use fewer tokens to completion.
How it works
The engine is a Rust crate (crates/engine, Apache-2.0, embeddable, no runtime deps) that evaluates state-machine JSON definitions: states, transitions, guards, tool restrictions. No LLM in the loop โ every decision is deterministic.
On top sits a plugin layer that wires the engine into the coding agent over MCP. Statewright registers MCP tools (statewright_start, statewright_get_state, statewright_transition, statewright_create_workflow, statewright_deactivate) and per-tool-call hooks enforce the current-state's allowed_tools. The model only ever sees the tools it's allowed to use in this state.
Guardrails per state
| Guardrail | Effect |
|---|---|
allowed_tools |
Tools invisible to the agent when not listed |
| Bash discernment | Blocks >> redirects, destructive ops (rm, shred), scripting interpreters in non-write states |
max_edit_lines |
Reject diffs exceeding the limit |
max_files_per_state |
Cap files edited per state |
allowed_commands |
Prefix-matched shell-command allowlist |
| Conditional transitions | Guards with predicates (eq, gt, exists) over context data |
requires_approval |
Pause for human review before a transition |
blocked_env / env_overrides |
Per-state env-var scoping |
CLAUDE_SESSION_ID |
Per-session state, multiple workflows in parallel |
A state-machine isn't a DAG โ states loop and retry (testing โ implementing on test failure), which matches how iterative agent work actually behaves.
Example workflow
{
"id": "bugfix",
"initial": "planning",
"states": {
"planning": {
"allowed_tools": ["Read", "Grep", "Glob"],
"max_iterations": 8,
"on": { "READY": "implementing" }
},
"implementing": {
"allowed_tools": ["Read", "Edit", "Write"],
"max_edit_lines": 20,
"max_files_per_state": 3,
"on": { "DONE": "testing" }
},
"testing": {
"allowed_tools": ["Read", "Bash"],
"allowed_commands": ["pytest", "cargo test", "npm test"],
"on": {
"PASS": { "target": "completed", "guard": "tests_passed" },
"FAIL_TEST": "implementing"
}
},
"completed": { "type": "final" }
},
"guards": {
"tests_passed": { "field": "test_result", "op": "eq", "value": "pass" }
}
}
Supported agents
| Agent | Integration | Enforcement |
|---|---|---|
| Claude Code | Hooks + MCP | Hard (protocol layer) |
| Codex | Hooks | Hard (alpha) |
| opencode | TypeScript plugin | Hard (alpha) |
| Pi | Skills extension | Hard (alpha) |
| Cursor | MCP + rules | Advisory (alpha) |
Hard = tool calls blocked at the protocol layer before the model sees them. Advisory = rules injected into context, model can still try. The Cursor case is a structural limitation โ MCP alone can't gate tool calls in Cursor's architecture.
Where it fits
Statewright is the structural answer to several recurring problems in the wiki:
- sandboxing-ai-agents โ Filesystem / network / HTTP / syscall isolation tells you what the agent can touch. Statewright is a fifth axis: what tools the agent can call, conditioned on phase. Crabtrap-style HTTP-policy and statewright-style tool-policy are layered defenses.
- skill-atrophy-supervision-paradox โ Constraining the agent in advance is the workflow Cohen's audit-discuss-execute enforces by human discipline, encoded as a machine-checkable spec.
- acceptance-criteria-ids / specsmaxxing โ
specs as IDs that agents reference backandstate-machines as IDs that agents transition throughare complementary moves toward navigable structure around the model.
The "bash discernment" guardrail (block >> and destructive ops in non-write states) is the same pattern hazmat hits via Seatbelt + pf at the OS layer โ statewright catches it earlier, before the call reaches the runner.
Pricing
Free tier (3 workflows, 200 transitions/month). Pro ($29), Team ($99). Engine is Apache-2.0 and self-hostable; single-developer and single-team self-hosting of the full stack is permitted under FSL-1.1-ALv2 (auto-converts to Apache-2.0 on 2029-05-03).
Limitations
- MCP is required for hard enforcement; Codex and opencode use hooks instead (alpha).
- Cursor support is advisory only โ MCP can't gate Cursor's built-in tools.
- Workflow definitions are hand-authored JSON; the
statewright_create_workflowMCP tool lets the agent generate them but the upstream schema still has to be loaded into context. - A too-restrictive workflow can leave the agent stuck;
statewright_deactivateis the escape hatch. - Research validation is a 5-task SWE-bench subset, not the full 2294 instances.
Quickstart (Claude Code, free tier)
/plugin marketplace add statewright/statewright
/plugin install statewright
/reload-plugins
Then say start the bugfix workflow or /statewright start bugfix. The first call asks for the API key from statewright.ai. (The README notes Claude may be cautious about pasted API keys โ confirm intent if it asks.)
Repo: https://github.com/statewright/statewright (Apache-2.0 / FSL, 88 stars, fresh). On the watchlist as a young single-vendor project.