An effect gate for AI agents: ask before you act, so the same side effect happens at most once.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent β or use 1-click editor setup below.
We haven't yet run this listing's install command through our automated sandbox check. This isn't a red flag β we're steadily working through the catalog.
π‘ Paste the JSON block into your client's configuration file under mcpServers, then restart the application.
An effect gate for AI agents. Your agent asks before it does anything it cannot take back β charge a card, ship a deploy, publish a package, send the email β and gets a durable decision, so the same real-world action is attempted at most once across crashes and retries. Agents can also read back what a run already did, and spend against a limit they cannot raise.
Agents retry. LLM control flow is non-deterministic, network calls fail ambiguously, and processes die mid-action. The result is duplicate emails, double charges, and repeated writes β and nothing in the stack knows which. Vendor idempotency keys help for the few vendors that offer them, and never across separate agent processes or model providers.
Ratchet does not execute your actions. It holds a durable decision record in front of them.
Only execute authorises the caller to act.
| Architecture | High-level design β what the gate is and what it deliberately is not |
| Assurance case | Threat model, trust boundaries, and the argument for each security requirement β including what is not defended |
| Roadmap | What the next year holds, and what will never be built |
| Governance | Who decides, and what happens if they stop |
| Contributing | How to report a bug or propose a change |
| Security policy | How to report a vulnerability, and how fast you hear back |
| Code of conduct | What is expected, and who to tell |
| Known limitations | Everything that is not true yet, stated plainly |
If your process dies between "go" and "done", most systems quietly let the next caller retry.
Ratchet won't. The lease expires and the effect becomes indeterminate β a known unknown,
surfaced instead of buried. What happens next is the policy you declared for that effect type:
on_indeterminate | Behaviour | Use for |
|---|---|---|
block (default) | No automatic retry. A human or verifying agent resolves it. | Anything irreversible |
retry | A fresh attempt is granted, up to max_attempts. | Vendors that are genuinely idempotent |
probe | Caller must verify at the vendor and record evidence first. | Charges, transfers, payouts |
Exactly-once delivery is not achievable in a distributed system and this project does not claim it. What Ratchet guarantees is at-most-once initiation, a recorded outcome that later callers replay, and an explicit state for the case nobody else admits exists.
Requirements: Node 20.11+, Docker (for local Postgres).
Then open http://localhost:8787, or drive it from the shell:
npm run seed populates a workspace with realistic state β a completed effect, a duplicate, an
indeterminate one, and one awaiting approval β so the console has something to show.
The one rule: report failed only when you know the action did not reach the outside world.
If you are unsure β a timeout, a dropped connection β report nothing. The lease lapses and Ratchet
records an honest indeterminate. A false failed is worse than silence, because it licenses a
duplicate.
Derive the key from the work, deterministically.
| Good | Broken |
|---|---|
welcome-email:user_123 | uuid4() |
invoice:2026-08:acct_88123 | "send-" + Date.now() |
pr:acme/api:feature-auth | f"job-{attempt_number}" |
A key that changes on every attempt makes every retry look like new work.
Ratchet sits in your critical path, so decide this before integrating: on an outage your agent either acts without the gate (fail-open) or refuses to act (fail-closed). Use fail-closed for anything you would have to apologise for; fail-open where the vendor deduplicates anyway.
Full contract, client patterns, and the honest availability posture:
docs/FAILURE_MODES.md.
The control plane is stateless and scales horizontally β it may run on serverless infrastructure.
The worker may not. It expires leases on a timer whether or not a request is in flight; a
serverless function cannot do that. Run it as a long-running container. Multiple replicas are safe
(every claim uses FOR UPDATE SKIP LOCKED).
At-most-once is enforced by a database unique constraint on
(workspace_id, effect_type, idempotency_key) β not by application logic.
Full detail: docs/handoff/ARCHITECTURE.md.
The control plane is stateless and can scale freely. The worker cannot β it expires leases on a
timer whether or not a request arrives, so it must be a long-running process. That single
constraint rules out purely serverless hosts (Vercel, Netlify functions) despite their being
easier, and is why fly.toml runs both process groups from one image.
The script is idempotent: it creates the app, provisions managed Postgres, generates AUTH_SECRET
once (never rotating it, since that would invalidate every API key), deploys both processes, and
verifies readiness. It refuses to proceed unless preflight passes:
Preflight runs the full suite and production build, then checks that AUTH_SECRET is strong and
not the dev default, PUBLIC_URL is set (otherwise the manifest would advertise localhost),
RATE_LIMIT_OVERRIDE is unset, private-network webhooks are off, CORS carries no wildcard, and β
if Stripe is selected β that both the key and the webhook secret are present. It prints no secret
values.
Any container platform works; only fly.toml is Fly-specific. Set DATABASE_URL, AUTH_SECRET,
PUBLIC_URL, NODE_ENV=production, then run node dist/api/server.js (scale freely) and
node dist/worker/main.js (at least one, always on).
To rehearse the exact production containers locally:
No reviews yet β be the first to share how this listing worked for you.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/ratchet)<a href="https://allmcps.com/mcp/ratchet"><img src="https://allmcps.com/api/badge/ratchet?style=directory" alt="Ratchet on AllMCPs" /></a>