Why Our AI Agent Asks Before It Acts, and Never Acts Twice
Two failure modes matter more than raw model capability: an agent that acts without asking, and one that accidentally acts twice. Here's how we solved both at the infrastructure level.
Two failure modes matter more than raw model capability when you're deciding whether to actually trust an AI agent with real work. The first is obvious: an agent that does something it shouldn't have, unsupervised. The second is quieter and just as damaging: an agent that does the right thing, but does it twice, sending a message a second time, creating a duplicate record, running up an API bill on a retry that should have been a no-op. Neither failure mode has much to do with how smart the underlying model is. Both are solved, or not, at the infrastructure layer sitting around it, what we've written about elsewhere as the harness. Here's specifically how ours handles both.
The default: nothing runs without a yes, tool by tool
Every tool our agent can call defaults to requiring human approval before it executes. Not as a global setting that gets toggled off in a rush before launch, but as the default on the base interface every tool is built from, so a new tool is opt-out of approval, not opt-in. The model can propose an action, drafting a message, creating a record, running a write against a database, but proposing isn't the same as doing. The action sits pending until a person says yes.
That default only earns its keep if the exceptions to it are narrow and deliberate rather than convenient. We carve out approval only for tools that are structurally read-only, ones where the action is a lookup that cannot change anything no matter what input it's given. Searching the agent's own long-term memory is one. Reading rows from its own private database with a SELECT statement is another. Both are exempted specifically because requiring a human to approve every single lookup would make the agent effectively unusable, dozens of interruptions for actions that carry zero risk, without buying any actual safety in return. Everything else, anything that writes, sends, creates, or deletes, waits for a yes.
"Read-only" is a structural test, not a feeling
The distinction that matters here is how a tool decides whether it's exempt, and it's worth being precise about it because "feels low-risk" and "is structurally incapable of causing damage" are different bars. Our database read tool doesn't just promise not to write anything, it structurally rejects any statement that isn't a SELECT or a read-only query before it ever touches the database, so there's no code path where a cleverly worded input turns a "read" into a write. That's a meaningfully stronger guarantee than a tool that's simply named and described as read-only and trusted to behave that way. When we exempt a tool from approval, we want that exemption backed by what the tool is physically capable of doing, not by what it's supposed to do.
The double-execution trap
Approval gating solves the first failure mode. It doesn't automatically solve the second, and it's worth walking through exactly how that gap shows up. Say a tool call is sitting pending, waiting for a human to approve it. The approval request goes out, and because of a flaky connection, a page refresh, or someone just clicking twice, the approval gets submitted a second time. A naive implementation runs the tool again on the second approval, because as far as it's concerned, it just received another instruction to run it. If that tool sends an email, a customer now gets the same message twice. If it charges something, that's a duplicate charge. If it writes a database row, there are now two.
We built approval handling to be idempotent specifically to close that gap. Before executing anything, the harness checks whether that exact tool call has already been recorded as completed. If it has, the second approval just returns the already-stored result instead of running the action again. The action itself only ever happens once, no matter how many times approval for it gets submitted. That's a small implementation detail with an outsized consequence: it's the difference between a flaky network connection being a minor annoyance and it being the reason a customer got double-billed.
One turn in flight per conversation, not several
A related failure mode shows up at the conversation level rather than the single-action level. Picture a user who sends a message, the agent starts generating a response, and, because it's taking a moment, the user sends a follow-up: "is this working?" A naive setup treats that as a second, independent request and starts a second generation running in parallel with the first, neither one aware the other exists. Now there are two runs racing each other against the same conversation history, and whichever one happens to finish last silently overwrites or duplicates the other's work.
We guard against this directly: a session can only have one turn actually generating at a time. A new message sent while a previous one is still in flight gets told plainly that a response is already being generated and to wait for it, rather than quietly kicking off a second, independent run. It's a small piece of friction in the rare case someone double-sends a message, in exchange for never having two competing runs for the same conversation stepping on each other's output.
What happens when a run actually gets stuck
Every meaningful step of a run, generating, waiting on tool approval, running an approved tool, gets written to a status record as it happens, not reconstructed after the fact from a chat log. That record is what turns "the agent seems stuck" from a guess into something checkable: which run, which session, which stage it was on when it stopped moving. If something inside the reasoning loop throws an unhandled error, the run is explicitly marked failed with whatever it was doing at the time, and the conversation gets a clean error message instead of a stream that just goes silent with no explanation.
That status record is also what makes a genuinely dangerous failure mode visible instead of invisible: a run that doesn't fail outright, but also never finishes, silently sitting in a "waiting" or "generating" state indefinitely because something hung rather than errored. Nothing about that looks broken from the chat window; the conversation just never gets a reply. We treat runs that have been stuck in that state for far longer than a real response ever takes as a specific thing worth flagging, which is part of a broader self-monitoring pass we run over the agent's own history, covered in more depth in a separate piece on how we watch our own agent for warning signs.
Picking a paused conversation back up correctly
When a tool call is left waiting on approval and the conversation resumes later, sometimes seconds later, sometimes as a genuinely separate request entirely, the harness has to reconstruct exactly where things left off without trusting the client's word for any of it. It reattaches to the specific run that was paused, rebuilds the model's context straight from what's actually stored in the database, the real messages, the real tool calls and their real results, and continues from there. Nothing about the resumed state is taken on the client's say-so, because the client is exactly the layer that shouldn't be trusted to accurately represent what already happened; the database is.
A concrete walkthrough: one message, sent twice
It helps to trace a realistic scenario end to end rather than take these safeguards on faith. Someone asks the agent to send a follow-up email to a client. The model drafts it and asks to run the send-email tool. Because sending an email is a write, not a read, it isn't in the small exempted set, so it pauses and waits for a human to approve it.
- A teammate reviews the draft and taps approve. The harness checks whether this exact tool call has already been recorded as completed; it hasn't, so it runs the tool, sends the email, and records the result against that call's ID.
- Their connection hiccups right as the approval request goes out, and their client, not knowing whether the first tap registered, quietly retries it a moment later.
- The second approval arrives. The harness checks the same tool call ID again, finds it's already recorded as completed, and returns that stored result directly, without touching the email tool a second time.
- The client never sees an error and doesn't need to. The email went out exactly once. Nobody had to notice the retry happened at all for the system to behave correctly.
Nothing in that sequence depended on the network behaving well, the teammate clicking carefully, or the model itself being aware a retry had happened. The correctness came entirely from the tool-call ID being the source of truth for "did this already happen," not the number of approval requests that were submitted. That's the actual test for whether idempotency has been built correctly: not whether it works when everything goes smoothly, but whether it's still correct when something, anything, gets sent twice.
Why this is the unglamorous part that actually matters
None of what's described here shows up in a five-minute product demo. A demo runs once, on a clean session, with nobody double-clicking approve or sending a follow-up message mid-response. It's exactly the boring, hard-to-see infrastructure, approval gating that's structurally enforced rather than promised, idempotent execution, an explicit run state instead of an implicit one, that decides whether an AI agent survives contact with how people actually use software: impatiently, with flaky connections, sending a second message when the first one seems slow. We wrote more generally about why that gap between demo and production is where most AI agents quietly fail; this is the specific, concrete version of us closing it in our own build, and it's the same standard we hold before recommending an AI agent to a client.