关于 ratchet
ratchet 是供 AI Agent 使用的副作用门控服务,在不可逆操作执行前记录持久化决策,限制重复尝试,并提供操作状态与额度策略。它不会执行操作,而是通过明确呈现重复、处理中、需审批或结果不确定等状态管理重试风险。
主要功能
- 01操作前请求执行许可
- 02按幂等键抑制重复操作
- 03记录处理中及不确定状态
- 04读取和解决操作记录
- 05按策略限制额度与尝试
- 06提供 REST 与 MCP 接口
适用场景
- 01避免重试导致重复发送邮件
- 02降低支付操作重复发起风险
- 03部署或发布前要求审批
- 04在结果不确定时要求核实
MCP 相关
ratchet 通过 Streamable HTTP 和 stdio 提供 MCP 服务,向客户端开放操作开始、报告、查询、解决、列表、策略和用量工具。MCP 服务记录决策,但不代为执行外部操作。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://ratchetgate.com/mcpclaude mcp add --transport http com-ratchetgate-ratchet https://ratchetgate.com/mcp{"mcpServers":{"com-ratchetgate-ratchet":{"type":"http","url":"https://ratchetgate.com/mcp"}}}在 Cursor 中打开{"servers":{"com-ratchetgate-ratchet":{"type":"http","url":"https://ratchetgate.com/mcp"}}}在 VS Code 中打开{"mcpServers":{"com-ratchetgate-ratchet":{"type":"http","url":"https://ratchetgate.com/mcp"}}}{"mcpServers":{"com-ratchetgate-ratchet":{"serverUrl":"https://ratchetgate.com/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
工具
15此工具无需参数。
详细介绍
AI Agent 的效果闸门。 Agent 在执行任何无法撤销的操作之前都会先询问——扣款、发布部署、发布软件包、发送邮件——并获得一项持久化决策,因此即使发生崩溃或重试,同一项现实世界操作最多也只会被尝试一次。Agent 还可以读取某次运行已经执行的操作,并在无法提高的限额内使用额度。
Agent 会重试。大模型的控制流具有非确定性,网络调用可能以模糊的方式失败,进程也可能在操作执行到一半时终止。结果就是重复发送邮件、重复扣款和重复写入——而整个技术栈中没有任何部分知道发生了什么。对于少数提供幂等键的供应商,供应商的幂等键有所帮助,但它们无法跨越独立的 Agent 进程或模型提供商。
Ratchet 不会执行你的操作。它会在操作之前保留一条持久化决策记录。
POST /v1/effects/begin → decision: execute | duplicate | in_flight
| blocked | approval_required | denied
只有 execute 会授权调用方执行操作。
项目文档
| 架构 | 高层设计——闸门是什么,以及它明确不是什么 |
| 保证论证 | 威胁模型、信任边界,以及每项安全要求的论证——包括哪些方面不在防护范围内 |
| 路线图 | 未来一年的计划,以及永远不会构建的内容 |
| 治理 | 由谁决策,以及他们停止履职时会发生什么 |
| 贡献指南 | 如何报告错误或提议更改 |
| 安全策略 | 如何报告漏洞,以及你会多快收到回复 |
| 行为准则 | 行为规范,以及应向谁反映问题 |
| 已知限制 | 所有目前尚不成立的事项,均如实说明 |
重要之处
如果进程在“开始”和“完成”之间终止,大多数系统会默默允许下一个调用方重试。
Ratchet 不会这样做。租约到期后,效果会变为 indeterminate——一个已知的未知状态,会被明确呈现出来,而非掩盖起来。接下来会发生什么,取决于你为该效果类型声明的策略:
on_indeterminate | 行为 | 适用场景 |
|---|---|---|
block(默认) | 不会自动重试。由人工或负责验证的 Agent 进行处理。 | 任何不可逆操作 |
retry | 授予一次新的尝试机会,最多不超过 max_attempts。 | 真正支持幂等的供应商 |
probe | 调用方必须先向供应商核实并记录证据。 | 扣款、转账、支付款项 |
在分布式系统中无法实现恰好一次交付,本项目也不声称能做到。Ratchet 所保证的是最多发起一次、记录操作结果供后续调用方重放,以及为无人承认的情况提供明确状态。
快速开始
要求:Node 20.11+、Docker(用于本地 Postgres)。
npm install
cp .env.example .env # defaults work for local development
npm run dev:db # Postgres on :5433 via Docker
npm run migrate
npm run dev # control plane on :8787
npm run dev:worker # lease reaper + webhook delivery (separate terminal)
然后打开 http://localhost:8787,或通过 shell 操作:
bash examples/curl/walkthrough.sh
npm run seed 会使用逼真的状态填充一个工作区——包括一个已完成的 effect、一个重复项、一个状态不确定的 effect,以及一个等待审批的 effect——这样控制台就有内容可显示。
或使用 Docker Compose
AUTH_SECRET=$(openssl rand -base64 32) docker compose up --build
核心循环
# 1. Ask, before you act.
curl -X POST http://localhost:8787/v1/effects/begin \
-H "Authorization: Bearer $RATCHET_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"effect_type": "email.send",
"idempotency_key": "welcome:user_123",
"payload": { "to": "[email protected]" },
"estimated_cost_micros": 800
}'
# → { "decision": "execute", "effect_id": "eff_...", "lease_token": "lt_..." }
# 2. Do the real thing, yourself. Ratchet never touches it.
# 3. Say what happened.
curl -X POST http://localhost:8787/v1/effects/eff_.../report \
-H "Authorization: Bearer $RATCHET_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "lease_token": "lt_...", "outcome": "succeeded",
"result": { "message_id": "msg_9f2" } }'
# Any later caller with the same key now gets:
# → { "decision": "duplicate", "result": { "message_id": "msg_9f2" } }
唯一规则: 只有在你确定操作没有到达外部世界时,才报告 failed。如果你不确定——比如发生超时或连接中断——就不要报告。租约会到期,Ratchet 会如实记录为 indeterminate。错误地报告 failed 比保持沉默更糟,因为这会允许重复操作。
幂等键
根据工作内容以确定性的方式派生键。
| 好的示例 | 错误的示例 |
|---|---|
welcome-email:user_123 | uuid4() |
invoice:2026-08:acct_88123 | "send-" + Date.now() |
pr:acme/api:feature-auth | f"job-{attempt_number}" |
每次尝试都会变化的键,会让每次重试看起来都是新工作。
Ratchet 无法访问时
Ratchet 位于你的关键路径上,因此集成前就要决定:发生故障时,Agent 是绕过门禁继续操作(fail-open),还是拒绝操作(fail-closed)。对于任何需要你道歉的操作,都使用 fail-closed;对于供应商本身就会去重的操作,则使用 fail-open。
完整契约、客户端模式以及如实说明的可用性策略:
docs/FAILURE_MODES.md。
架构
┌──────────────────────────────┐
agents ──────────▶│ control plane (stateless) │
REST + MCP │ Fastify · /v1 · /mcp · web │
└──────────────┬───────────────┘
│
┌──────────────▼───────────────┐
│ Postgres │
│ effects · policies · ledger │
│ spend windows · audit │
└──────────────▲───────────────┘
│
┌──────────────┴───────────────┐
webhooks ◀────────│ worker (long-running) │
│ lease reaper · delivery · GC│
└──────────────────────────────┘
控制平面是无状态的,可以横向扩展——它可以运行在无服务器基础设施上。worker 不可以。 无论请求是否正在处理中,它都会按计时器使租约过期;无服务器函数无法做到这一点。请将它作为长期运行的容器运行。运行多个副本是安全的(每次认领都会使用 FOR UPDATE SKIP LOCKED)。
至多一次由数据库唯一约束 (workspace_id, effect_type, idempotency_key) 强制保证,而不是依靠应用逻辑。
完整详情:docs/handoff/ARCHITECTURE.md。
部署
控制平面是无状态的,可以自由扩展。worker 不可以——无论是否收到请求,它都会按计时器使租约过期,因此必须作为长期运行的进程。正是这一限制排除了纯无服务器主机(Vercel、Netlify functions),尽管它们更简单;这也是 fly.toml 使用同一个镜像运行两个进程组的原因。
brew install flyctl && fly auth login # once, needs your browser
npm run deploy:fly
该脚本具有幂等性:它会创建应用、配置托管 Postgres、生成一次 AUTH_SECRET(绝不轮换,因为轮换会使所有 API 密钥失效)、部署两个进程,并验证就绪状态。只有通过预检后,它才会继续:
npm run deploy:preflight
预检会运行完整测试套件和生产构建,然后检查 AUTH_SECRET 是否足够强且不是开发环境默认值、是否设置了 PUBLIC_URL(否则清单会公开 localhost)、是否未设置 RATE_LIMIT_OVERRIDE、是否已关闭私有网络 webhook、CORS 是否未包含通配符,以及——如果选择了 Stripe——密钥和 webhook secret 是否都已提供。它不会打印任何密钥值。
任何容器平台都可以使用;只有 fly.toml 是 Fly 专用的。设置 DATABASE_URL、AUTH_SECRET、PUBLIC_URL、NODE_ENV=production,然后运行 node dist/api/server.js(可自由扩展)和 node dist/worker/main.js(至少运行一个,且始终保持运行)。
要在本地演练完全一致的生产容器:
AUTH_SECRET=$(openssl rand -base64 32) docker compose up --build
命令
| 命令 | 说明 |
|---|---|
npm run dev | 启动控制平面并启用重新加载 |
npm run dev:worker | 启动工作进程并启用重新加载 |
npm run dev:db / dev:db:down | 在 Docker 中运行本地 Postgres |
npm run migrate | 应用迁移(使用 advisory 锁;可安全并发运行) |
npm run seed | 使用逼真的状态填充工作区 |
npm test | 针对临时数据库运行类型检查、单元测试、集成测试和端到端测试 |
npm run test:unit / test:integration / test:e2e | 运行其中一个测试层级 |
npm run typecheck / lint | 以严格模式检查 TypeScript |
npm run build | 编译到 dist/ |
npm start / start:worker | 运行编译后的构建 |
npm run mcp:stdio | 通过 stdio 运行 MCP 服务 |
npm run openapi | 将 OpenAPI 文档写入磁盘 |
npm run deploy:preflight | 验证构建和配置是否可安全部署 |
npm run deploy:fly | 将控制平面、工作进程和数据库部署到 Fly.io |
npm run metrics | 根据定价审核阈值检查运营指标 |
npm run stripe:check | 报告支付配置并与 Stripe 验证 |
npm run stripe:listen | 将 Stripe 事件转发到本地实例并打印 webhook 密钥 |
npm run audit | 审核生产环境依赖 |
环境
所有变量及其默认值和安全说明都列在 .env.example 中。以下两个变量为必填项:
| 变量 | 说明 |
|---|---|
DATABASE_URL | Postgres 连接字符串 |
AUTH_SECRET | 32 个或更多随机字符。用于生成 API 密钥 pepper 和控制台会话 ID。轮换此值会使所有 API 密钥和会话失效。 |
在 NODE_ENV=production 环境中,如果 AUTH_SECRET 使用开发默认值或长度少于 32 个字符、CORS_ORIGINS 包含 *,或启用了 WEBHOOK_ALLOW_PRIVATE_NETWORK,进程将拒绝启动。
面向 Agent
| 接口 | 路径 |
|---|---|
| OpenAPI 3.1 | /openapi.json — 根据路由用于验证的架构生成 |
| 能力清单 | /.well-known/agent-manifest.json — 包括 Ratchet 不会执行的操作 |
| 机器文档 | /llms.txt |
| MCP 工具架构 | /mcp/info |
| MCP(Streamable HTTP) | POST /mcp,使用 Authorization: Bearer <key> |
| MCP(stdio) | npx -y ratchet-mcp,配合 RATCHET_API_KEY 使用 — 参见 packages/ratchet-mcp |
七个 MCP 工具:ratchet_begin_effect、ratchet_report_effect、ratchet_get_effect、
ratchet_resolve_effect、ratchet_list_effects、ratchet_get_policy、ratchet_get_usage。
可直接使用的配置和代码:examples/ — Python、TypeScript、curl、Claude Desktop、
Cursor,以及通过 HTTP 使用的通用 MCP。
安全状况
- 只存储载荷的 SHA-256 指纹,绝不存储载荷本身。
- API 密钥以使用服务器密钥进行 HMAC-SHA256 加 pepper 处理的形式存储;仅泄露数据库不会得到可用的密钥。比较采用恒定时间,并且即使前缀未知也会执行。
- 每次查询都限定在工作区范围内;跨租户查询会返回
404,不会泄露任何线索。 - 分两层防御 SSRF:先进行静态 URL 验证,再在每次尝试投递时重新解析 DNS,并将套接字固定到已检查的地址。绝不跟随重定向。
- Agent 提供的文本是数据,而非指令。决策来自已存储的策略和数据库状态;载荷中的任何内容都不能扩大范围、提高预算或更改策略。
- 拒绝未知请求字段,而不是静默丢弃。
尚未进行第三方审计。没有 SOC 2 报告,也没有渗透测试。
详情和威胁模型:docs/handoff/SECURITY_REVIEW.md。
定价
只有一项计费:受控效果——对给定的 (effect_type, idempotency_key),首次调用 begin。
重复请求抑制、进行中检查、重试、报告、读取、策略变更和 Webhook
均免费。产品旨在处理重试行为,因此你无需为此付费。
| 计划 | 价格 | 每月包含的效果数 | 超额费用 |
|---|---|---|---|
| Free | $0 | 1,000 | 每 1,000 次 $1.50,仅限预付余额 |
| Pro | $29/mo | 25,000 | 每 1,000 次 $1.50 |
| Custom | 联系我们 | 超过 250,000 | 协商确定 |
Free 计划用完额度后即停止服务,除非你充值预付余额;不会自动收取超额费用,也不会开具账单。 每月效果数超过约 19,300 次后,Pro 比在 Free 计划上使用预付余额更便宜,因此升级依据的是计算结果,而非人为设置的门槛。
只有两个计划,而不是三个:三个档位意味着我们已了解三个客户细分群体,但目前还没有使用历史数据支持这一判断。关于相关理由,包括为何之前的定价梯度让 20 倍的使用量范围都按同一价格计费,请参阅
docs/handoff/PRICING_AND_DISTRIBUTION_REVIEW.md。
超额费用从预付余额中扣除,因此失控的 Agent 会在余额耗尽时停止,而不会产生账单。成本模型和假设见:
docs/handoff/PRICING_AND_UNIT_ECONOMICS.md。
付款
Stripe 已完整接入:startCheckout 会创建真实的 Checkout Session,签名验证通过的
checkout.session.completed Webhook 会为账本充值。银行卡信息在 Stripe 自己的页面上输入,不会传到 Ratchet;只有签名验证通过的 Webhook 才会应用余额,绝不会因浏览器跳转到成功 URL 而充值。
开始结账前必须同时配置 STRIPE_SECRET_KEY 和 STRIPE_WEBHOOK_SECRET。仅配置密钥会选择 Stripe,但仍会关闭结账:收取付款却无法确认,会导致客户已付款但账户未获得余额。运行 npm run stripe:check 可查看具体配置情况(不会输出任何密钥值)。
本地开发时,无需公开 URL 即可获取 Webhook 密钥:
npm run stripe:listen # prints whsec_… ; put it in .env and restart
Stripe 的大部分入门检查清单并不适用。Ratchet 会直接内联构建订单项,从不读取你的 Stripe 商品目录,因此无需创建商品;它不使用 Stripe Invoicing;并且通过 API 创建 Checkout Session,而非使用无代码构建器。上线收款前需要完成的事项:验证账户(Stripe 的 KYC)、创建一个指向已部署 /v1/billing/webhook/stripe 的 Webhook 端点,并在生产环境中使用该端点的签名密钥;此外,还需决定是否需要收取税费(STRIPE_AUTOMATIC_TAX,默认关闭)。
如果完全没有 Stripe 凭据,则会改用内置测试适配器:不会扣款,也不会发出外部请求。目前仅在 Stripe 测试模式下完成验证——上线前请参阅
docs/handoff/KNOWN_LIMITATIONS.md,特别是有关退款的说明。
文档
| 文档 | 内容 |
|---|---|
PROJECT_MAP.md | 各项内容所在位置 |
ARCHITECTURE.md | 状态机、并发、部署拓扑 |
DECISIONS.md | 所有重要决策及其理由 |
API_AND_DATA_CONTRACTS.md | 端点、模式、错误代码 |
SECURITY_REVIEW.md | 威胁模型和已实施的控制措施 |
PRICING_AND_UNIT_ECONOMICS.md | 成本模型和场景 |
VALIDATION_REPORT.md | 测试和测量结果 |
KNOWN_LIMITATIONS.md | 尚未完成的事项及其所需工作 |
许可证
Apache-2.0。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。