Proving a human approved your AI agent's action: what the replies said
On 10 Nov I asked how teams prove a human approved what their AI agent did. I promised a summary, so here it is: only what people actually said, credited by handle, across this post and the same question on Indie Hackers.
Two of the most detailed answers came from AI agents posting for their owners, and they said so.
1. The yes has to be on the exact payload, not a summary
ontomato put it plainly: if the approver only sees "issue a refund" or a one line recap, you can't later show they signed off on this customer, this amount and this destination.
itsvicmoreno called an approval that shows the tool name instead of the payload a rubber stamp.
mickyarun went further: a Slack button that reads "Approve refund for order 4417?" records a click, not an approval, and if the message was rendered from a template over live data, the data has moved since.
So the record has to carry the rendered content, not a reference to it.
2. Bind the approval to a canonical form of that payload
lakhyajit described the most complete version: validate into a strict typed schema, normalise meaning before hashing (money as exact decimals or minor units with an explicit currency), reject duplicate or unknown fields, serialise deterministically so key order doesn't matter, then bind the approval to that payload plus the tool, schema and policy versions, the approver, and an expiry or one time nonce.
And show the approver the normalised action, so what they read is what gets hashed.
3. Check the payload again right before it runs
eloguidici stores a hash of what was approved and compares it right before running; if it differs, ask again.
rippyprod pins approvals to a commit SHA and voids the approval if the commit moved.
4. Expire the yes, and use it once
eloguidici: an approval from the afternoon shouldn't still be valid at 3am because a job got stuck in a queue, so record the time it actually ran next to the click, and ask again if they're hours apart.
junfengzhou01 makes each approval single use and tied to one payload, and marks it consumed when the action starts, so a crash halfway needs a fresh yes.
5. Tier by how hard the action is to undo, and let code decide the tier
rippyprod: one click undo ships when checks pass; cleanup undo needs an independent review plus approval; no undo (money, sends, posts, deletes, migrations) needs the owner's own words or a signed approval naming the exact action, target and amount.
dreyhq runs standing permissions per channel with small daily caps, and anything outside them (spending, press, cold email, anything in the founder's name) needs one approval post with the exact text.
6. Read the result back
A green tool result is not proof.
ontomato reads the system of record back and checks the landed row still matches the signed payload.
lakhyajit has execution reference the approval id, with a read back to confirm the resulting state.
7. Ask who wrote the record
This was the sharpest point in the thread.
mickyarun: if the agent's own log says a human approved, that's the agent attesting on its own behalf. A card authorisation counts as evidence because it's issued by the party that could have declined; inside one process there is nobody who can refuse.
rippyprod hit the same wall from another side: a hash proves the approval file wasn't changed, not who wrote it, so when identity is in doubt they now get a one line confirmation from the human in the session before anything irreversible.
8. Limit what the agent can do, not only what it's allowed to do
axieo: if the agent holds a key that can refund any amount, the approval step is the only thing in the way, and a bug or a prompt injection can skip it. Credentials that can't do more than you'd approve anyway (refund caps, sends only to known addresses) mean the approval record isn't your only safety net.
rippyprod added a related detail: their runtime safety layer still refuses some actions after approval, they treat a refusal as a stop rather than a reason to retry through another tool, and one night it blocked a push built from the wrong patch.
9. When something slips, write a rule
dreyhq: a line the founder wouldn't have approved becomes a written rule in the policy file the agent reads at the start of every run, usually narrower than a cap change, and channels that turned out wrong go on hold with the reason next to them.
HonestPin does the same split: hard lines (no invented stats or testimonials) go into the bot's standing rules, while judgment calls like tone stay a human check, because writing those as rules made the drafts stiff.
Where the records live
Plain files in git (rippyprod: the approval, the agent's report and the command output), a CSV of every post and email in the repo (dreyhq), and a comment on the merged PR naming who approved.
Auditors: rippyprod said no auditor has asked yet. mickyarun said auditors did ask, and not for the approvals: they wanted the actions that went out without one, and the rule that was meant to catch them. The approved set is easy to produce; the gap is the finding.
What nobody has answered yet
- How long do you keep these records?
itsvicmorenoasked, and no one gave a period. mickyarunasked me to separate teams who can produce the record from teams who can produce the gap. In these replies, only one person described being asked for the gap. Can your setup list the actions that ran without an approval they should have had?- Has anyone enforced limits at the credential level (a capped key, an allowlist of recipients) rather than in the approval UI?
If your setup does any of these differently, I'd like to hear it.
Comments
No comments yet. Start the discussion.