The Problem
Fully autonomous agents can cause irreversible harm: sending an email to the wrong person, deleting a file, making a purchase, posting to social media. These actions require a moment of human judgment before execution, but the agent’s code shouldn’t be littered with ad-hoc confirmation prompts scattered throughout business logic.
The Solution
A HumanGate interface isolates the approval concern. The agent calls gate.RequestApproval(ctx, action) before any irreversible operation and blocks until the human responds. Two implementations cover the main use cases: TerminalGate reads from stdin for CLI tools, and ChannelGate sends requests on a Go channel — ideal for web UIs, tests, and any async approval flow. The agent’s business logic stays clean; the gate is the single seam for all human intervention.
Structure
Agent Pauses at the Gate
Before executing any irreversible action, the agent calls gate.RequestApproval(). The call blocks — the agent's goroutine is suspended until the human responds. Context cancellation propagates timeout.
sequenceDiagram participant Agent participant Gate as HumanGate participant Human participant Tool Agent->>Gate: RequestApproval(action) Gate->>Human: Display action details Human-->>Gate: approved=true, feedback Gate-->>Agent: approved, feedback Agent->>Tool: Execute(action) Tool-->>Agent: result
Implementation
package main
import "context"
// Action describes a potentially irreversible agent action awaiting approval.
type Action struct {
Name string
Description string
Args map[string]any
}
// ApprovalRequest is sent to a human gate for review.
type ApprovalRequest struct {
Action Action
Response chan ApprovalResponse
}
// ApprovalResponse carries the human's decision back to the agent.
type ApprovalResponse struct {
Approved bool
Feedback string
}
// HumanGate pauses execution and asks a human to approve or reject an action.
type HumanGate interface {
RequestApproval(ctx context.Context, action Action) (approved bool, feedback string, err error)
} Real-World Analogy
A surgeon and a circulating nurse: the surgeon calls for an instrument, but before anything irreversible is handed over, the nurse reads it back aloud for confirmation. The surgeon either proceeds or clarifies. The safety checkpoint is built into the protocol, not improvised case by case.
Pros and Cons
| Pros | Cons |
|---|---|
| Prevents irreversible mistakes in production agentic systems | Blocks agent execution — unsuitable for fully automated high-throughput pipelines |
HumanGate interface makes gates swappable between CLI, web, and test | Requires humans to be available during agent runtime |
ChannelGate enables async, non-blocking approval UIs | Approval latency adds wall-clock time to every guarded operation |
| Feedback from rejection is injected back into agent context automatically | Too many gates erode the value of automation — gate only truly irreversible actions |
Best Practices
- Gate only irreversible or high-stakes actions (send, delete, pay, post) — not every tool call. Over-gating defeats the purpose of automation.
- Always propagate
context.Contextthrough the gate so approvals can time out. - Log every
ApprovalRequestand its response with a timestamp — the approval trail is an audit record. - In tests, use
ChannelGatewith a goroutine that auto-approves; never useTerminalGatein automated tests. - Surface the human’s feedback back to the LLM via History — “rejected: email address looked wrong” helps the agent self-correct.
When to Use
- Agentic systems that take real-world actions with external side effects.
- Enterprise workflows requiring audit trails and human sign-off.
- Any automation where a mistake is costly and irreversible.
When NOT to Use
- Fully automated batch pipelines where human availability is not guaranteed.
- Low-stakes read-only tool calls — gating a web search is unnecessary friction.
- High-throughput systems where blocking on human input is architecturally infeasible.