TAOS
← White Papers
AI Engineering

Building a Human Approval Queue for AI Agents (Without Building an Approval System)

May 1, 2026Taos Team
Human-in-LoopApproval QueueArchitecture

Building a Human Approval Queue for AI Agents (Without Building an Approval System)

Category: AI Engineering | Reading time: 5 min


The Approval System Nobody Wants to Build

Every team deploying AI in enterprise workflows hits the same requirement: some actions need human approval before they execute. A payment above a threshold. A document sent to a client. A medical recommendation for a high-risk procedure.

The standard response is to build an approval system: a database table for approval requests, a notification service, a review UI, a webhook for decisions, a state machine to track status. Three sprints of engineering work before you've written a single line of AI code.

Taos ships the approval system. You configure when to use it; the kernel handles the rest.


How Approval Routing Works in Taos

Approval routing is a first-class kernel primitive. When the Rego policy returns action = "require_approval" and required_role = "manager", the kernel automatically:

  1. Creates a structured approval request in the database
  2. Associates it with the current workflow execution
  3. Pauses the workflow and suspends the executing step
  4. Notifies the appropriate approver role
  5. Resumes execution when the approver decides
  6. Compensates cleanly if the request is rejected or times out

The application code that invokes this is three lines:

approval_id = await taos.request_approval(
    approver_role=decision.required_role,
    invoice_id=invoice_id,
    amount=amount,
    vendor_name=vendor_name,
    summary={"reason": decision.reason, "rule": decision.rule_fired},
)

That's it. No approval state machine. No notification service. No database schema to design.


The Approval Request Structure

When request_approval is called, the kernel creates:

{
  "id": "appr-uuid-7821",
  "workflow_execution_id": "exec-abc123",
  "invoice_id": "INV-8821",
  "amount": 18500.00,
  "vendor_name": "Acme Supplies Ltd",
  "approver_role": "manager",
  "submitted_by": "aclerk",
  "status": "pending",
  "nonce": "a3f2b1c4",
  "summary": {
    "reason": "$18,500 requires manager approval ($1,000–$25,000 tier)",
    "rule": "tier_manager_approval"
  },
  "created_at": "2024-03-15T14:23:11Z",
  "expires_at": "2024-03-17T14:23:11Z"
}

The nonce is a cryptographic value derived from the execution ID, invoice ID, and approver role. When the approver submits their decision, the nonce is verified to ensure the approval corresponds to the specific request and hasn't been replayed.


The Approver Experience

The approval queue UI — included in the Taos-governed payment demo — shows every pending approval for the logged-in user's role:

┌─────────────────────────────────────────────────────────┐
│ Pending Approvals (3)                                   │
├────────────────┬─────────┬─────────────┬───────────────┤
│ Vendor         │ Amount  │ Submitted   │ Action        │
├────────────────┼─────────┼─────────────┼───────────────┤
│ Acme Supplies  │ $18,500 │ aclerk      │ [✓] [✗]      │
│ DataTech Corp  │ $7,200  │ bsmith      │ [✓] [✗]      │
│ Office Depot   │ $1,450  │ jrowe       │ [✓] [✗]      │
└────────────────┴─────────┴─────────────┴───────────────┘

Clicking approve or reject:

  • Updates the approval request status
  • Extends the OBO chain with the approver's entry
  • Resumes (or compensates) the workflow

The approver sees full context — vendor, amount, submitter, policy rule that triggered the request — without any email chain or manual context assembly.


Implementing Role-Scoped Queues

The approval queue returns only requests matching the logged-in user's role. This is a simple database query:

@app.get("/api/approvals")
async def list_approvals(user: dict = Depends(require_auth)) -> list[dict]:
    """List pending approvals for the current user's role."""
    rows = await db.fetch_pending_approvals(user["role"])
    return [row_to_dict(r) for r in rows]

A manager sees manager-tier approvals. VP Finance sees VP Finance-tier approvals. A CFO sees all high-tier approvals. Each role only sees what they're responsible for.


Handling Rejection and Timeout

On rejection: The kernel receives the rejection, raises ApprovalRejectedError, and runs saga compensation:

try:
    approval_id = await taos.request_approval(...)
except ApprovalPendingError:
    # Workflow is paused — real approval path
    return {"status": "pending_approval", "approval_id": approval_id}

# If we reach here in mock/test mode, approval was granted
# In production, workflow resumes via webhook when approver decides

On timeout: Approval requests include an expires_at timestamp. If the approver hasn't acted by expiry, the kernel automatically compensates the workflow and notifies the submitter. The invoice returns to the queue for re-submission with a note about the expired approval.


The Production Approval Flow

In production, Taos uses its relay service to bridge the kernel's workflow execution with the approver's web interface:

Workflow paused → Approval request created in DB
                → Taos relay sends notification to approver role
                → Approver reviews in web UI
                → Approver clicks approve/reject
                → API calls POST /api/approvals/{id}/decide
                → Kernel resumes workflow execution

The workflow can be paused for minutes or hours — it doesn't matter. The kernel holds the execution state, the saga compensation stack, and the OBO chain while waiting. When the approver decides, execution resumes from exactly where it paused.


Multi-Level Approval Chains

Some workflows require sequential approvals — manager first, then VP if manager approves. This is encoded in the workflow step graph:

evaluatePolicy → [if amount >= $1k] → managerApproval
                                           │
                                           ▼ (if approved)
                                       [if amount >= $25k] → vpApproval
                                                                 │
                                                                 ▼ (if approved)
                                                             submitPayment

Each approval step pauses the workflow, routes to the appropriate role, and resumes on decision. The OBO chain accumulates all approvals in sequence.


The Bottom Line

Human approval queues are a requirement, not a feature. Every production AI system handling consequential actions needs one.

Building your own costs 3+ engineering sprints and ongoing maintenance. The Taos kernel ships it as a primitive: configure the policy to say when approval is required, and the kernel handles the rest — queuing, routing, pausing, resuming, and recording everything.

Spend your engineering time on the AI. Let the kernel handle the approvals.


Tags: human-in-the-loop, approval queue, AI workflow, enterprise AI, payment approval, governance kernel