All guides

How to add human approval to an AI agent workflow

By Nodrail · 6 min read

On this page
  1. Choose which operations require review
  2. Show the action the person is authorizing
  3. Store a pending request before sending notifications
  4. Authenticate the reviewer and check their authority
  5. Revalidate immediately before execution
  6. Handle execution retries separately from approval reuse
  7. Check the cases that a successful demo misses
  8. 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:

FieldIllustrative value
Request IDreq-release-014
Organization and environmentacme, production
Agentrelease-agent
Tool and operationrelease-tools, release.create
Repositoryacme/website
Version and source commitv1.4.0, a resolved commit identifier
Release contentThe exact title, notes and publication settings
ExpiryA 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 stateValid next stateWhat it means
pendingapproved, denied, expired, cancelledA decision or deadline closes the review
approvedclaimed, expired, cancelledOne execution attempt may claim valid authorization
claimedAn execution outcome recorded separatelyThe approval cannot authorize another attempt
denied, expired, cancelledNo execution transitionA 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:

CaseExpected authorization behavior
Pending requestThe release tool does not run
Denied or expired requestThe release tool does not run
Different repository, commit or release contentThe previous approval cannot be reused
Caller without reviewer authorityNo approval transition
Two reviewers decide at onceOne valid terminal review decision
Two workers claim one approvalAt most one valid claim
Approval storage or verification unavailableNo tool invocation through this path
Provider response lost after an accepted callReconcile 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.