开源工具通过状态机可视化帮助开发者构建更稳定、可预测的 agent 系统。
Agent 是建议,状态是法律。
状态机护栏控制你的 AI agent 在每个阶段可以使用哪些工具。定义一次工作流,在 Claude Code、Codex、Cursor、opencode 和 Pi 中强制执行。完整文档→
AI agent 很脆弱。给一个模型 40+ 个工具和一个开放式问题,它会重复读取同一个文件五次,在审查时调用 Edit,在测试通过前就部署。常见的解决方案是更大的模型和更长的 prompt……有时候有帮助。可观测性告诉你事后发生了什么,但不能预防问题。
与其让模型更大,不如让问题更小。
状态机约束工具空间和解决方案空间,使模型在每个步骤都在受约束的上下文中推理。规划状态只能使用只读工具。当 agent 过渡到实现阶段时,编辑工具解锁并拥有受限的 shell 访问权限。即使允许 Bash,写入重定向和破坏性操作仍然被阻止。测试只允许指定的测试命令。
调用当前阶段不可用的工具,你会收到一条拒绝消息,告诉你有哪些工具可用以及如何过渡。状态机可以循环和重试(不同于 DAG),这才是 agent 工作实际需要的。
适用于前沿模型和本地模型。在 13GB 以下,模型可以生成工具调用但无法保留足够的文件内容来进行准确的编辑。超过这个阈值,护栏开始将失败转化为成功。
安装到 Claude Code:
/plugin marketplace add statewright/statewright
/plugin install statewright
浏览器会打开→在 statewright.ai 注册→生成密钥→粘贴→完成。
然后启动一个工作流:
❯ start the bugfix workflow — fix the failing tests in calc.py
◆ statewright — statewright_start (workflow: bugfix)
◆ [statewright] Workflow activated: bugfix
◆ statewright — statewright_get_state (MCP)
◆ Current phase: planning. Let me read the code first.
Read 2 files
[statewright] planning => implementing
◆ statewright — statewright_transition (READY)
Edit calc.py: 1 line changed
[statewright] implementing => testing
◆ statewright — statewright_transition (DONE)
Bash: pytest -x — 7 passed
[statewright] testing => completed
◆ [statewright] Workflow complete. 46 seconds.
你也可以直接使用斜杠命令:/statewright start bugfix。
在我们的 5 任务 SWE-bench 子集(不是完整的 2294 个实例基准)中,两个本地模型从 10 次尝试中通过 2 次提高到通过 10 次,使用了 statewright 约束。相同的任务,相同的硬件。
*带有专门的 edit_line 工具适配 †在 5 个任务中的 2 个进行了测试(在初始实验运行后添加)
下限约为 13GB。在此以下,模型可以正确识别 bug,但无法序列化外科手术式编辑(它们会重写整个文件)。这是模型限制,不是我们的问题。
更大模型上的结构性优势是打破读取循环死亡螺旋并保持工具空间足够小,使模型能够推理而不是乱动。研究概要→
三个层次,每个都独立有用:
Engine (crates/engine) — Pure Rust 状态机求值器。状态、转移、守卫、工具限制。确定性的。循环中没有 LLM。无运行时依赖。
Engine (crates/engine) — Pure Rust 状态机求值器。状态、转移、守卫、工具限制。确定性的。循环中没有 LLM。无运行时依赖。
Agent 二进制文件 (crates/cli, binary: sw-agent) — 直接到 Ollama 的 agent 执行器。加载工作流,在受约束的循环中运行 LLM,强制执行工具访问,并流式传输结构化的 JSONL 事件。通过 --config 支持每个状态的模型路由,通过 --state 支持单状态执行(TUI 或 MCP 网关编排,sw-agent 每次执行一个状态然后退出)。
Agent 二进制文件 (crates/cli, binary: sw-agent) — 直接到 Ollama 的 agent 执行器。加载工作流,在受约束的循环中运行 LLM,强制执行工具访问,并流式传输结构化的 JSONL 事件。通过 --config 支持每个状态的模型路由,通过 --state 支持单状态执行(TUI 或 MCP 网关编排,sw-agent 每次执行一个状态然后退出)。
Plugin 层 (crates/mcp-gateway + plugins/) — MCP 网关与编码 agent(Claude Code、Codex、Pi 等)集成。当你激活工作流时,hook 强制执行每个状态的工具限制。模型看到 5 个工具而不是 30 个。它获得当前阶段的清晰说明和条件满足时的转移。statewright_run_agent MCP 工具为受益于直接 Ollama 执行的状态生成 Rust 二进制文件。
Plugin 层 (crates/mcp-gateway + plugins/) — MCP 网关与编码 agent(Claude Code、Codex、Pi 等)集成。当你激活工作流时,hook 强制执行每个状态的工具限制。模型看到 5 个工具而不是 30 个。它获得当前阶段的清晰说明和条件满足时的转移。statewright_run_agent MCP 工具为受益于直接 Ollama 执行的状态生成 Rust 二进制文件。
TUI (crates/tui, binary: statewright) 是一个 ratatui 终端界面,作为子进程生成 sw-agent 并实时渲染其 JSONL 事件流。它处理键盘输入、演示模式和夹具选择。
状态可以通过 model 字段指定要使用的模型。meta 中的 default_model 应用于没有显式覆盖的状态。支持程序化模型切换的客户端(Pi、Rust 工具)强制执行此规则;其他的则将其视为建议。
{
"meta": { "default_model": "claude-sonnet-4-20250514" },
"states": {
"diagnose": {
"model": "claude-haiku-4-5-20251001",
"allowed_tools": ["Read", "Bash"]
},
"propose_fix": {
"model": "anthropic/claude-opus-4-6",
"allowed_tools": ["Read"]
},
"execute": {
"allowed_tools": ["Read", "Edit", "Bash"]
}
}
}
在此示例中,diagnose 使用 Haiku(快速、廉价的侦察),propose_fix 升级到 Opus(高风险推理),execute 继承 default_model(Sonnet)。sw-agent 二进制文件还接受一个 --config 文件,其中包含 model_routing 块,用于每个状态的 Ollama URL、temperature 和上下文窗口覆盖。
使用 requires_approval: true 标记转移以暂停以供审查。网关默认为本地 UI 路由并在会话状态缓存中存储待处理的批准(包括其 approval_message)。客户端 hook 在转移后将该消息作为审查提示呈现;它们不阻止主机的 Stop hook。
当带外审查者拥有决策权时,将 meta.approval_mode 设置为"external"。在该模式下,客户端将待处理的批准留给该渠道,不呈现本地提示。Statewright 目前不提供 Telegram、Slack 或 Discord 分发器;外部集成必须通过网关回调/API 解决待处理的批准。
Codex、OMX 和 Claude Code hook 在转移后都刷新其缓存的工作流状态。当该缓存包含待处理的本地批准时,其 PostToolUse hook 要求主机 UI 呈现审查消息。其 Stop hook 刻意通过:它们不得隐藏或替换主机的批准提示。外部批准模式改为将该提示留给配置的集成。
| 特性 | 描述 |
|---|---|
| 中断 | 编辑与 glob 模式匹配的文件?自动过渡到验证状态,然后返回原位置 |
| 分叉/合并 | 顺序或并行运行分支,当全部(或任意)完成时合并 |
| 环境作用域 | 通过 blocked_env 隐藏 PROD_DB_URL,用 env_overrides 替换 |
| 会话隔离 | 通过 CLAUDE_SESSION_ID 的每个会话状态 |
| 每个状态的模型路由 | 将便宜的状态路由到小模型,昂贵的状态路由到前沿模型。每个状态的 model,meta 中的 default_model。 |
| 思考级别控制 | 每个状态的 thinking_level 字段(high、medium、low、off),用于支持推理努力调整的客户端。 |
| 工具升级检测 | 验证器在状态跳跃 2 个或以上权限级别时不带批准门控时发出警告 |
完整护栏参考见文档。
{
"id": "bugfix",
"initial": "planning",
"meta": {
"default_model": "claude-sonnet-4-20250514"
},
"states": {
"planning": {
"allowed_tools": ["Read", "Grep", "Glob"],
"model": "claude-haiku-4-5-20251001",
"thinking_level": "low",
"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" }
}
}
将 agent 指向 JSON 模式,它会通过 statewright_create_workflow 生成工作流。在可视化编辑器中调整工具、命令和环境块。
硬强制意味着工具调用在执行前在 hook 层被拦截。建议意味着规则被注入到上下文中,但模型不被阻止忽略它们。
*Pi 包括工具名称规范化和本地模型(Ollama、LM Studio)的工具调用恢复。
网关向连接的 agent 公开这些工具:
statewright.ai 的托管云处理工作流存储、运行历史和 MCP 网关。价格不会上升。
使用 Docker Compose 在本地运行完整堆栈——PocketBase、MCP 网关和工作流编辑器。自带 Ollama。自托管指南→
cd self-hosted && docker compose up --build
engine (crates/engine) 和 agent 层 (crates/agent) 使用 Apache 2.0 许可证,可嵌入,无运行时依赖。MCP 网关使用 FSL-1.1-ALv2(在 2029 年转换为 Apache 2.0)。单个开发者和单个团队自托管在 FSL 许可证下是允许的。
需要 agent 中的 MCP 支持(或针对非 MCP agent 如 Codex 的 hook)
工作流定义是手工编写的,尽管 agent 可以通过 statewright_create_workflow 生成它们
Cursor 强制是建议的,而不是硬强制。仅凭 MCP 无法在 Cursor 的架构中限制工具调用
研究结果来自 5 任务 SWE-bench 子集,不是完整的 2294 个实例基准
如果工作流过于限制性,agent 会卡住。statewright_deactivate 是逃生舱口
docs.statewright.ai — 安装指南、工作流编写、模式参考、MCP 工具参考和 agent 生成的工作流。
欢迎提供工作流定义、模板和 bug 报告。参见创建你自己的了解如何编写工作流。
Apache 2.0 — 部分 FSL-1.1-ALv2(在 2029 年 5 月 3 日转换为 Apache 2.0)。statewright.ai 的托管云。
此项目包括一份专利承诺,涵盖专利中所述技术的独立实现。无论是否使用 Statewright 软件,独立开发者、研究人员、开源项目和单个团队自托管部署都受到保护。
一个 hook 统治它们。