> ## Documentation Index
> Fetch the complete documentation index at: https://docs.duvo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Designing Human-in-the-Loop Workflows

> Decide where humans belong in the loop, choose the right approval shape, and design what happens when nobody responds — before an incident reaches production.

This guide helps you decide where humans belong in the loop, choose the right approval shape, and design what happens when nobody responds — before you encounter an incident in production.

For a reference on the mechanics of creating approval requests — how to write AOP instructions, respond via Slack, or manage Requests — see [Human-in-the-Loop](/user-guide/assignment-features/human-in-the-loop).

## When to Add an Approval Step

Not every step needs human review. Use this risk framework to decide where approval gates add genuine value and where they only add friction.

```mermaid theme={"dark"}
flowchart TD
    A[Agent is about to take an action] --> B{Irreversible external?<br/>Tier 1}
    B -->|Yes| G[Always gate]
    B -->|No| C{Destructive internal?<br/>Tier 2}
    C -->|Yes| G
    C -->|No| D{High-value transaction?<br/>Tier 3}
    D -->|Above threshold| G
    D -->|No| E{Ambiguous interpretation?<br/>Tier 4}
    E -->|Low-confidence match| G
    E -->|No| F{Routine and reversible?<br/>Tier 5}
    F -->|Yes| H[Skip the gate]
    F -->|No| G
```

### Risk tier framework

| Tier | Action type | Examples | Default stance |
| - | - | - | - |
| **1 — Irreversible external** | Sends something that cannot be recalled or undone | Outbound email, publish to public channel, submit a payment | Always gate |
| **2 — Destructive internal** | Removes or overwrites data | Delete records, overwrite fields, archive items | Always gate |
| **3 — High-value transaction** | Financial or compliance impact above a threshold | Approve purchase order, grant access, sign contract | Gate above threshold |
| **4 — Ambiguous interpretation** | Agent cannot reliably determine intent | Categorizing a one-off case, routing to the right team | Gate on low-confidence matches |
| **5 — Routine and reversible** | Can be corrected without consequence | Tagging a record, updating a status, creating a draft | Skip the gate |

A practical starting point: start with an approval gate on all Tier 1 and 2 actions. Remove gates only after you have observed that a branch never produces surprises.

### Decision criteria by action category

| Category | Gate? | Notes |
| - | - | - |
| Send email to external recipient | Yes | Include recipient, subject, and full body in the request |
| Post to a public Slack channel | Yes | Include the channel name and draft text |
| Submit a financial transaction | Yes | Include amount, recipient, and reference number |
| Modify or delete a customer record | Yes | Include the record ID and the proposed change |
| Reply to an internal thread | Usually not | Gate only if the reply is policy-sensitive |
| Tag or label a record | No | Reversible; iterate without a gate |
| Create a draft (not sent) | No | Show in the approval request instead of gating during creation |

## Choosing the Right Approval Shape

The Human-in-the-Loop connection supports three request types. Picking the right one keeps operators efficient and prevents ambiguous responses.

<AccordionGroup>
  <Accordion title="Approval (confirm or reject)" icon="circle-check">
    Use when the agent has already determined what to do and just needs a go/no-go before acting.

    **When it fits:** The agent is about to send an email, submit a payment, or delete a batch of records.

    **AOP pattern:**

    ```
    Before sending the email, request approval. Set the title to
    "Send to [recipient] — [subject line]". Include the full email body
    in the description. Only send after approval. If denied, ask what to
    change and revise.
    ```
  </Accordion>

  <Accordion title="Question (choose from options)" icon="circle-question-mark">
    Use when the right next step depends on context the agent does not have, and the options are well-defined.

    **When it fits:** The agent needs to route a case, choose a tone, or decide between two valid policies.

    **AOP pattern:**

    ```
    If the invoice currency does not match the vendor's default, ask:
    (a) Convert to USD at today's rate and continue
    (b) Flag for manual review by the finance team
    (c) Reject and return to sender with a note
    ```

    **Design rules for good options:**

    * Keep option labels short and action-oriented.
    * Make options mutually exclusive — if they overlap, the operator will guess.
    * Do not add an "Other" option unless you also tell the agent what to do with a free-text answer.
  </Accordion>

  <Accordion title="When to use free-text instead" icon="pen-line">
    Free-text operator input makes sense when the operator needs to supply content, not just choose a path: dictating a reply, providing context about an anomaly, or overriding a specific field value.

    **Risk:** Free-text answers must be parsed by the agent in its next step. If the agent expects a decision but gets prose, it may misinterpret. Only use free-text when the agent's AOP explicitly handles open-ended input.

    **Common mistake:** Using a free-text question where a structured Question would do. Structured options are faster for operators and produce more reliable downstream behavior.
  </Accordion>
