Field note

AI Agent Permissions: Read, Draft, Approve, Execute

Design AI agent permissions enforced in code, not prompts: action classes, exact-action approval, expiry, one-time use, revocation and the negative tests that prove it.

Contents

A bunch of keys on a keyring lying on a wooden table

Image: Filip Szalbot on Unsplash.

An AI agent's permissions should be enforced by the runtime, not requested in a prompt, and every consequential action should run only with approval for that exact action. Approve "send this reply to Sam," and a reply to someone else, or with different text, needs a new approval.

Here is the case this guide is built around.

You approve a draft to Sam.

Before it sends, the agent "improves" it and adds Alex.

The old approval should now be worth nothing.

This guide is part of the AI harness engineering guide.

Classify actions before granting permissions

Not every action needs the same control. Sort them first.

Class Examples Default control
Read List events, search notes, read a thread Allowed within scope, logged
Draft Write a reply, propose an event, prepare a file Allowed; the output is held for review, nothing leaves
Execute, reversible Create a private note, add a tentative hold Approval, or a narrow standing rule you wrote
Execute, external Send a message, invite people, post publicly Exact-action approval every time
Irreversible or financial Delete data, pay, sign, cancel accounts Exact-action approval plus a second check, or not allowed at all

Two dimensions matter: whether the effect leaves your control, and whether it can be undone. A sent email cannot be unsent. A deleted file may be gone for good. Treat those classes as the most expensive.

Most personal workflows deliver their value at the draft stage. Start there.

Put enforcement outside the prompt

The model proposes. The runtime decides.

A system prompt that says "always ask before sending" is a preference the model usually follows. A harness where the send tool checks for a valid approval before executing is a rule it cannot skip. Prefer rules:

  • Remove tools a task does not need. No send tool means no accidental sending.
  • Scope credentials so a tool cannot reach other accounts or resources.
  • Check policy in code before every execution, in a component the model cannot modify.
  • Apply downstream limits too, such as read-only scopes at the provider.

Layered controls matter because any single one can fail.

Design a readable exact-action preview

An approval is only meaningful if you can see what you are approving. A good preview shows:

Field Example
Action Send email
Account work account
To sam@example.com
Subject Re: Project Alpha beta
Body Full text, not a summary
Attachments None
Reversible? No. Delivered email cannot be recalled
Expires 15 minutes

Show the full content. "Send a short reply confirming the date" is not an approval of the actual reply.

Be honest about reversibility. If an action cannot be undone, say so on the preview, not in documentation.

Bind approval to the exact operation

OWASP's AI Agent Security Cheat Sheet states the rule precisely: before execution, check that the approval belongs to the current actor and the exact tool call, remains valid and has not already been used, and check and consume it in one atomic step so concurrent or repeated requests cannot reuse it (OWASP).

In practice, an approval record holds:

{
  "approval_id": "apr_7f3c",
  "actor": "you",
  "tool": "email.send",
  "action_digest": "sha256 of the canonical tool name and every argument",
  "created": "2026-10-18T09:12:00Z",
  "expires": "2026-10-18T09:27:00Z",
  "used": false
}

At execution time the runtime recomputes the digest from the actual call. If anything differs, a recipient, a word, an attachment, the approval does not match and the action is refused.

The state machine is short:

  1. Proposed. The agent prepares the action; nothing has happened.
  2. Awaiting approval. You see the preview.
  3. Approved. An approval record exists for this digest.
  4. Executing. The runtime atomically checks and consumes the approval, then runs the action.
  5. Done, failed or uncertain. The result is recorded.

Any change to the action before step 4 sends it back to step 1.

Handle revocation, cancellation and uncertain outcomes

Expiry. Approvals should expire. Resuming a task tomorrow should not reuse today's consent.

Revocation. If you revoke a connector or credential, pending approvals that depend on it are void.

Cancellation. Cancelling a task stops new actions. It cannot undo completed ones, so report exactly what already happened.

Uncertain outcomes. If a send times out, the email may or may not have gone. Do not retry blindly. Check the sent folder or the provider's API first, then decide. The scheduling guide covers this reconciliation step in depth.

Test the denial paths

Permissions are only real if the failure cases are tested. Write these before you connect a real account:

Test Expected result
Execute with no approval Refused; nothing sent
Execute after approval expired Refused; new approval requested
Approve, then change the recipient Refused; digest mismatch
Approve, then change one word of the body Refused; digest mismatch
Reuse a consumed approval Refused
Two concurrent executions of one approval Exactly one succeeds
Execute after revoking the credential Refused at the tool or provider
A document instructs the agent to send No send occurs without your approval

Check the downstream state, not just the agent's message. "I didn't send it" is a claim; an empty sent folder is evidence. The evaluation guide shows how to fold these into a full suite.

Apply the policy to a personal workflow

Start with the strongest version of the policy: no execution tools at all. The draft-only email tutorial builds a useful assistant that way. When you later add a consequential action, add it through this approval design and these tests, and connect it through a scoped tool as shown in the MCP tutorial.

The order matters:

read first,
then draft,
then approve,
then execute,
one capability at a time.

Frequently asked questions

Is asking the model to seek permission enough?

No. Models usually follow such instructions, but nothing guarantees it. Enforce approvals in code the model cannot change.

Should every read operation require approval?

Usually not. Scope reads tightly and log them instead. Reserve approvals for actions with external or irreversible effects.

What if an approved action changes before execution?

The approval no longer matches and the action is refused. The new version needs its own approval.

Can rolling back local state undo a sent email?

No. Local rollback restores your system's records, not effects in the outside world. Treat external actions as permanent.

AI Agent PermissionsHuman in the LoopAI Agent SecurityApprovalsAI Harness Engineering