The agent is about to commit a refund, send an email, or push a change. You want the workflow speed of an agent and the certainty that a human said yes before the irreversible part.
Refunds, account changes, infra changes, money movement, customer-visible communication, deletes.
Internal read-only operations, search, summarisation, draft generation. Approval gates kill UX when the action is reversible.
Drop this into an app.yaml. Adjust the credential refs and module names to fit your existing setup.
1schema_version: 223app:4 app_id: human-in-the-loop5 name: "Human in the loop"6 version: "1.0.0"78modules:9 http: {}10 context_builder: {}1112runtime:13 mode: conversation14 entry_agent: ops15 hooks:16 - id: gate_destructive17 "on": tool_start18 condition:19 type: all_of20 conditions:21 - { type: tool_name, match: "http.request" }22 - { type: expression, expr: "tool.params.url contains '/refund' or tool.params.url contains '/delete'" }23 action:24 type: gate25 reason: "Confirm {{tool.name}} to {{tool.params.url}} before it runs."2627tools:28 capabilities:29 grant:30 - { module: context_builder, tools: [ask_user] }3132agents:33 - id: ops34 modules:35 - {http: [request]}36 - {context_builder: [ask_user]}37 brain: { provider: anthropic, model: claude-sonnet-5, credential: { ref: anthropic_main, scope: per_user, provider: anthropic } }38 system_prompt: |39 Before any irreversible request (refunds, deletes, sends), call40 ask_user with a one-line summary and yes/no choices. Only proceed41 when the user picks "yes". A gated call means a human hasn't42 confirmed yet - do not retry it silently.Walking through the YAML one block at a time so the design is clear, not memorised.
The system prompt teaches the agent to ask first. The hook enforces it: even if the agent forgets, the runtime gates destructive calls before they reach the network.
context_builder.ask_user pauses the agent, surfaces the question to the user, and resumes when they answer. The choice becomes a normal tool result the agent reads.
The gate action on tool_start blocks the specific irreversible call outright, with a reason the model (and the user, in logs) can read.
tools.capabilities.grant explicitly names context_builder's ask_user tool - nothing is implicitly available, every capability is a deliberate line in the YAML.
The pattern above is not the only answer. Here is when something else is the right call.
Have the agent emit a plan first, the user approves the plan, then the agent executes the whole plan without per-step prompts. Less interruption, larger blast radius if approval is given to an underspecified plan.
Agent does the work, posts a draft for human review elsewhere (a message, a ticket). Humans approve later. Higher throughput, weaker safety because the action is already taken.
Engineering notes from the Digitorn team. No marketing, no launch announcements, no "10 prompts that will change your life". Just the things we write that we'd want to read.