What is a bound approval for an AI agent action?
A bound approval ties a human decision to the exact request it was given for. What it binds, how it differs from an approval flag, and where its protection stops.
A bound approval is a human approval tied to the exact request it was given for, so the request that runs is the request that was reviewed, and any difference is refused before dispatch. The human approves the exact change, and that exact change is what runs.
How is a bound approval different from an approval flag?
An approval flag records "yes" against an approval id. Whatever is sent next under that id runs. If the amount changes from $20 to $200 between review and dispatch, the flag still says yes. That gap is approval drift.
A bound approval stores what was reviewed and checks it again at the moment of the call. In Anlyon, the approval of a governed action is bound to a digest of the request, target, versions, preconditions and expiry. Anlyon recomputes it before dispatch and refuses on any difference. The digest is SHA-256 over the canonical request. It is a digest, not a signature.
What does the binding cover?
| Bound field | What goes wrong without it |
|---|---|
| The normalized request | A larger refund or a different recipient runs under the old decision |
| The resolved target | The decision given for one account or resource is spent on another |
| Action and adapter versions | An action edited after review runs under the earlier approval |
| Preconditions observed at review | The reviewer approved a file state that no longer exists |
| Expiry | A decision from last week runs a request nobody looked at today |
Example
An agent asks to update a status file in GitHub. Anlyon builds a preview: the exact request, the before and after text, and the blob SHA the reviewer sees. The invocation names that preview.
import { Client } from '@anlyonhq/sdk';
const agent = new Client({ apiKey: process.env.ANLYON_AGENT_KEY! });
const input = { path: 'data/status.txt', content: 'status: green\n', message: 'Mark green' };
const { data: preview } = await agent.actions.preview('update-fixture', input);
// Send the same input with the reviewed preview.
await agent.actions.invoke('update-fixture', input, { previewId: preview!.id });
If the agent sends different content with that previewId, Anlyon refuses it at admission with 409 PREVIEW_MISMATCH. No effect is created and nothing is sent. If the file changes at GitHub after review, GitHub refuses the write on the reviewed blob SHA and the receipt grades failed.
Where does a bound approval stop?
- It binds the request, not the provider's whole state. Stripe has no compare-and-set, so the refundable amount a reviewer sees is as of review, and the preview labels it
freshness. - It applies to governed actions. An action with no declaration and no adapter is approved on its request snapshot. With the local
approvals.gate()wrapper, your process runs your function with your credential, and Anlyon records the decision. - A preview expires, and an approval never outlives it.
- An approval is permission to attempt the reviewed operation. A halt, a revoked credential or a full shared limit still refuses it at dispatch.
Related terms
Read next
Frequently asked questions
What is a bound approval?
A bound approval is a human approval tied to the exact request it was given for, so the request that runs is the request that was reviewed, and any difference is refused before dispatch. In Anlyon, the approval of a governed action is bound to a digest of the request, target, versions, preconditions and expiry.
Is the approval digest a signature?
No. The approval digest is SHA-256 over the canonical request. It is a digest, not a signature and not tamper evidence. Its job is to let Anlyon recompute the reviewed operation before dispatch and refuse on any difference.
