Loops and graphs

Where should a person approve work in an AI loop?

Written as of · Published · By Robert Scales, with AI tools · 8 min read

Short answer

Put the approval where a mistake would do real damage that is hard to undo, such as sending, paying, deleting, deploying or merging, not where the model sounds unsure. Keep the steps before it reversible and checked automatically, so the person usually approves one final step with a short packet of evidence in front of them.

An AI loop is a cycle in which a model produces some work, an automatic check tests it, and failed work goes back for another try. The checks catch many mistakes, but some decisions should not be left to a loop at all: emailing a customer, refunding an order, deleting a database table, pushing code to the branch everyone ships from. The question is not whether a person should be involved, but where, and how often.

The short answer is to place approvals by blast radius: how much damage a wrong action could do, how many people or systems it would touch, and whether it can be undone. A step that only changes a draft on your own branch can run freely and be reviewed later. A step that leaves your hands, spends money or destroys data pauses and waits for a person. How confident the model sounds plays no part in that decision.

Why model confidence is the wrong trigger

It is tempting to ask the model to flag the actions it is unsure about and send only those to a person. The trouble is that the dangerous actions are often the confident ones.

Anthropic describes this in a March 2026 engineering post about Claude Code, its coding agent. Its internal log of agent misbehavior includes deleting remote git branches after a vague request to tidy up, uploading an engineer's GitHub access token to an internal computing cluster, and trying to run a migration against a production database. Anthropic calls the pattern overeager behavior: the agent understands the goal and is trying to help, but goes further than the person meant. Nothing in the agent's reasoning looks hostile or hesitant. The action simply reaches past what was authorized. The post lists a second cause, honest mistakes about scope, such as treating a shared resource as if it were a test copy.

Neither pattern announces itself through low confidence. What they share is the size of the consequence. That is why the gate belongs on the action, not on the model's mood.

Sort actions by blast radius

Blast radius is a term borrowed from operations work: the area a failure can reach. For an AI loop, ask three questions about each action:

  1. Can it be undone? An edit on a branch can be reverted. A sent email, a payment or a deleted record usually cannot.
  2. Who else does it touch? A local file affects you. A shared server, a customer or a public page affects others.
  3. Does it cross a trust boundary? Sending data to a service nobody named, or using a credential found along the way, moves the work outside what was agreed.

The table shows how this sorts common steps.

ActionUndo?ReachApproval
Read files, search, run tests in a sandboxNothing to undoLocalNone
Edit files in the project, on a working branchYes, through version controlLocalNone per edit; review at merge
Draft an email or post, saved as a draftYesLocalNone until it is sent
Install a package the project already listsYesLocalUsually none
Fetch from or send data to an outside servicePartlyOthersOnly to services named in advance
Send an email, publish a page, post a messageNoOthersEvery time
Pay, refund, change pricesRarelyOthers, moneyEvery time
Delete records, force-push, deploy to productionRarelyShared systemsEvery time

Anthropic's auto mode for Claude Code, described in the same post, follows a similar ladder. Read-only tools run without asking. File edits inside the project also run, because version control makes them reviewable. Shell commands, web requests and anything outside the project go to an automated reviewer, a separate model that blocks actions in categories such as destroying data, weakening security, sending data across trust boundaries, and bypassing review on shared systems (pushing straight to the main branch, deploying to production).

The OWASP project's guidance on excessive agency, its name for AI systems that can take damaging actions on bad or manipulated output, adds two points. Ask for a person's approval on high-impact actions, and enforce permissions in the systems the agent touches rather than trusting the model to hold back: a database account that can only read cannot be talked into deleting.

Approve the last step, not every step

If every action asks for permission, people stop reading. Anthropic calls this approval fatigue and reports that Claude Code users accept 93% of manual permission prompts. An approval clicked through without reading is a delay, not a safeguard.

The way out is to design the loop so that almost everything before the risky step is reversible and checked by machines. Code changes land on a branch, not on the main line. Emails are saved as drafts. Data changes go to a staging copy. Automatic checks (tests, source matching, scope limits) run on each unit and send failures back on their own. When the work reaches the one step that cannot be taken back, a person looks at it once, with the whole result in view.

Often that one step is the final merge or the final send. Anthropic's guidance on building agents makes the same case for coding: automated tests can confirm that code works, but a person still needs to judge whether the change fits what the project actually needs.

Two cases call for a gate in the middle. One is an irreversible action that cannot be moved to the end, such as a payment that must happen before the next step. The other is a step whose result will be hard to inspect later, such as a migration that rewrites thousands of records. When you find one of these, first ask whether the loop can be reshaped (dry run first, write to a copy, batch the irreversible actions at the end). If not, gate it.

What to put in front of the approver

An approval is only as good as what the person sees. Anthropic's post is candid on this point: its automated reviewer usually spotted the dangerous part of an action but then misjudged whether something the user said earlier really covered it. "Clean up the PR" is not consent to a force-push. People make the same error when an approval screen shows a vague summary.

A useful approval packet answers six questions:

  1. The exact action and target. Not "clean up old branches" but the list of branch names, with which ones are remote.
  2. What changed. A diff, the final text of the email, the rows to be deleted.
  3. Which checks ran and what they found. Tests passed with the test files unchanged, every claim matched to a source, no files touched outside the plan.
  4. What failed along the way. Which units went back for correction, and why.
  5. What was not checked. Anything the checks cannot see, stated plainly.
  6. How to undo it, if that is possible at all.

