On this page8 sections
This is the question I get asked most about AI, usually in a lower voice than the others: what stops it from sending the wrong email, charging the wrong card, or changing something I never agreed to?
The honest answer is that nothing stops it unless the system is built so it can't. A prompt that says "always check with me first" is a request. A tool that physically cannot run without a current, matching approval is a control. I build the second kind, and this guide shows what that looks like from your side of the screen.
The goal isn't an assistant that asks permission to think. It's an agent that does the legwork, brings you work worth reviewing, and knows which decisions are yours.
Preparing, approving and doing are three different powers
I treat these as separate permissions, because they are.
Drafting a change doesn't include the right to publish it. Reading one customer's record doesn't include reading every customer's. Being allowed to approve a booking change doesn't quietly include approving a refund.
| Power | What the agent may do | How I know it held |
|---|---|---|
| Read | Look at the records this task needs, for this user | Nothing outside that scope was touched |
| Prepare | Draft a change without altering the real record | A proposal exists; the live record is unchanged |
| Approve | Only an authorized person, for this exact proposal | The decision records who approved which version |
| Do | Apply the approved action, within its limits | The destination confirms what actually happened |
| Recover | Pick up after an interruption | Finished work stays finished; unfinished work stays visible |
Not every action needs a person. You can decide that small, low-risk updates run on their own. The point is that you decide, in writing, rather than letting a broad tool connection decide by accident.
Try approving something, then change it
The lab below is fictional. Nothing connects to a real booking system. Approve the proposed change, then alter its time or destination and watch what happens to your approval.
Approve a change you can actually inspect.
The agent has prepared a booking update. Review it, then change the proposal or let its approval expire. These controls update only this teaching record.
- Read the permitted booking.
- Found the customer’s requested change.
- Checked the supplied availability.
- Prepared an exact proposal.
- Original appointment in this example
- September 9, 10:00 a.m.
- Proposed appointment
- September 11, 10:00 a.m.
- Unchanged
- Service, agreed price, and customer account
- Evidence
- Fictional request R-28 and availability snapshot S-9
This proposal changes one appointment field at the destination shown. It does not authorize a message, a charge, or access to another account.
Acting role: manager. Only the manager can grant approval. A changed proposal needs a new decision.
Proposal 1 prepared. No booking has changed.
Decision history (1 entry)
- 01Proposal 1 prepared. No booking has changed.
An actual integration must enforce identity, permissions, exact payload binding, expiry, and duplicate protection on the server. This local interaction demonstrates the policy; it is not a backend authorization test.
A few things to notice. The agent's preparation stays visible while the protected step waits. Time running out is not consent. The agent can't approve its own request. And trying to run the action a second time after it finished doesn't do it twice.
Those are the behaviors I require from the real integration. A demo proves the idea; the connected system has to prove it again.
What you should see before you click Approve
A good approval screen answers five questions without making you read the whole conversation the agent had.
Where will this happen? The account, the application, and the exact record. Not "the Johnson booking." The booking ID you can check against your own system.
What changes? Before and after. For a message, the exact text and who receives it. For a batch, the list of records and the rule that picked them. "Update the account" tells you nothing.
Why? The request, source or finding that led here, attached to the proposal. A link to a document that merely mentions the same customer isn't evidence.
What else happens? Updating a booking, emailing the customer, charging a card and notifying staff can be four separate actions. If one click approves all four, the screen says so.
What's uncertain? A missing availability check or two conflicting instructions belongs right beside the proposal. A "confidence: high" badge generated by the model is not a fact.
The boundary lives in the software, not the prompt
Instructions tell the agent how to work. They don't decide whether it's allowed to.
The part of the system that performs an action checks four things first: who is asking, where it's going, whether that operation is permitted, and whether the required approval exists and still matches. A document the agent reads can't grant it new powers by containing instructions. A confident-sounding proposal doesn't become authorized because it sounds confident.
Provider controls help, but I read their scope carefully. Claude's Managed Agents permission policies, for example, govern the tools it runs on its own servers, and the documentation is explicit that tools your own application provides remain your application's responsibility to guard. A setting that protects one path doesn't protect every path. Claude permission-policy documentation
So I map every route to a protected destination. If a restricted "publish" tool sits next to a general-purpose tool that can reach the same place, the restriction is decoration. Each write path gets its own check.
An approval is tied to exactly what you reviewed
When you approve, the system records what you approved: the destination, the operation, the exact content, the version, who you are, and how long the decision is good for.
Then it treats these as reasons to stop and ask again:
- The destination changed.
- The content changed in a way that matters.
- The approval expired or was withdrawn.
- The underlying record changed while the proposal was waiting. Someone else moved the appointment, revoked access, or the slot disappeared.
- The action already ran. A repeat attempt returns the recorded result instead of doing it again.
That fourth one catches people out. The proposal can be unchanged and still be stale, because the world moved. So the system rechecks the facts at the moment it acts, not just at the moment you approved.
Saying no, and taking your time
A rejection leaves a readable reason. The agent can use it to prepare a different proposal, but that's a new proposal, reviewed on its own. Nothing gets edited underneath a card you already approved.
A delayed approval stays pending. I name an owner and a backup, and we agree how long is too long. If the deadline passes, the system notifies or escalates. It never treats silence as a yes.
And I try not to make every step an interruption. Related preparation gets bundled into one complete proposal. Genuinely separate protected actions stay separate. The right size is the one where you understand the consequence without approving a stream of fragments.
When the connection drops halfway
Here's the moment most demos skip. The system sends an approved action, the destination completes it, and the response gets lost on the way back. The agent sees a timeout and is tempted to try again.
I build for that. Before repeating anything that matters, the system checks the destination to see whether the work already happened. If it did, it records the result and stops. If it can't tell, it holds the case and hands it to a person rather than guessing. What it never does is call the job done because the agent said so.
The tests I run before real customers are involved
Before connecting live work, I run the boundary through the cases where the right answer is "nothing happened": an unanswered proposal, a rejection, an unauthorized approver, a changed destination, changed content, an expired approval, a repeated run, and a record that changed between approval and action.
After each one I inspect the destination. I keep the blocked tool call and the decision record, so you can tell a real denial from a screen that merely showed an error.
Then the positive case: a valid approval on a still-current proposal runs once and leaves a receipt. A system that blocks everything isn't a safe system, just a useless one.
I can't promise an agent will never make a mistake in what it prepares. I can build it so the mistakes it can make are the ones you get to catch.
An agent can research and draft on its own. Anything that reaches a customer, moves money, changes access or rewrites a record waits for a person, and the software enforces that. Approvals are tied to the exact change reviewed and rechecked at the moment of action, and an interrupted action is verified before it's ever repeated.