{"schema_version":"1","name":"Ratchet","description":"An effect gate for AI agents. Before an agent performs a side effect it asks Ratchet for permission; Ratchet returns a durable decision — execute, replay a recorded result, wait, or stop — so the same real-world action is attempted at most once, stays inside a declared budget, and leaves an auditable record.","version":"0.1.0","documentation_url":"https://ratchetgate.com/docs","openapi_url":"https://ratchetgate.com/openapi.json","llms_txt_url":"https://ratchetgate.com/llms.txt","integrate_url":"https://ratchetgate.com/v1/integrate","oauth":{"protected_resource_metadata":"https://ratchetgate.com/.well-known/oauth-protected-resource","authorization_server_metadata":"https://ratchetgate.com/.well-known/oauth-authorization-server","dynamic_client_registration":true,"pkce_required":true,"code_challenge_methods":["S256"],"grant_types":["authorization_code","refresh_token"]},"api_base_url":"https://ratchetgate.com/v1","authentication":{"type":"bearer","header":"Authorization: Bearer <api_key>","alternate_header":"X-API-Key","obtain":"POST https://ratchetgate.com/v1/workspaces","scopes":["effects:begin","effects:report","effects:read","effects:admin","policies:read","policies:write","workspace:read"]},"mcp":{"protocol":"model-context-protocol","transports":{"stdio":{"command":"npx","args":["-y","ratchet-mcp"],"note":"Not yet published to npm; run from source with `npm run mcp:stdio`."},"streamable_http":{"url":"https://ratchetgate.com/mcp"}},"tools":[{"name":"ratchet_begin_effect","description":"Call this IMMEDIATELY BEFORE performing any side effect that touches the outside world (sending a message, charging a card, creating a resource, writing to someone else's system). Returns a decision you MUST obey:\n- \"execute\": you hold the lease. Perform the action now, then call ratchet_report_effect.\n- \"duplicate\": this action ALREADY HAPPENED. Do NOT perform it. Use the returned `result` as though you had just done the work.\n- \"in_flight\": another process is doing it right now. Do NOT perform it. Wait `retry_after_seconds` and ask again.\n- \"blocked\": an earlier attempt may or may not have taken effect. Do NOT perform it. Tell the user what is unresolved, or verify at the vendor and call ratchet_resolve_effect.\n- \"approval_required\": a human must approve. Do NOT perform it.\n- \"denied\": policy or budget refused it. Do NOT perform it.\nThe idempotency_key must be derived deterministically from the work itself so that a retry of the same logical action produces the same key. Never use a random value or the current time."},{"name":"ratchet_report_effect","description":"Call this IMMEDIATELY AFTER performing an action that ratchet_begin_effect authorised. Pass the lease_token you were given.\nReport \"succeeded\" with a result — future duplicate callers replay that result instead of repeating the action.\nReport \"failed\" ONLY when you are certain the action did NOT reach the outside world (for example, a validation error before the request was sent). That permits a clean retry.\nIf you are UNSURE whether it went through — a timeout, a dropped connection, an ambiguous error — do NOT report anything. Say so to the user. Letting the lease lapse records an honest \"indeterminate\", which is far safer than a false \"failed\" that licenses a duplicate."},{"name":"ratchet_heartbeat_effect","description":"Call this periodically during a long action you were authorised to perform, before the lease expires. It tells Ratchet you are alive and extends your hold.\nUse it when work turns out to take longer than the lease you asked for — a slow vendor, a large export, a retrying upload. Without it, the lease expires while you are still working, the effect is recorded as having an UNKNOWN outcome, and your report is then refused.\nIf it fails with lease_expired or lease_lost, STOP. Your hold is gone and the outcome is already recorded as unknown. Do not keep going and do not retry the action — call ratchet_begin_effect to find out where things actually stand."},{"name":"ratchet_check_effect","description":"Look up the recorded state of an action WITHOUT reserving a lease and without consuming your plan allowance. Use it to answer \"did I already do this?\" — for example when resuming after a crash, or when a user asks whether something went through. To actually perform work, use ratchet_begin_effect instead; this tool never grants permission."},{"name":"ratchet_resolve_effect","description":"Use ONLY after you have checked the third-party system and now know what really happened to an effect that was left \"indeterminate\". Record \"succeeded\" if the action did occur, \"failed\" if it did not, or \"cancelled\" to abandon it. Include how you verified it in `evidence`. Never guess: resolving incorrectly is exactly the duplicate or lost action this service exists to prevent."},{"name":"ratchet_list_effects","description":"Review recent effects for this workspace, optionally filtered by state or run. Use it to find unresolved work — filter by state \"indeterminate\" to see every action whose outcome is unknown and still needs verification."},{"name":"ratchet_get_policy","description":"Shows how this workspace has configured a given effect type: whether it is allowed, how long a lease lasts, the attempt ceiling, spend limits, and — most importantly — what happens when an attempt ends indeterminate. Check this before designing a retry strategy."},{"name":"ratchet_unwind_group","description":"Call this when a multi-step workflow fails partway and the steps that already succeeded must be undone — a booking made but not paid for, a resource created but not configured.\nReturns the exact compensations to perform, in the order to perform them, which is the REVERSE of the order they succeeded in. Undoing forwards can strand a step that depended on an earlier one.\nRatchet does NOT perform the compensations. For each step: call ratchet_begin_effect with the step's suggested_idempotency_key and compensates_effect_id, do the real undo, then call ratchet_report_effect. Gating the undo is what stops a retry from refunding twice.\nRead `unresolved` first. If any effect in the group has an unknown outcome, STOP and resolve it before undoing anything around it. Read `irreversible` too: those steps succeeded and declared no way to undo themselves, so a human has to decide what to do about them. Say so plainly rather than implying the rollback was complete."},{"name":"ratchet_group_status","description":"Shows every step in a multi-step unit of work: what succeeded, what can still be undone, what has already been undone, what is irreversible, and what has an unknown outcome. Use it to answer \"where did this workflow actually get to?\" after a crash, without changing anything."},{"name":"ratchet_usage","description":"Returns the current plan, remaining included effects for the month, prepaid credit balance, and today's declared external spend against each budget ceiling. Use it to warn a user before a long run exhausts an allowance or a budget."}]},"core_workflow":["POST /v1/effects/begin with an effect_type and a deterministic idempotency_key","Branch on `decision`: execute | duplicate | in_flight | blocked | approval_required | denied","If execute — perform the real side effect, then POST /v1/effects/{id}/report with the lease_token","If duplicate — replay the returned `result`; do not perform the action again","If blocked — a prior attempt is indeterminate; verify reality, then POST /v1/effects/{id}/resolve"],"capabilities":["at-most-once gating of side effects across processes, machines, and model providers","durable recorded results replayed to duplicate callers","leases with fencing tokens so a stalled worker cannot overwrite a newer attempt","explicit indeterminate state when an attempt neither completes nor cleanly fails","per-effect, per-key, and per-type daily external spend ceilings","operator approval gating for named effect types","signed webhooks with SSRF protection","immutable credit ledger and audit trail"],"does_not":["execute code, shell commands, or HTTP requests on the caller's behalf","store the raw payload of a gated effect (only a fingerprint is kept)","guarantee exactly-once delivery — that is not achievable; Ratchet guarantees at-most-once initiation and makes the unknown case explicit","hold customer funds or act as a payment processor for third-party effects","proxy, transform, or inspect the side effect itself"],"events":["effect.succeeded","effect.failed","effect.indeterminate","effect.approval_required","effect.approved","effect.rejected","effect.denied","budget.exceeded"],"pricing":{"meter":"gated_effect","free_tier_effects_per_month":1000,"plans_url":"https://ratchetgate.com/v1/billing/plans"},"limits":{"max_request_bytes":65536,"max_result_bytes":32768,"rate_limit_per_minute_by_plan":{"free":120,"pro":600,"scale":3000}}}