DEV Community

George Belsky
George Belsky

Posted on

How to Add Human Approval to AI Agent Workflows Without Building It Yourself

Your AI agent generates a quarterly financial report. Before it emails the board, a human needs to review it. Simple requirement.

Here's what you actually have to build.

The DIY Approach

import secrets
import smtplib
from apscheduler.schedulers.background import BackgroundScheduler

def request_approval(reviewer_email, context, agent_id):
    # 1. Generate approval token
    token = secrets.token_urlsafe(32)
    db.insert("approvals", token=token, agent_id=agent_id,
              status="pending", created_at=datetime.utcnow())

    # 2. Send notification
    send_slack_message(reviewer_email,
        f"Approval needed: {context}\n"
        f"Approve: https://your-app.com/approve/{token}\n"
        f"Reject: https://your-app.com/reject/{token}")

    # 3. Schedule reminder (5 min)
    scheduler.add_job(send_reminder, 'date',
        run_date=datetime.utcnow() + timedelta(minutes=5),
        args=[token, reviewer_email])

    # 4. Schedule escalation (30 min)
    scheduler.add_job(escalate_to_backup, 'date',
        run_date=datetime.utcnow() + timedelta(minutes=30),
        args=[token, get_backup_reviewer(reviewer_email)])

    # 5. Schedule timeout (8 hours)
    scheduler.add_job(handle_timeout, 'date',
        run_date=datetime.utcnow() + timedelta(hours=8),
        args=[token])

    return token

# Plus you need:
# - Webhook endpoint for approve/reject callbacks
# - Token validation and expiry
# - Polling loop or callback for the agent to resume
# - Audit logging (who approved, when, what context)
# - DB cleanup for expired tokens
# - Error handling for failed notifications
# - Unit tests for all of the above
Enter fullscreen mode Exit fullscreen mode

That's about 200 lines before error handling. You also need a web server for the webhook, a scheduler process that stays alive, and a database for approval state.

All you wanted was "pause and wait for a human."

The 4-Line Version

from axme import AxmeClient, AxmeClientConfig

client = AxmeClient(AxmeClientConfig(api_key=os.environ["AXME_API_KEY"]))

intent_id = client.send_intent({
    "intent_type": "intent.report.review_approval.v1",
    "to_agent": "agent://myorg/production/report-generator",
    "payload": {
        "report": "Q1 Financial Summary",
        "pii_detected": False,
        "reviewer": "cfo@company.com",
    },
})
result = client.wait_for(intent_id)
Enter fullscreen mode Exit fullscreen mode

The platform handles:

  • Notification - Slack, email, CLI. Reviewer gets notified immediately.
  • Reminders - Configurable intervals. Default: 5 min, then 30 min.
  • Escalation - Reviewer A does not respond? Escalate to reviewer B, then to the team.
  • Timeout - Graceful timeout with configurable fallback action.
  • Audit trail - Who approved, when, with what context. Stored durably.
  • Durable state - Agent crashes? Restarts? The approval state is in PostgreSQL, not in process memory.

What Matters in Production

The demo version of human approval is always simple. input("Approve? y/n"). The production version is where things break.

Production concern DIY AXME
Human is on vacation Build escalation chain Built-in
Agent crashes while waiting Lost approval state Durable in DB
Two approvals needed Build chaining logic Approval chains
Audit for compliance Custom logging Built-in event log
Reminder if no response in 5 min Scheduler + cron job Built-in
Mobile-friendly approval Build a UI Slack/email/CLI

Works With Any Framework

This is not framework-specific. Your agent can be built with LangGraph, CrewAI, AutoGen, OpenAI Agents SDK, Google ADK, or raw Python. The approval layer sits outside your agent code.

The agent framework handles reasoning. The coordination layer handles waiting for humans.

Try It

Working example - agent generates a report, pauses for human review, resumes after approval:

github.com/AxmeAI/async-human-approval-for-ai-agents

Built with AXME - human approval for AI agent workflows, built in. Alpha - feedback welcome.

Top comments (0)