</AccordionGroup>

## Designing Fallback and Escalation Behavior

Every approval gate needs an explicit answer to "what happens if no one responds?" Without a defined fallback, the agent stalls indefinitely or makes an unsafe assumption.

### There is no timeout — design for the wait

An unanswered approval does not expire: the Run stays in **Needs Input** until someone responds, and a paused agent cannot act, so time-based instructions ("if not approved within 4 hours, escalate") have no effect. Decide up front whether an indefinite wait is acceptable for this action:

**Gate it** when the action can wait as long as it needs to — the Run pauses, the approver answers when they answer, and the work resumes.

**Fail-safe instead of gating** when the action is time-sensitive and the approver might be away — have the agent take the safe default up front and report it, rather than pausing:

```
If the refund exceeds the threshold, do not send it. Fail the case with
the reason "Needs manual approval — above refund threshold" and include
the prepared refund details in the case data.
```

The exception lands as a failed Case a human reviews on their own schedule, and the Run — and its Queue slot — is released instead of waiting.

### Repeated rejection → halt

If the operator rejects the same action multiple times, the agent has likely misunderstood the requirement. Continuing to loop wastes operator time.

```
If the approval is denied twice in a row for the same case, stop and
add a note: "Halted after two rejections — requires manual review."
Mark the case as Failed.
```

### Know who the approver is — and cover their absence

An approval request goes to the Run's author: the person who started the Run, the creator of the schedule, or — for Case-triggered Runs — the owner of the previous Run on that Case. There is no automatic escalation chain, so coverage is an operational habit, not an AOP instruction: make sure the approver has Slack or Teams request notifications on, agree who watches their [Requests](/user-guide/assignment-features/requests) page during absences, and prefer the fail-safe pattern above for anything that cannot afford to wait.

## Using Queue to Manage Exceptions at Scale

When an agent processes many cases, Requests becomes a bottleneck. The [Queue](/user-guide/assignment-features/case-queue) is the right tool for managing exceptions across high-volume workflows.

### Triage pattern

1. **Consumer agent** processes cases automatically.
2. Cases that need a human decision surface as **Needs Input** in the queue.
3. An operator reviews the **Needs Input** filter, responds in the case detail panel, and the agent resumes.
4. Cases the agent cannot resolve at all land as **Failed** — the operator reviews, updates the case data, and retries.

This separates routine processing from exception handling: the agent handles volume, the operator handles judgment calls.

### Bulk delegation for surges

When a backlog of Needs Input cases accumulates, you can select multiple cases and delegate them to a specialist agent — one designed specifically for exception handling — rather than asking one person to respond to dozens of individual HITL requests.

### Aging via postpone, not via paused Runs

A paused approval blocks its Run (and a Queue concurrency slot) until someone answers. For exceptions that can wait without blocking, have the agent postpone the Case instead of pausing — the time check happens at the start of the retry Run, which is the one place elapsed-time logic actually works:

```
If the case needs information from the requester, send them the request via
[channel], record what was asked in the case data, and postpone the case for
24 hours. On retry, check for their reply. If none has arrived, ask the team
lead: (a) Proceed with the default option, (b) Assign to a specialist,
(c) Close the case.
```

## Ramping Toward Safe Autonomy

The goal is not maximum oversight — it is the right level of oversight. As an agent matures, you should expect to remove approval gates where they no longer provide signal.

