Isn't this just idempotency keys?
Isn't this just idempotency keys?
No. An idempotency key deduplicates at one API that chose to support it, inside its
retention window. An effect key deduplicates at the agent, before the call, across every
remote it touches, is bound to the approval and the receipt, and refuses a retry when the
outcome is unknown rather than resending and hoping. Where a remote does support
idempotency keys, pass the effect key as one and get both.
More.
Why not a durable workflow engine?
Why not a durable workflow engine?
Different guarantee. An engine makes a workflow finish, retrying activities until they
succeed; CTRLRun decides whether a consequential effect is authorized and refuses to retry
an unknown outcome. Their advice, make activities idempotent, is the work CTRLRun does for
you and enforces in the store. Run the workflow in the engine and decorate the activity
that acts. More.
Do I need an adapter for my framework?
Do I need an adapter for my framework?
Probably not.
@protect covers anything in your Python process, and the gateway covers
anything behind an MCP server in any language. An adapter buys exactly one thing: routing an
approval through the framework’s own interrupt so a human answers where they already answer.
A framework with no such primitive needs none. More.Is it exactly-once?
Is it exactly-once?
No, and nothing can be against systems it does not control. CTRLRun guarantees it will not
knowingly execute the same logical effect twice, and never treats an unknown outcome as a
failure. The remote is the only thing that knows what the remote did; when nobody knows,
CTRLRun says so and stops. More.
What happens on a timeout?
What happens on a timeout?
The effect becomes
AMBIGUOUS, never FAILED, and a retry against it is refused. Only
NotExecuted, raised by your executor when it knows the remote did nothing, means failed.
A human runs ctrlrun resolve --committed or --failed after asking the remote, or a
reconcile hook asks for them. More.Can the agent bypass it?
Can the agent bypass it?
It can call the undecorated function, and the threat model says so: process-level
enforcement is out of scope. Two things narrow it. The gateway sits between the agent and
its tools, where the agent has no choice; and CTRLRun is never a tool the agent decides to
call, because a check the agent opts into is not a check.
Threat model.
Does it phone home?
Does it phone home?
No. There is no telemetry, no licence check and no network call of any kind in the kernel.
ctrlrun stats counts the local SQLite file, and a test runs the demo in a subprocess whose
sockets are all refused. The extras reach the network only where you point them: your JWKS,
your webhook, your OTLP endpoint, your Postgres.What if the human takes an hour?
What if the human takes an hour?
The approval request expires at its TTL, fifteen minutes by default, and a waiting call
raises
ApprovalTimeout with nothing executed. Raise the TTL for slow approvals, or do not
wait: ApprovalRequired carries the request id, so an agent can surface it and come back
later with with_approval(request_id). More.One host or many?
One host or many?
Either. On one host the store is a SQLite file and reservation is atomic across processes
through
BEGIN IMMEDIATE. Across hosts, pip install "ctrlrun[postgres]" and change the
store: a unique index on the effect key and compare-and-set updates give the same guarantee,
graded by the suite written for SQLite. More.What is in a receipt?
What is in a receipt?
One executed action: who proposed it, the action and its canonical arguments, the decision
and why, the approval and approver, the effect key, the outcome, the timestamps, the hash
and declared version of the policy that decided it, and the hash of the receipt before it.
Portable JSON, one object per line. More.
Is the receipt chain a signature?
Is the receipt chain a signature?
No. Each receipt carries the hash of the one before, so an edit, a deletion from the middle
or a reordering is detected and named by
seq. It does not prove who wrote a receipt,
receipts are not signed, and it does not survive an administrator who can rewrite every row
including the chain head. More.What is not covered?
What is not covered?
A compromised host or process. A malicious administrator with write access to the store. A
lying remote. A compromised approver. An executor that raises
NotExecuted after the remote
acted, which ctrlrun verify cannot see. Data exfiltration through reads. Authority across
an agent-to-agent hop. Threat model.Next
- Why · Get started.
- Compare: the five comparisons in full.