Human-in-the-Loop and Intervention Points
Approval gates, escalation triggers, the autonomy-oversight spectrum, and the production triad
Overview
Intervention is the eighth first-class harness concern — not an afterthought, but a deliberate architectural choice. In Lesson 6 (Persistence), we introduced the production triad: persistence enables recovery, recovery enables intervention. Without persistence to checkpoint state, HITL patterns cannot pause and resume safely.
This lesson focuses on when and how humans intervene in agent execution. We'll cover five intervention points, the approval gate pattern, the autonomy-oversight spectrum, guardrails vs HITL distinction, and how production harnesses implement intervention policies.
Why intervention matters:
- Agents make mistakes. Humans correct course before damage occurs.
- High-stakes actions (delete production database, send legal notice) demand approval.
- Uncertainty signals (low confidence, unfamiliar domains) trigger escalation.
- Regulations and organizational policy require human oversight for certain decisions.
Intervention is not a sign of failure — it's a deliberate control mechanism.
Five Intervention Points
A harness provides multiple intervention points where humans can influence agent behavior:
graph TD
TURN["Turn Start"] --> CTX["Context Assembly"]
CTX --> MODEL["Model Call"]
MODEL --> PARSE["Parse Response"]
PARSE --> PRE{"Pre-Action<br/>Approval"}
PRE -->|approved| EXEC["Tool Execution"]
PRE -->|denied| GOAL
EXEC --> POST{"Post-Action<br/>Review"}
POST -->|ok| STATE["Update State"]
POST -->|flag| ESC
STATE --> TERM{"Termination<br/>Check"}
TERM -->|continue| GOAL{"Goal<br/>Modification?"}
GOAL --> TURN
TERM -->|uncertain| ESC{"Escalation on<br/>Uncertainty"}
TERM -->|stop| DONE["Done"]
ESTOP["Emergency Stop"] -.->|async, any point| DONE
style PRE fill:#ffd700,stroke:#b8860b
style POST fill:#ffd700,stroke:#b8860b
style GOAL fill:#ffd700,stroke:#b8860b
style ESC fill:#ffd700,stroke:#b8860b
style ESTOP fill:#ff6347,stroke:#cc0000,color:#fff
1. Pre-Action Approval
The harness pauses before executing a high-risk action and requests human approval.
Example: Before the agent runs DROP TABLE users, the harness checkpoints state, presents the proposed SQL, and waits for approval.
Use cases:
- Destructive actions (delete files, revoke permissions)
- External communications (send email, post to Slack, create PR)
- Financial transactions (charge credit card, transfer funds)
2. Post-Action Review
The harness executes the action but logs it for human review. The human can approve or roll back.
Example: The agent commits code to a branch. A human reviews the diff before merging to main.
Use cases:
- Low-risk actions where rollback is possible
- Batch operations where pre-approval is impractical (100 file edits)
- Audit trails for compliance
3. Goal Modification
The human changes the agent's goal mid-execution.
Example: The agent is searching for "best cloud provider." The human narrows the goal to "cheapest cloud provider for batch workloads under $500/month."
Use cases:
- The original goal was underspecified
- New information changes priorities
- The agent is stuck in an unproductive loop
4. Escalation on Uncertainty
The agent detects its own uncertainty and asks for help.
Example: A code-review agent encounters unfamiliar syntax. Instead of guessing, it escalates: "I don't recognize this pattern. Should I flag it as risky or skip?"
Use cases:
- Low confidence scores from model outputs
- Out-of-distribution inputs
- Contradictory information in retrieved context
5. Emergency Stop
The human or system halts execution immediately.
Example: The agent begins deleting files outside the project directory. A filesystem monitor triggers an emergency stop.
Use cases:
- Runaway loops (agent calls the same API 1000 times)
- Unexpected behavior (agent starts reading sensitive files)
- Resource exhaustion (agent spawns 50 subprocesses)
The Approval Gate Pattern
The approval gate is the most common HITL pattern. It follows this sequence:
- Policy check: The harness evaluates whether the proposed action requires approval.
- Pause execution: The agent's loop is suspended.
- Checkpoint state: The run state (messages, tool calls, context) is serialized to durable storage.
- Present to human: The harness sends the proposed action to a review queue or UI.
- Receive decision: The human approves, rejects, or modifies the action.
- Resume or abort: The harness restores the checkpoint and continues (if approved) or terminates (if rejected).
Sequence: Agent proposes action → Harness checks policy → Checkpoint state → Present to human → Receive decision → Resume (approved) or Abort (rejected).
Key insight: Without Step 3 (checkpoint), the harness cannot resume. This is why Lesson 6 called persistence a prerequisite for intervention.
The Autonomy-Oversight Spectrum
Not all agents need the same level of human involvement. The autonomy-oversight spectrum ranges from fully autonomous to fully human-directed:
Spectrum: Autonomous (no human) → Approval Gates (human approves risky actions) → Supervised (human monitors logs) → Human-Directed (human commands each step).
Where to place your agent:
- Autonomous: Low-risk, well-defined domains (data formatting, test generation).
- Approval gates: High-stakes but predictable actions (deploy to production, send customer emails).
- Supervised: Exploratory tasks where humans watch for drift (research assistants, code refactoring).
- Human-directed: Novel domains or strict compliance environments (legal review, medical diagnosis).
Most production agents operate in the approval gates or supervised zones.
Escalation Triggers
How does the harness decide when to escalate? Common escalation triggers include:
- Confidence thresholds: The model's logprobs or a classifier's score falls below a threshold.
- Action risk classification: The action is tagged as high-risk in the harness policy.
- Cost limits: The agent has consumed more tokens, API credits, or wall-clock time than budgeted.
- Anomaly detection: The agent's behavior deviates from expected patterns (infinite loop, unexpected file access).
The harness maps action risk and reversibility to an intervention level:
Decision matrix: Low risk + reversible → auto-execute. Medium risk + irreversible → require approval. High risk + irreversible → block unless policy explicitly allows.
Example policy:
git commit→ low risk, reversible → execute without approval.git push --force→ medium risk, irreversible → require approval.rm -rf /→ high risk, irreversible → block (should never be allowed).
Synchronous vs Asynchronous Intervention
Intervention can be synchronous (blocking) or asynchronous (non-blocking):
| Attribute | Synchronous | Asynchronous |
|---|---|---|
| Agent behavior | Blocks, waits for response | Checkpoints, continues other work |
| Latency impact | High (user must be present) | Variable (hours to days possible) |
| Use case | Interactive CLI, short-lived scripts | Long-running agents, batch jobs |
| Persistence needed | No (process stays alive) | Yes (checkpoint + resume) |
| User experience | Immediate dialog prompt | Notification or approval queue |
Synchronous (Blocking)
The agent waits for the human to respond before continuing. The human is actively engaged and the system is blocked.
Example: A CLI agent pauses and prompts: Send this email? [y/n]. The user types y, and execution resumes immediately.
Pros:
- Low latency (user is present and responds quickly).
- Simple implementation (no checkpoint persistence needed if the process stays alive).
Cons:
- Human must be available and waiting.
- Not suitable for long-running agents or batch processing.
Asynchronous (Non-Blocking)
The agent pauses and checkpoints its state. The human reviews the approval request later (minutes, hours, or days). The system processes other tasks in the meantime.
Example: A research assistant agent wants to send an email summary. The harness checkpoints state, adds the request to an approval queue, and moves to the next agent run. When the human approves (via web UI), the harness restores the checkpoint and resumes.
Pros:
- Humans review on their own schedule.
- Scales to many agents (one human can manage an approval queue).
Cons:
- Requires durable persistence (Lesson 6).
- Higher latency (agent may wait hours for approval).
Choosing between sync and async:
- Sync: Interactive CLI tools, short-lived scripts, human is present.
- Async: Long-running agents, batch jobs, agents running overnight or on servers.
Guardrails vs HITL: A Critical Distinction
Guardrails and HITL are often confused, but they serve different purposes:
| Aspect | Guardrails | HITL | |--------|-----------|------| | Definition | Automated runtime checks (input validation, output filtering, content safety) | Pause-for-human-decision pattern | | Human involvement | None — runs automatically | Requires human to approve/reject | | Examples | Block SQL injection in user input, filter toxic content from model output, enforce rate limits | Approve email before sending, review code before deploying, modify search goal mid-execution | | Persistence required? | No (stateless checks) | Yes (checkpoint before pause, resume after decision) | | When to use | Enforce invariants, prevent known bad patterns | Handle uncertainty, high-stakes decisions, human judgment calls |
A harness may use both. They are complementary, not interchangeable.
Example: An agent that generates and sends emails might have:
- Guardrails: Block emails containing PII (automated check), enforce subject line length limits (automated).
- HITL: Human approves the email content before sending (requires pause and resume).
Anti-pattern: Using HITL where guardrails suffice. If the rule is deterministic (e.g., "never send emails to competitors"), encode it as a guardrail. Reserve HITL for cases requiring human judgment.
How Harnesses Expose Intervention
Different harness frameworks provide different intervention primitives:
LangGraph
LangGraph supports interrupts and breakpoints:
from langgraph.graph import StateGraph
from langgraph.checkpoint.memory import MemorySaver
workflow = StateGraph(state_schema=AgentState)
workflow.add_node("send_email", send_email_node)
workflow.add_node("human_approval", interrupt("approve_email"))
# Checkpoint state before human_approval node
checkpointer = MemorySaver()
app = workflow.compile(checkpointer=checkpointer, interrupt_before=["human_approval"])
# Execution pauses before human_approval
response = app.invoke({"recipient": "user@example.com", "body": "Hello"})
# Human reviews and approves
app.update_state(response["thread_id"], {"approved": True})
# Resume from checkpoint
app.invoke(None, thread_id=response["thread_id"])
Key features:
interrupt_beforepauses execution before a node.- Checkpointer saves state automatically.
update_stateinjects the human decision.
OpenAI Agents SDK
The OpenAI Agents SDK separates guardrails (automated) from HITL approvals (human-in-the-loop):
from openai import Client
from openai.agents import Agent, RunState
client = Client()
agent = Agent(
model="gpt-4",
tools=["send_email"],
# Guardrails: automated checks
guardrails={
"input_validation": lambda x: validate_input(x),
"output_filtering": lambda x: filter_toxic_content(x),
},
# HITL: approval required before send_email
approval_policy={"send_email": "pre_action"}
)
run = agent.run("Send summary to team")
if run.status == "waiting_for_approval":
# Checkpoint state (RunState is serializable)
saved_state = run.serialize()
# Present to human (application responsibility)
approval = present_to_human(run.pending_action)
if approval:
# Resume from checkpoint
run = agent.resume(saved_state)
Key features:
- Guardrails are automated checks registered in the agent config.
- HITL approval policy specifies which tools require pre-action approval.
- The SDK handles checkpointing via
RunState.serialize()andagent.resume(). - The application is responsible for the review UI and approval queue.
Custom Harnesses
Custom harnesses typically implement intervention through:
- Policy checks: A configuration file or function that maps actions to intervention levels.
- Approval queues: A database table or message queue where pending actions are stored.
- Saved run state: Serialized agent state (messages, context, tool calls) in durable storage.
- Resume commands: A CLI, API, or UI action that loads the checkpoint and resumes execution.
Example policy config (YAML):
intervention_policy:
send_email:
level: pre_action_approval
reason: "External communication requires human review"
git_commit:
level: post_action_review
reason: "Low risk, but log for audit"
delete_file:
level: pre_action_approval
condition: "path outside project directory"
DROP_TABLE:
level: block
reason: "Never allow in production"
Designing Intervention Policies
A good intervention policy balances safety and efficiency. Too much intervention creates fatigue; too little creates risk.
Principles for designing policies:
-
Start strict, relax over time. Begin with pre-approval for all medium-risk actions. As the agent proves reliable, move some actions to post-review or autonomous.
-
Use risk and reversibility. High-risk or irreversible actions require pre-approval. Low-risk, reversible actions can run autonomously.
-
Prevent intervention fatigue. If humans approve the same action 50 times without rejecting, consider moving it to autonomous with logging.
-
Provide context. When presenting an action for approval, include: the agent's goal, the proposed action, why the action was chosen, and the potential impact.
-
Support batch approval. For bulk operations (edit 100 files), group similar actions and allow humans to approve the pattern, not each instance.
-
Monitor approval rates. If humans reject >20% of requests, the agent's judgment is miscalibrated. Retrain or adjust the policy.
Example context for approval UI:
Agent Goal: Research cloud providers and send summary to team
Proposed Action: send_email(to="team@example.com", subject="Cloud Provider Summary")
Reasoning: Goal complete. Summary ready. No errors detected.
Risk: Medium (external communication)
Reversibility: Low (email cannot be unsent)
Email Preview:
Subject: Cloud Provider Summary
Body: [first 200 chars]...
[Approve] [Reject] [Modify Goal]
Case Study: Email Approval Gate in a Research Assistant
Scenario: A research assistant agent gathers information on cloud providers and sends a summary email to the team.
Harness design:
- The
send_emailtool is tagged as requiring pre-action approval. - When the agent calls
send_email, the harness:- Runs policy check → approval required.
- Pauses execution (agent loop stops).
- Checkpoints run state (messages, tool calls, email content) to PostgreSQL.
- Adds an entry to the
approval_queuetable with the email preview. - Returns
status: waiting_for_approvalto the caller.
Human review:
- A web UI polls the
approval_queueand displays pending approvals. - The human reads the email preview, verifies the recipient list, and clicks Approve.
Resume:
- The web UI calls
POST /api/approve_actionwith the approval decision. - The harness:
- Loads the checkpoint from PostgreSQL.
- Restores agent state (messages, context).
- Executes
send_emailwith the approved parameters. - Marks the run as complete.
Why this works:
- Persistence (Lesson 6) enables checkpoint and resume.
- Intervention (this lesson) ensures humans approve high-risk actions.
- The harness enforces the policy automatically — the agent doesn't need special code for approval.
Implementation sketch (pseudocode):
class ResearchAssistantHarness:
def run(self, goal):
state = AgentState(goal=goal)
while not state.complete:
action = self.agent.next_action(state)
if self.requires_approval(action):
# Checkpoint and pause
checkpoint_id = self.checkpoint(state)
self.enqueue_approval(checkpoint_id, action)
return {"status": "waiting_for_approval", "checkpoint_id": checkpoint_id}
result = self.execute(action)
state.update(result)
return {"status": "complete", "result": state.result}
def resume(self, checkpoint_id, decision):
state = self.load_checkpoint(checkpoint_id)
if decision == "approved":
action = self.get_pending_action(checkpoint_id)
result = self.execute(action)
state.update(result)
# Continue loop
return self.run_from_state(state)
else:
return {"status": "aborted", "reason": decision.get("reason")}
Summary
Human-in-the-loop intervention is a first-class harness concern. We covered:
- Five intervention points: pre-action approval, post-action review, goal modification, escalation, emergency stop.
- The approval gate pattern: policy check → pause → checkpoint → present → decide → resume/abort.
- Autonomy-oversight spectrum: from fully autonomous to human-directed.
- Escalation triggers: confidence, risk, cost, anomalies.
- Sync vs async: blocking (human waits) vs non-blocking (agent pauses, human reviews later).
- Guardrails vs HITL: Guardrails are automated checks (no human). HITL pauses for human decisions (requires persistence). They are complementary.
- How harnesses expose intervention: LangGraph interrupts, OpenAI SDK guardrails + HITL approvals, custom policy configs and approval queues.
- Designing policies: balance safety and efficiency, provide context, prevent fatigue.
- Case study: Email approval gate with checkpoint, approval queue, and resume.
Key takeaway: HITL is not a sign of failure. It's a deliberate mechanism to blend agent autonomy with human judgment.
Next: Lesson 8 (Observability and Debugging) explains how intervention creates events — and how harnesses make those events visible for debugging and monitoring.