---
name: human_in_the_loop_design
description: Design human-in-the-loop approval checkpoints for autonomous agents. Use when deciding which agent actions need approval, building approval workflows, batching decisions, fighting approval fatigue, or setting up audit trails for autonomous runs.
---

# Human-in-the-Loop Design

## Purpose

Decide where human judgment sits in an autonomous agent workflow: which actions need a gate, how the gate asks, and how approvals stay meaningful instead of turning into rubber stamps. A gate the approver never reads is not oversight, it is decoration. Research from Uber's MLSys 2026 deployment found users approving 50 or more agent actions per session without meaningful review, producing no real oversight despite a nominal approval step. This skill exists to stop that.

## Workflow

### 1. Classify actions by risk, at design time

Define the tiers before the agent ever runs. Never improvise thresholds mid-run.

| Tier | Meaning | Examples | Gate |
|------|---------|----------|------|
| T0 | Read-only, reversible | Search, read files, draft text | None. Log only. |
| T1 | Low-stakes side effects | Post internal comment, open draft PR, send internal message | Autonomous within budget caps. Batch review. |
| T2 | Consequential or hard to reverse | Customer-facing message, code merge, money movement under a cap | Single approver, synchronous or async. |
| T3 | Irreversible or high stakes | Production DB writes, deletes, large money movement, legal/compliance actions | Senior approver or quorum, explicit options, full context. |

The approver level rises with the tier. A working pattern: T1 goes to any on-call, T2 to a team lead, T3 to an incident commander or equivalent. Calibrate the cutoffs from real agent behavior observed during a supervised period before production, not from guesses.

### 2. Pick the gate shape

- **Synchronous gate:** agent pauses until approved or rejected. Use for T2/T3 where the action is one decision, one moment.
- **Async batch gate:** agent queues requests; a human reviews a digest a few times a day. Use for T1 volume. Fewer interruption batches beat hourly pings for attention and mood (Fitz et al., 2019), and digests get roughly 35% higher engagement than per-event alerts in product data. Do not send an empty batch just to keep a rhythm; an empty ping is worse than silence.
- **Decaying gate:** the request auto-resolves after a stated deadline if nobody replies, toward the safe default (usually rejection). Deadlines are real design: explicit decay reduces the attention residue the pending decision leaves on the approver (Leroy, 2009), and it prevents agents stalling forever on an unreachable approver.
- **Quorum gate:** N approvals required for T3. Track each response individually so quorum is checkable.
- **Stop/interrupt:** for live agents, always wire a stop path. EU AI Act Article 14 names this explicitly for high-risk systems: the ability to intervene or interrupt is not optional.

See `references/approval-patterns.md` for the full state machine (pending, approved, rejected, timed out, escalated, executed, aborted), scope-drift re-approval, and gateway-outage behavior.

### 3. Present the decision like it matters

Three properties separate a real gate from a rubber stamp:

1. **Threshold legible:** the approver sees why this needed a human, what tier it is, what happens if they do nothing (the decay default and deadline).
2. **Options, not confirmations:** show real alternatives with tradeoffs. A single "approve?" button with a wall of JSON trains approvers to pattern-match the format instead of reading the content; adversarial testing shows format-locked output gets higher compliance than the same content in plain language.
3. **Full context, minimal format:** what the action does in plain words, the blast radius, what was already tried, how to undo it, and a diff view where anything changed. Keep the payload small enough to read in under a minute.

Also frame honestly: never dress a risky action as routine ("just a cleanup"). Minimizing language around permission requests is a known attack pattern for manufacturing exactly the shortcut this skill fights.

### 4. Defend against approval fatigue as a system property

Fatigue is a defect in the workflow, not a discipline problem in the human. Design controls:

- **Admission control:** every approval request declares what action it needs from the approver. If nothing is needed, it goes to a quiet surface (log, digest, status view), not to the interrupt channel.
- **Rate limits per source:** cap interruption frequency; collapse bursts into one digest entry.
- **Earned interrupt rights:** a category whose requests go persistently unreviewed loses the right to interrupt until fixed.
- **Severity stays scarce:** if most requests are "urgent," none are. Define priority by required response, and check the distribution instead of assuming it.
- **Watch for YOLO mode:** if review-time-per-request drops or approvals-per-session climbs without rejections, the gate has already failed. Measure it.
- **Separation:** people who benefit from continued approval should not be the overseers. Rotate reviewers, use canary tasks to keep judgment sharp.

Full research notes in `references/fatigue-defense.md`.

### 5. Audit everything the loop touched

Log every state transition, every approval decision (who, when, with what comment), the full action context, and the outcome. The audit trail is how you defend the decision later: regulators expect it (EU AI Act Articles 12 and 14, NIST AI RMF GOVERN), and post-incident analysis is impossible without the context the agent had when it asked.

Schema and hash-chained JSONL writer in `references/audit-trail.md` and `scripts/approval_gate.py`. Fields: request id, idempotency key, tier, action description, blast radius, context snapshot, approver identity, decision, timestamp, expiry, outcome, hash chain link.

### 6. Handle the failure modes

- **Gateway down:** the agent suspends. Never default to autonomous execution when approval infrastructure is unreachable; a DoS on the approval service must not grant the agent a free pass.
- **Scope drift:** an approval covers the plan as presented. If mid-execution reality diverges materially from what was approved, the original approval is void and a new request goes out.
- **Idempotency:** every approved action carries a unique idempotency key tracked in the state store, so a retry or restart can never double-execute.
- **Timed out:** requests that decay go to an explicit terminal state with an escalation path, never silent death.

## Output Contract

When this skill runs, it produces:

1. An **action classification table** (T0-T3) for the agent in question, with named approver tiers and decay defaults.
2. A **gate design** (shape, presentation template, batching cadence, rate limits) filled from `templates/approval-policy.yaml`.
3. An **audit plan** (fields logged, retention, who can read it, how tamper detection works).
4. For implementations: a working `approval_gate.py`-style service verified by a dry run showing request, approve, reject, timeout, and digest paths.

## Operating Rules

1. Classify before building. No gate ships without a T0-T3 table first.
2. Every factual claim about research stays attributed. If you cannot verify a number, date, or event, cut it or frame it as your own judgment.
3. No confident claims about regulations beyond what the references establish. This skill is engineering patterns, not legal advice; say so when compliance is on the table.
4. Approval volume is a design variable with a number on it. If the design produces more than a human can review in a day, the design is wrong, not the human.
5. Test the loop end to end before production: request, approve, reject, expire, gateway-down, scope-drift. An untested gate is a decoration.
6. Plain language in all approver-facing text. No press-release phrasing, no stacked adjectives, and never an em dash.
