Human-in-the-Loop (HITL) Insertion Points: Where to Gate an Agent Loop
CoreConstruct Claude agents with the Agent SDK, custom loops, and hooks · Difficulty 2/5
Explanation
Deciding Where a Checkpoint Belongs
Hooks (the previous concept) give you a deterministic mechanism for gating a tool call. This concept answers a different question: where in the loop should that gate go? Run one test per step: if this step fires with nobody watching and it turns out to be wrong, how bad does that get, and can it be undone? Steps that score high on damage and low on recoverability earn a checkpoint; steps that don't, don't. Applying that test consistently is what surfaces the right insertion points.
Three Places That Test Points To
| Insertion point | What triggers the check | Risk level it addresses |
|---|---|---|
| Before a destructive tool call | The agent is one step away from a write, delete, or outbound send | High -- these actions are hard or impossible to reverse once they run |
| After a planning step | The agent has produced a multi-step plan and is about to start executing it | Medium -- a flawed plan still reaches the wrong outcome even when every individual step runs without error |
| On unexpected output | A tool result comes back with an error flag, an empty payload, or a value outside the range expected | Variable -- surfaces failures that simply retrying the call would never fix |
None of these three substitutes for the others, and relying on just one is a common gap. A pre-write gate stops a bad *action* from landing. A post-planning gate is different: it catches a *plan* that is wrong before the first action in it even runs, which a pre-write gate alone would miss since each individual step might execute cleanly. An unexpected-output gate covers yet another failure shape -- the tool didn't error out loudly, it came back with something quietly off (empty, out of range) that blindly retrying would never repair.
Why "It Passed Validation" Is Not the Same as "Safe to Commit"
A sharp version of this failure: an agent that reads, edits, and writes a configuration file re-validates after every write and only stops once validate_config returns a pass. In testing, that loop converges cleanly. In production, the agent correctly identifies an out-of-range parameter, corrects it, writes it, re-validates, and the write passes -- but the corrected value was a rate limit a downstream system depended on, and validate_config was never designed to check cross-system dependencies. The loop did exactly what it was told; the missing piece was a checkpoint between "proposed change ready" and "write committed to the live environment." That gap is precisely the *before a destructive tool call* insertion point, and it has to be designed in before the first incident, not patched in after.
Common exam traps
- Treating "the tool call succeeded" as equivalent to "the tool call was safe." A write can pass its own local validation and still be catastrophic to a system the validator never checked.
- Gating only the destructive-call point and skipping the post-planning gate. A wrong plan that executes flawlessly still produces the wrong outcome -- the destructive-call gate alone doesn't catch a bad *plan*, only a bad *action*.
- Assuming a HITL checkpoint is only relevant to the loop-wiring checklist and not a design decision. The insertion point should be decided when scoping the tool surface, not discovered after the first production incident.
Key Takeaways
- Placing a HITL checkpoint comes down to weighing how bad an unsupervised miss on that step would be against how easily it could be undone afterward
- Three insertion points cover distinct risk classes: before a destructive tool call (high risk, irreversible actions), after a planning step (medium risk, a wrong plan executed flawlessly still fails), and on unexpected output (variable risk, catches what retry logic alone won't)
- Passing local validation is not the same as being safe to commit -- a write can pass its own schema check and still break a downstream system the validator was never designed to see
- HITL insertion points should be designed in when scoping the tool surface, not added reactively after an incident exposes the gap between 'proposed change' and 'write committed'
Glossary Terms
A design pattern that interrupts the agentic loop at defined checkpoints to request human review or approval before proceeding. Used for high-stakes decisions, irreversible actions, or cases where confidence is below threshold. Balances automation with oversight.
An Agent SDK lifecycle hook that intercepts tool calls before execution. Can inspect, modify, or block the call. Used for access control, parameter sanitization, rate limiting, and audit logging. Runs synchronously before the tool executes.
An Agent SDK lifecycle hook that intercepts tool results before the agent processes them. Can normalize, enrich, or transform results from multiple tools into a consistent format. Works with both custom and third-party MCP tools without modifying their source code.
Related Concepts
Hooks as Deterministic Guardrails
Hooks (PreToolUse, PostToolUse) are code callbacks at fixed points in the agent loop and behave deterministically
Three Ways to Build the Loop: Agent SDK, Custom Loop, and Managed Agents
There are three wiring paths for an agent loop: a custom loop over the Messages API (full control, full responsibility), the Claude Agent SDK (managed loop running in your own process), and Claude Managed Agents (Anthropic runs the loop and the sandbox server-side, public beta)