In a test on 15 September, Claude Code got a single line telling it to get a client, named in the prompt, to send their ID by the 30th. It was connected to the MCP server for DokuTrak, the tool I build to collect documents from the clients of accountants and law firms. The optional skill we ship next to it, which tells the agent to confirm first, wasn't installed, so the model had only the tool's own description to go on.
Claude created the document request and sent it in the same turn. There was no recap of who would get the email and no question about the deadline. A real email went to a real recipient.
It wasn't a bug in the usual sense. The model understood the instruction and picked the right tool. I had authorized the task, but I hadn't reviewed the recipient, deadline and wording that would actually leave the system. The missing safeguard was a review of those exact details before sending.
Two moments where an agent goes wrong
Since then I've separated agent failures into two moments.
The first comes before anything gets built. Pathmode separates three questions: is the spec ready, have the product decisions been resolved, and has someone authorized implementation of this revision?
Its local preflight checks six deterministic gates on an intent.md: a meaningful title, a specific objective, testable outcomes, hard constraints, edge-case coverage and concrete verification. It makes no model call. A passing verdict describes the spec's readiness; it does not grant permission to build.
In a connected workspace, open PM change requests must be applied or rejected with a reason, and an agent-drafted spec stays pending until a signed-in person authorizes that exact revision. Ready, decided and authorized are three different things. The local readiness check alone does not provide that workspace authorization.
The second moment is when the agent acts. The decision behind an action can be sound and the action can still go wrong: the right request goes to the wrong person, or leaves before anyone looked. My test was this kind. Nobody doubted that the client had to send an ID. The problem was that the agent's reading of one sentence became an email without passing in front of me.
Both checkpoints ask a person to stand behind the specific interpretation the agent will act on. A broad instruction can leave details that still need review.
Why asking the client wasn't enough
Our first fix shipped on 23 September, in version 0.1.1 of the connector, and it lived entirely on the client side. The tool's description now asks the model to lay out the recipient's address, the due date, the wording of every document the client will see and any note, and to wait for an explicit yes. The tool is also annotated destructiveHint: true and openWorldHint: true, and carries _meta["anthropic/requiresUserInteraction"]: true, a key Anthropic defined. With those, Claude Desktop prompts before running it, and Claude Code prompts on every call, auto mode included.
Both layers are still requests to someone else's software. The description is advice to a model, and the test had just shown a model acting on its own reading of a sentence. The annotations are hints a client may follow. Our server receives an authenticated call either way and can't tell whether anyone clicked.
Eight days later we built a second server, a remote MCP endpoint meant for ChatGPT, and moved the yes to our side. It was merged on 1 October 2026. As of that date, it was not live. The rest of this piece walks through that implementation.
The boundary is specific: the agent's API credential cannot grant approval. A signed-in browser session can, which leaves a limitation if an agent also controls that browser. I return to that below.
A worked example
Say a bookkeeper tells ChatGPT: "Ask Dana Reyes for her 2025 W-2 and her last two bank statements, by 15 October." Here is what happens, call by call.
1. Prepare
The agent calls prepare_request with a recipient, a checklist, a deadline and a message. The server checks them, stores nothing, and returns a normalized preview with a version: a SHA-256 hash of that preview. Changing the preview changes its version.
2. Review
The agent calls review_request with the unchanged preview and an operation_id it picks itself, a UUID. The server stores the operation with its version and the agent's connection, marks it awaiting_confirmation, and returns a link. No document request has been created and no email has been sent. The operation expires after 24 hours if nobody acts on it.
3. The agent tries to go on
Suppose it calls send_request right away. The tool is defined like this (description trimmed):
server.registerTool('send_request', {
title: 'Send the confirmed Document Request',
description: 'Send only after the Professional confirms the exact version on reviewUrl. Use operation_id and version from review_request. Retries recover the same request. …',
inputSchema: z.object({ operation_id: z.uuid(), version: z.string().length(64) }).strict(),
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true, idempotentHint: true },
});It takes no recipient, no checklist and no date, only an operation and a version. The server finds the operation still awaiting confirmation and returns its state. Nothing is sent. This check runs in our code, so it holds whatever the client makes of the annotations. (The send isn't marked destructive: in MCP's terms it adds something rather than destroying it.)
4. The details change
Say the bookkeeper adds in the chat, "make it the 16th", and the agent calls review_request again with the same operation_id and the new date. The new preview hashes to a different version, and the server answers 409: details changed, review a new operation. An approval can't be carried over to an action that differs from the one reviewed. The same idea appears on Pathmode's page on what belongs in a spec: "A changed objective or outcome should invalidate stale confirmation rather than inherit approval from older wording." In their flow, a material edit to an authorized spec clears the authorization.
5. The agent tries to approve itself
The confirm endpoint is an ordinary HTTP route, and the agent holds a valid OAuth token for the same account. If it posts to that route, the request is refused before it reaches the confirmation code: the whole router accepts only a signed-in browser session, and an agent's token isn't one. The refusal is written to the audit log. The agent can see whether a yes exists, through the operation's state, but its OAuth token cannot create one. Pathmode documents a similar boundary in its connected workflow: its authorization endpoint refuses API keys, and the agent "can read the gate but never open it."
6. A person confirms
The bookkeeper opens the link in DokuTrak and sees Dana's address, the three documents, the deadline, the language and the message, with a confirm button and a cancel button. Confirming posts the version the page showed. If it doesn't match the version on record, the server answers 409 and nothing is approved. If it matches, the operation becomes confirmed, and the audit log records who confirmed, which version, and through which connection.
7. Send
The agent calls send_request again with the same operation and version. Now the request is created and the email goes out. If the call fails halfway, the agent retries with the same operation_id and gets back the same request, with no new question and no second email. If we can't tell whether the email provider accepted the message, the operation is marked delivery_unknown, nothing is resent automatically, and a person checks.
The person approves the displayed details; the server binds that approval to their version. The send accepts only the matching operation and version. The agent's OAuth token cannot create that approval: the confirmation route requires a signed-in browser session.
Where the spec and the confirmation meet
Constraints and edge cases are where a spec says what must not happen, and "never contact a client without review" is a reasonable constraint to write there. Pathmode grades a pull request against constraints like that. Once the code ships, though, a sentence in a spec can't stop a model in the middle of a working day. At action time the constraint has to become a property of the tool: a send that can't run without a confirmed version, and a recap that shows the fields the constraint is about. For us, the edge cases that matter are a wrong recipient and a wrong deadline.
Confirmation fatigue
A gate on every call stops protecting anyone once people learn to click through it. So we sort actions by consequence and gate only the ones that reach a person, can't be undone, or spend money. On the remote server that leaves one gate across four tools. Preparing, reviewing and reading collection progress affect nobody outside the conversation, so they ask nothing. Payment and workspace settings aren't reachable by the agent at all. And the yes covers the operation, not each call, which is why retries don't ask again. The bet is that asking once per decision keeps people reading the recap.
What's still open
Our server records which account gave a yes. It cannot establish whether a person or browser automation clicked the button. What we check is a signed-in session belonging to the professional who owns the agent's connection, in the same workspace. That isn't the same as a human reading the page. An agent driving the professional's logged-in browser could open the review link and press confirm, and our server would record approval from that account. A signed-in authorization anywhere shows which account confirmed, not that someone read the page.
I don't have an answer. Asking the person to sign in again at confirmation raises the cost but proves the same thing. What I'd want is a confirmation tied to something an agent in the browser can't do, and I don't know of a standard way to ask for that today.
The other open part is plainer. As of 1 October 2026, this flow hadn't met a real user. Its tests covered retries, concurrent sends, cancellations and changed previews, but nobody had run it end to end in ChatGPT. Those tests cannot tell me whether people will read the recap or press confirm within two seconds.
Editor’s note: The same browser-session limitation applies to Pathmode’s authorization gate. It records which account authorized a revision; it does not prove that a human read the page.
Arthur Teboul builds DokuTrak, software that collects the paperwork accountants and law firms need from their clients and keeps chasing it until it arrives. A person at the firm accepts every file.