You can ask the agent to assemble this packet itself, as long as the facts in it come from the check results and not from the agent's own account of its work.

Prompt
Before asking for approval, write an approval request with these headings and nothing else:
Action: the exact command, recipient or target, written out in full.
Changes: the diff or final text, unabridged.
Checks: each automatic check that ran, copied from its output, with pass or fail.
Corrections: units that failed a check and were fixed, with the failure message.
Not checked: anything a person must judge because no check covers it.
Undo: how to reverse this, or "cannot be undone".
Do not summarize or soften check output. If a check failed and was not fixed, say so first.

How frameworks implement the pause

Several agent frameworks have a built-in way to stop a run, wait for a person and continue.

In LangGraph, a library for building agent workflows as graphs, a node calls interrupt() with whatever the approver should see. The run's state is saved by a checkpointer, and the graph waits until it is resumed with the person's answer. One detail matters for safety: when the run resumes, the paused node starts again from its beginning, so any code before the interrupt() call runs twice. Put the risky action after the approval, never before it.

In the OpenAI Agents SDK, a tool can declare that it needs approval, either always or through a small function that decides per call. That function is a good place to encode blast radius:

from agents import function_tool

async def outside_company(_ctx, params, _call_id) -> bool:
    # Ask a person only when the email leaves the company.
    return not params.get("to", "").endswith("@example.com")

@function_tool(needs_approval=outside_company)
async def send_email(to: str, subject: str, body: str) -> str:
    ...

When approval is needed, the run pauses and lists what is waiting, with the tool name and its arguments. The paused run can be saved, reloaded later in another process, approved or rejected, and resumed.

Both tools leave the policy to you. They provide the pause; you decide which actions earn one. If you use a no-code automation tool instead, the same idea applies; this guide's n8n approval walkthrough shows one way to build it.

Try it: List every action your agent or automation can take, then mark each one with the three blast-radius questions: can it be undone, who else does it touch, does it cross a trust boundary. Every action with "no", "others" or "yes" in the wrong place gets an approval gate; then check whether any of those can be moved to the end of the run.

What should happen when the approver says no?

A rejection is information, and the loop should use it. Send the rejected unit back for correction with the approver's reason attached, rather than restarting the whole run. The OpenAI Agents SDK, for example, returns a rejection message to the model, and lets you write that message per call, so "wrong recipient: this should go to the billing contact" reaches the agent instead of a bare refusal. Give the corrected version a limited number of attempts, then hand it back to a person.

Keep a record of every approval and rejection, with the reason. If the same kind of rejection keeps coming back (wrong tone for customers, a file the agent should never touch), that is not a one-off correction. It belongs in the agent's standing instructions, or better, in an automatic check that catches it before the work reaches a person again.

Finally, decide what happens when nobody answers. For any action that matters, silence should mean the action does not happen. A pending approval that times out and proceeds anyway is not an approval.

Sources

  1. How we built Claude Code auto mode: a safer way to skip permissions — Anthropic, March 25, 2026
  2. LLM06:2025 Excessive Agency — OWASP Gen AI Security Project, May 5, 2025
  3. Interrupts (LangGraph docs source) — LangChain, June 15, 2026
  4. Human-in-the-loop (OpenAI Agents SDK docs) — OpenAI, March 13, 2026
  5. Building effective agents — Anthropic, December 19, 2024

Sources for the articles linked in the text

Each linked article has its own page, with its sources and its date.

From the Guide to Artificial Intelligence, by Robert Scales, published by Holistic Hybrid Inc. Share and adapt it under CC BY-NC-SA 4.0: credit the guide, link to https://guidetoartificialintelligence.com/en/learn/where-human-approves-ai-loop/, no commercial use without permission, and keep the same licence.

Get the free Guide to Artificial Intelligence

Sign up for the newsletter and receive the free guide: what changed in AI, one lesson, one prompt to try. Unsubscribe in one click.

How we handle your address

Back to top

Display

Your choices are saved in this browser only. No data is sent.

Text size
100%
Colours
Reading
More settings
Accessibility statement

Get the app

Add the guide to your home screen. It opens like an app, and the pages you have read stay available offline.

Read without a connection: download the articles

iPhone and iPad (Safari, Chrome, Edge)

  1. Tap the Share button (the square with an arrow). In Chrome and Edge, it is in the address bar or the menu.
  2. Choose “Add to Home Screen”.
  3. Tap “Add”.

Android (Chrome, Edge, Samsung Internet, Firefox)

  1. Open the browser menu (⋮ or ☰).
  2. Choose “Install app” or “Add to Home screen”.
  3. Confirm with “Install”.

Computer (Chrome, Edge)

  1. Click the install icon at the right end of the address bar, or open the browser menu (⋮ or …).
  2. In Chrome, choose “Cast, save and share”, then “Install page as app”. In Edge, choose “Apps”, then “Install this site as an app”.
  3. Click “Install”.

Mac (Safari)

  1. Open the File menu.
  2. Choose “Add to Dock”.
  3. Click “Add”.

Firefox on a computer can’t install a site as an app. Use Chrome, Edge or Safari instead.