<Steps>
  <Step title="Start with gates on every risky branch" icon="shield">
    When you first deploy an agent, add approval gates on all Tier 1-2 actions and any branch where you are unsure what the agent will do.
  </Step>

  <Step title="Measure the approval rate" icon="chart-line">
    After a few weeks of production traffic, review the pattern of approvals and denials in Requests or the Runs list. Estimate the approval rate per gate.

    * **Approval rate above \~95%**: The agent is getting it right consistently. Consider removing the gate and trusting the output directly.
    * **Approval rate below \~70%**: The agent is frequently wrong. Refine the AOP before removing the gate.
    * **High denial rate with a consistent pattern**: The agent is doing the same wrong thing repeatedly. Update the AOP to correct the root behavior.
  </Step>

  <Step title="Remove gates selectively" icon="scissors">
    Remove gates one at a time, in order of confidence. Monitor the next two weeks of output. If quality holds, the gate can stay removed.

    **Do not remove a gate** if:

    * The action is irreversible and errors are high-cost.
    * Volume is too low to measure a meaningful approval rate.
    * You have changed something in the connected systems recently.
  </Step>

  <Step title="Re-introduce gates when conditions change" icon="rotate-ccw">
    Re-add approval gates when:

    * You modify the AOP in ways that could affect the gated branch.
    * The agent gains access to a new system.
    * Volume increases significantly (edge cases appear at scale that were rare before).
    * Approval rate drops during a quarterly review.
  </Step>
</Steps>

<Note>
  **Quarterly cadence:** Review approval rates for all agents in production. Prune gates with consistently high approval rates. Re-add gates on branches that have drifted.
</Note>

## Worked Examples

<AccordionGroup>
  <Accordion title="Expense report approval — threshold-based gate" icon="receipt">
    The agent auto-handles low-value expenses and escalates high-value ones through a structured flow.

    ```
    Process each expense report:
    — Under $200: approve automatically and update the status.
    — $200–$1,000: request approval. Title: "Approve expense — [employee] — $[amount]".
      Description: employee name, department, line items. If denied, return to the
      employee with the reason.
    — Over $1,000: ask whether to (a) approve, (b) deny, or (c) escalate to the
      finance director.
    ```

    See the full tutorial: [Expense Report Approval](/user-guide/examples/expense-report-approval)
  </Accordion>

  <Accordion title="Customer response email — tone check before send" icon="mail">
    The agent drafts a reply and holds it for review before sending.

    ```
    Draft the reply email. Request approval before sending.
    Title: "Send reply to [customer name] — [ticket ID]".
    Description: the full draft email body.
    If approved, send immediately.
    If denied, ask: (a) Revise the tone to be more formal, (b) Revise the tone
    to be more empathetic, (c) Escalate to the account manager.
    Regenerate based on the selected option and request approval again.
    ```

    See a related example: [Reviewing Drafts Before Sending](/user-guide/examples/reviewing-drafts-before-sending)
  </Accordion>

  <Accordion title="Supplier follow-up — gate only while there is time to wait" icon="clock">
    The agent gates routine follow-ups on approval, but switches to a fail-safe default when the item is too urgent to sit in a paused Run. The urgency check runs at the start of the Run — the one place time-based logic works.

    ```
    If the PO is fewer than 10 days overdue: request approval from the operations
    lead before sending.
    Title: "Follow-up: PO [number] — [supplier] — [days overdue] days overdue".
    If approved, send. If declined, fail the case with the reason.
    If the PO is 10 or more days overdue: send the follow-up using the default
    template immediately and log: "Sent without approval — past the urgency
    threshold".
    ```
  </Accordion>
</AccordionGroup>

## Related

<CardGroup cols={2}>
  <Card title="Human-in-the-Loop" icon="user-check" href="/user-guide/assignment-features/human-in-the-loop">
    Reference for request types and responding via Slack, Teams, and Requests.
  </Card>

  <Card title="Requests" icon="inbox" href="/user-guide/assignment-features/requests">
    Managing and responding to pending approval requests.
  </Card>

  <Card title="Queue" icon="layers" href="/user-guide/assignment-features/case-queue">
    Queue-based exception handling for high-volume workflows.
  </Card>

  <Card title="Guardrails for High-Risk Automations" icon="shield" href="/user-guide/security/high-risk-guardrails">
    Risk classification, hard caps, allow/deny lists, and kill switch procedures.
  </Card>

  <Card title="Refining Your Agent" icon="wand-sparkles" href="/user-guide/building-assignments/refining-your-assignment">
    Using HITL approval feedback to improve your AOP.
  </Card>

  <Card title="Expense Report Approval" icon="receipt" href="/user-guide/examples/expense-report-approval">
    Full tutorial showing threshold-based approvals.
  </Card>

  <Card title="Reviewing Drafts Before Sending" icon="pen-line" href="/user-guide/examples/reviewing-drafts-before-sending">
    Full tutorial showing draft review before outbound communication.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.