
Approving an agent's actions: how to ask permission without stopping the work
Action approval is the step where a person authorizes what an AI agent is about to do before it happens. How to design the question and avoid prompt fatigue.
What exactly gets approved?
An agent does many things, but not all of them deserve a question. What gets approved are actions that are hard to reverse or that leave the system: writing to a project file, running a terminal command, sending an email, creating a payment, deleting a record.
In Claude Code, for example, Manual mode (the default) separates tool types. Reading files inside the working directory does not ask for approval. Editing files does, and so do terminal commands, except for a built-in set of read-only commands. Web searches also ask for permission. That separation is a good starting point: not everything an agent does carries the same risk.
How should the question look?
An approval question that only says “Allow this action?” is useless. The person needs information to decide. The question should show four things:
- The exact action. The full command, the email with its recipient, the amount, the file and the change it will make.
- The reason. Why the agent wants to do it, in one sentence, within the plan.
- What changes or leaves. What gets modified, who receives it, what cannot be recovered.
- The options. Approve this time, reject, modify the action before approving and, in some cases, remember the decision for that kind of action.
Claude Code’s prompt covers part of this: it shows the action’s description and the exact command (for example, npm test) and offers “Yes”, “Yes, and don’t ask again for: npm test *” and “No”. The second option saves a rule: for terminal commands, permanently in that repository; for file edits, until the session ends. So read the pattern before accepting it, and prefer narrow ones. You can also press Tab to attach a note when you approve or reject.
How do you avoid fatigue?
Approval fatigue happens when people approve so often that they stop reading. It is a known risk of this design: the control seems to exist when it does not.
Three practices help:
- Ask only about what matters. If everything asks for permission, nothing stands out. Review which actions are irreversible or external and leave the rest automatic.
- Group similar actions. Ten edits across ten files of the same change can be approved as one package, with its differences visible, instead of ten questions in a row.
- Offer narrow rules. A rule such as “allow test commands in this repository” is reasonable. A rule such as “allow everything” cancels the system. The OpenAI Agents SDK supports sticky decisions (
always_approveandalways_reject) that apply to future calls of the same tool; for a function tool they are also tied to the agent that requested the approval.
Claude Code also offers modes that change what gets asked. In acceptEdits, edits inside the working directory are approved automatically. In auto, a classifier reviews actions instead of the person, aimed at long tasks and at reducing fatigue. They are useful shortcuts, but they move the decision elsewhere: before using them, confirm what still asks for permission.
What happens when the person rejects?
A rejection is useful information, not a failure. The agent should receive it and change course: propose an alternative, ask what to change or stop. What it must not do is try the same action under another name or with another tool, because that bypasses the person’s decision.
That is why a rejection should be able to carry a short reason. “No, this email goes to the wrong customer” helps the agent correct the plan, and leaves a record of why it stopped. Claude Code supports this: the comment on a “No” reaches Claude as the reason for the rejection and it keeps working; if you reject without a comment, the turn stops. The OpenAI SDK accepts a rejection_message on each rejection. If the action had already been approved and later turns out to be wrong, the problem moves to undoing what an agent did.
Approval is one part of a wider set of controls. To decide which checkpoints belong in the whole flow, see human-in-the-loop. And for the rules that limit what the agent can do even when nobody approves, guardrails is the background layer.
Example
Illustrative example: an agent prepares a change to the code of a pricing page. It reads the files and proposes changes without asking, because nothing has been touched yet. When it reaches the step of editing the payments configuration file, it stops and shows: “Edit config/payments.ts: changes the annual plan price from 96 to 120 dollars. Reason: the plan was updated in the brief. Options: approve, reject, or edit the value before applying”.
The person changes the value to 110 and approves. The agent applies that value, not the one it proposed. The decision is recorded with the exact change.
When should you NOT ask for approval?
- For reversible, low-risk actions, such as creating a draft or reading a file. The question only adds noise.
- When approval comes after the effect. If the prompt appears after the email was sent, it is a notification, not control.
- When the person has no context to decide. A question with no reason and no detail protects nobody; it just transfers the responsibility.
What should you record for each decision?
Store who decided, when, which exact action was approved, whether the person modified it before approving and, for a rejection, the reason. That log serves three purposes: auditing an incident, seeing which kinds of action get rejected most often, and tuning the rules. If the record only says “approved”, it cannot help you learn from mistakes.
Common mistakes
- Asking permission for everything, and ending up with automatic approvals.
- Showing only the tool name, without the command or the recipient.
- Offering “always allow” without limiting what it applies to.
- Retrying the same action after a rejection, under another name.
- Not saving the decision, so there is no way to audit what was approved.