How to add human approval to an AI agent workflow
On this page
- Choose which operations require review
- Show the action the person is authorizing
- Store a pending request before sending notifications
- Authenticate the reviewer and check their authority
- Revalidate immediately before execution
- Handle execution retries separately from approval reuse
- Check the cases that a successful demo misses
- Keep the workflow visible to the team
Add human approval to an AI agent by pausing a proposed tool call, storing its exact scope, asking an authorized person to decide and letting the client's runtime resume only after validating that decision. The approval must belong to the action being executed, remain current and be protected against reuse.
Sending a notification is one part of that workflow. The execution path still needs to prevent the tool call while the request is pending, denied or expired.
This guide uses an illustrative release-publishing workflow. The state model and pseudocode are design examples, not production code or an available Nodrail integration. For the policy model behind the workflow, start with how to manage AI agent permissions.
Choose which operations require review
An agent might read release notes automatically but need approval before publishing a release to a production repository. Define that distinction in policy before creating the approval interface.
A request outside the agent's permitted organization or resource scope may need denial rather than escalation. A reviewer must not be able to approve an operation they have no authority to authorize. An explicit prohibition should retain its precedence in the policy model.
Review also needs a workable volume. If every routine operation demands a click, the team may stop examining requests carefully. Use narrow standing permissions where appropriate, and reserve individual review for actions that need a person to assess their specific effect.
Show the action the person is authorizing
For our example, release-agent proposes publishing version v1.4.0 in acme/website. A reviewable request could contain:
| Field | Illustrative value |
|---|---|
| Request ID | req-release-014 |
| Organization and environment | acme, production |
| Agent | release-agent |
| Tool and operation | release-tools, release.create |
| Repository | acme/website |
| Version and source commit | v1.4.0, a resolved commit identifier |
| Release content | The exact title, notes and publication settings |
| Expiry | A specific timestamp visible to the reviewer |
Resolve identity, repository ownership and the effective commit from trusted application state. A tag or branch name can move; showing a version label alone may not describe the artifact that will be published.
The interface can lead with a summary, but the relevant parameters must be inspectable. Render content from the agent as untrusted data, not as instructions to the reviewer or executable HTML. A text field saying user_confirmed: true is not an authorization record.
OWASP's agent security guidance includes action-bound approval and execution-side validation. The example here makes those requirements concrete for a release request.
Store a pending request before sending notifications
Persist the effective action and its review state before attempting delivery to a web inbox, email or a chat channel. If notification fails, the operation stays pending; notification delivery is not permission to proceed.
A simple state model is:
| Current state | Valid next state | What it means |
|---|---|---|
pending | approved, denied, expired, cancelled | A decision or deadline closes the review |
approved | claimed, expired, cancelled | One execution attempt may claim valid authorization |
claimed | An execution outcome recorded separately | The approval cannot authorize another attempt |
denied, expired, cancelled | No execution transition | A new operation needs its own valid request |
The application must resolve concurrent changes, such as approval arriving as a request expires. Use a conditional, atomic state update against persisted state so only a valid transition wins. Duplicate clicks should return the existing state rather than create independent approvals.
Authenticate the reviewer and check their authority
A reviewer opening a notification needs a valid session and permission to inspect that request. At decision time, check whether they are allowed to approve the specific organization, environment and operation.
Keep agent credentials separate from human approval authority. Knowing a request ID must not allow a caller to approve it. An “Approve” URL in a notification should open a review flow rather than silently change state when visited by a link scanner.
Slack can be a review interface, but a delivered Slack message does not prove who approved an operation. An implementation must verify the incoming interaction and map its workspace and user to an authorized reviewer. The same central request should be updated regardless of which supported channel the reviewer uses.
Revalidate immediately before execution
A human may spend several minutes reviewing a request. During that interval, the action can change, the request can expire or a policy can be revoked. Validate the current effective operation when the client's runtime is ready to continue.
Illustrative pseudocode:
request = load_request_for_authenticated_runtime(request_id)
action = resolve_effective_action_from_trusted_context()
if action_does_not_match_the_reviewed_request(action, request):
stop_and_request_a_new_review()
policy = evaluate_current_policy(action)
if policy is unavailable or invalid or policy is DENY:
stop_without_invoking_tool()
claim = atomically_claim_if_approved_current_and_unconsumed(request, action)
if claim is not valid:
stop_without_invoking_tool()
result = client_runtime.invoke_registered_tool(action)
record_execution_outcome_separately(claim, result)
The named functions stand for application-specific contracts. In a real system, define normalization, relevant resource versions, policy freshness and the point where the authorization claim becomes binding. A digest helps detect changes only when it is calculated over a trustworthy representation and checked against the effective operation.
The OpenAI Agents SDK provides a human-in-the-loop interruption and resume pattern. Its documentation also calls out production responsibilities around authentication, authorization, storage and recovery. A runtime's pause mechanism is useful infrastructure; the surrounding application still owns the authorization contract.
Handle execution retries separately from approval reuse
An atomic claim can prevent two workers from consuming the same approval. It cannot, by itself, make a remote provider operation execute exactly once.
For a supported provider, use an appropriate idempotency key for the same logical operation. If the connection fails after the provider may have accepted it, record an uncertain outcome and reconcile it before retrying. Do not interpret a missing response as proof that nothing happened, and do not simply reset the approval to approved.
If a retry would create a new effect, require a new authorization where the policy calls for it. If a standing rule applies, evaluate the new request under that rule. One-time review and standing permission remain different mechanisms.
Check the cases that a successful demo misses
The following are proposed acceptance criteria for the illustrative workflow:
| Case | Expected authorization behavior |
|---|---|
| Pending request | The release tool does not run |
| Denied or expired request | The release tool does not run |
| Different repository, commit or release content | The previous approval cannot be reused |
| Caller without reviewer authority | No approval transition |
| Two reviewers decide at once | One valid terminal review decision |
| Two workers claim one approval | At most one valid claim |
| Approval storage or verification unavailable | No tool invocation through this path |
| Provider response lost after an accepted call | Reconcile the uncertain outcome before retrying |
Measure actual invocations of a simulated tool when implementing these tests. These rows are not claims that Nodrail has already passed them. Also inspect any direct credential or network route that avoids this checkpoint; human approval in one SDK does not isolate the entire agent environment.
Keep the workflow visible to the team
Show the requester, proposed effect, reviewer, decision, expiry and execution status with clear provenance. “Approved” and “Completed” should be different states in the interface. Give the team a way to find requests whose notifications were not delivered or whose execution outcome is unknown.
Nodrail is developing a headless permissions and approvals layer for this kind of workflow. Your team keeps its runtime and tool credentials; supported integrations will be published when tested. Join the Nodrail waitlist, or use the permission matrix guide to define your first rules.