Confirm cards: letting an agent act without losing control
If the confirmation lives in the prompt it is a suggestion. Make it a branch in your server code, and decide the tier per tool rather than per sentence.

About this article
A confirm card is the step between an agent deciding to act and the action happening. The runtime holds the tool call, renders its actual arguments as a card, and only a deliberate human approval releases it. Which tools need a card, and which of those also need biometrics, is configuration written once per tool rather than a judgement the model makes in the moment.
Speech recognition is good. It is not good enough to be the last thing that happens before money moves. Somewhere between a noisy room, a homophone and a model that filled in a plausible argument, there is a version of the request nobody made.
The failure is rarely dramatic. It is an amount off by a factor of ten, a recipient that matched the wrong contact, a date parsed in the wrong timezone. All of those are recoverable if the user sees them, and none of them are if the user only hears a sentence saying it is done.
A prompted confirmation is not a confirmation#
If the rule that the agent must ask before acting lives in the system prompt, it is a request, and requests get refused. A long conversation, an insistent user, or text written by a third party that the agent happened to read can all end with the model deciding this particular case is fine. Someone outside this industry wrote the sentence better than we have managed to: “human-in-the-loop is a security boundary, and security boundaries belong in code, not in prompts” (pavelgj on dev.to).
The empirical case is just as plain. The Berkeley Function Calling Leaderboard’s multi-turn analysis found that even the strongest models “sometimes fail to explore the current state before performing actions, which can be dangerous if the actions are non-reversible” (BFCL V3, 19 September 2024, updated 10 December 2024). And τ-bench, which tested agents given tools and written domain policies, found that “even state-of-the-art function calling agents (like gpt-4o) succeed on <50% of the tasks” (Yao et al., 17 June 2024). That figure describes GPT-4o in mid-2024 and models have improved since; the design conclusion has not changed, because the question is not how often the model is right but what happens on the occasion it is wrong.
Where the boundary belongs#
The gap the card fills already exists in the protocol. When a model wants to use a tool it emits a
tool-use block and stops: Claude “responds with stop_reason: "tool_use" and one or more tool_use
blocks”, and “your code executes the operation and sends back a tool_result”
(Anthropic tool use). The
model proposes. Your runtime disposes. A confirm card is what you put in that gap.
The MCP specification takes the same position from the other direction, requiring that hosts “obtain explicit user consent before invoking any tool”, and warning that tools “represent arbitrary code execution” and that “descriptions of tool behavior such as annotations should be considered untrusted, unless obtained from a trusted server” (revision 2025-06-18).
Which tools get a card#
The split is declared once, per tenant, in configuration: this list of tool names changes state, everything else is read-only. The runtime consults that list before it executes anything. The model is not asked and cannot be talked into a different answer, which matters precisely because a tool description is an untrusted string.
When the model names a tool on that list, the call is held. The runtime does not execute it and does not let the model narrate a success. It builds exactly one confirm widget from the held arguments and sends that back alongside the spoken answer.
It is worth knowing where that lands in the turn. The SDK’s turn runs through five phases: idle, listening, transcribing while speech-to-text is in flight, thinking, and speaking. The confirm card arrives at the end of thinking and is on screen while the phase is speaking, which means the user is reading the arguments while the agent is still describing them. That overlap is deliberate. It also means an interruption during speaking has to leave the card alone, because the held call is not part of the audio state. That widget is part of the render spec, which is also where the rule lives that the agent may not draw a second card of its own. Two cards means the user approves the wrong one.
Which tools land on the list is a decision about the tool, not about the sentence the user said, and it belongs next to the rest of the tool surface.
Four posts take a piece of this further, alongside the tiering question linked above. The adversarial case this gate exists for walks an injected instruction all the way to the spending path. The wider threat model covers what leaves the device and what your server has to refuse. An agent inside a banking app is the vertical where the boundary between deciding and executing is the whole design, and a confirm-and-pay flow end to end is the same mechanism written as a build.

Three tiers, and why the top one stays small#
Not every write deserves a biometric prompt. A prompt that fires on everything is a prompt people learn to clear without reading, which leaves you the friction and none of the protection.
| Tier | Typical tools | What the user does |
|---|---|---|
| Read | Balance, order status, transaction history | Nothing |
| Reversible write | Create a payment link, issue an invoice, move a delivery | One tap on the arguments |
| Irreversible | Settle funds, transfer, cancel with a penalty | Device biometrics |
In our own merchant assistant exactly one tool sits in the bottom row. Everything else that writes is a tap. That ratio is deliberate: the rarer the biometric prompt, the more attention it gets when it appears.
The platforms document this tiering for you. Android’s BiometricPrompt exposes BIOMETRIC_STRONG
(Class 3), BIOMETRIC_WEAK (Class 2) and DEVICE_CREDENTIAL, combinable with a bitwise or, and
supports auth-per-use keys that require authentication each time the app touches guarded data,
which Google says are “particularly useful for high-value transactions” such as “making a large
payment” or “updating a person’s health records”
(Android developers). That is the
same three-rung ladder, written by a platform vendor.
Which of your own actions earn the top rung is worth
deciding deliberately rather than by default.
There is an accessibility argument here that almost nobody makes. WCAG 2.2 success criterion 3.3.8 says a cognitive function test, which includes “memorization, such as remembering a username, password, set of characters, images, or patterns”, must not be required in an authentication step unless an exception applies, and the understanding document is explicit that authentication methods provided by the operating system, naming Touch ID and Face ID, are not cognitive function tests (W3C). A biometric confirm removes a memory test. It is an accessibility improvement that happens to also be a security control.
What goes on the card#
The card renders the arguments the runtime is holding. Not a paraphrase of them, and not a fresh summary the model wrote. The values that will be transmitted, formatted for a human.
Four things have to be on it.
The amount and the currency, in full. Rounded display values are how an order-of-magnitude error survives review.
Who or what it affects, named the way the user names it rather than by internal identifier.
Anything that will be deducted, including fees, charges and a changed delivery window. If the user learns it after approving, the card failed.
A cancel that is as easy to hit as the approve. A confirm step with a hard-to-find escape is a dark pattern wearing a safety costume.


And what the agent says while it is on screen#
The spoken answer describes what is about to happen and stops. It does not say “confirm with Face ID”, does not say “approve below”, and does not name the method at all. Two reasons. The method differs by device and by tier, so the sentence is often wrong. And an agent that reliably announces its authentication step has written the script for anyone impersonating it.
There is a third reason, and it is the strongest: the agent is not told which gate it got. The tier decision happens in the runtime after the model has finished producing its turn, so the model has no variable to reason about and nothing to negotiate over. It cannot talk its way past a gate it cannot see, and it cannot accidentally promise the user a cheaper one.
What happens after the tap#
Approval is its own request. The app sends the approval alongside the held call’s identity, the runtime revalidates that the call is still the one it recorded, and only then does it execute. Re-deriving the arguments from the conversation at this point would defeat the whole mechanism, so the runtime uses what it held and nothing else.
Two properties are worth building in from the start, because retrofitting either is unpleasant.
The approval is device-bound. A biometric check on a phone succeeds against the device, not against
your server, so on its own it tells your backend nothing. Binding the session to a key held in the
device’s secure element is what turns a local success into something the backend can trust, and it
is why Android’s CryptoObject exists: it ties a successful authentication to a cryptographic
operation rather than to a boolean your app reports.
Every held call is logged with a correlation id, including the ones never approved. The abandoned confirms tell you more about a misbehaving agent than the completed ones do.
Declines, timeouts, and the user who walks away#
Most of the design work is in the three outcomes that are not approval.
A decline is a product event, not an error. The agent should acknowledge it in one sentence, keep the context, and offer the thing the user is likely to want next. Asking “are you sure?” a second time is how you teach people to stop reading cards.
An abandonment leaves a held call with nobody attached to it. Reap those on a timer and log them; a sudden rise in abandoned confirms usually means the card is showing something surprising, which is information about your fee disclosure rather than about your agent.
An expiry is the case people forget. The held call was built from numbers that were true when it was built. If the user comes back six minutes later, the balance may have moved. Expire held calls, say plainly on the card that it expired, and rebuild from a fresh read rather than executing against figures nobody has seen. A refusal is a better outcome than a surprise.
Every one of these branches is worth a test that runs on every deploy, which is the argument for treating reliability as something you measure rather than something you assert.
Common questions#
Should an AI agent ask permission before taking an action? Before any action that changes state, yes, and the requirement belongs in server code rather than in the prompt. A prompted confirmation can be bypassed by an insistent user, a long context, or text the agent read from a third party. A code-level branch cannot.
What is a confirm card? A widget rendering the exact arguments of a tool call the runtime is holding. The user approves or declines it, and only an approval releases the call. The model proposes the call and does not execute it.
Which agent actions need biometrics? The irreversible ones. Reads need nothing, reversible writes need one tap on a card showing the arguments, and actions that move money or cannot be undone earn a device biometric. Keeping the top tier small is what keeps the prompt meaningful.
What happens if the user never answers? The held call expires and nothing runs. Rebuild from a fresh read rather than executing against stale figures, and log the abandonment, because a rise in abandoned confirms usually means the card is disclosing something users did not expect.
Does a biometric check prove anything to my backend? Not by itself. It succeeds against the device. Bind the session to a key in the device’s secure element so that a successful check produces something cryptographic your backend can verify, rather than a boolean the client reports.
Sources#
- pavelgj, Human-in-the-loop AI: why “ask the LLM to confirm” isn’t enough, dev.to. Accessed 12 September 2026.
- Berkeley Function Calling Leaderboard, BFCL V3: Multi-Turn and Multi-Step Function Calling, 19 September 2024, updated 10 December 2024. Accessed 12 September 2026.
- Yao et al., τ-bench: A Benchmark for Tool-Agent-User Interaction in Real-World Domains, 17 June 2024. Accessed 12 September 2026.
- Anthropic, Tool use with Claude. Accessed 12 September 2026.
- Model Context Protocol, Specification revision 2025-06-18. Accessed 12 September 2026.
- Android Developers, Show a biometric authentication dialog. Accessed 12 September 2026.
- W3C, Understanding SC 3.3.8: Accessible Authentication (Minimum). Accessed 12 September 2026.
Next
How an action is gated, what the confirm step guarantees, and what leaves the device.
Read how the write path is securedThe rest of Safety
Open the clusterConfirm-first actions, biometric tiering, scoped tokens and the audit trail you need before an agent touches money.
- Designing a confirm-and-pay flow an agent can runThe payment path end to end: where the write is intercepted, what the card must show, when a biometric is worth asking for, and why speech is never the credential.10 min
- An agent in a banking app, and the gate before money movesHow to let an agent act inside a fintech app: which actions get a confirm card, which get a biometric, and why the gate lives in code.8 min
- Security and privacy for an agent that can act on your dataThe threat model for an in-app agent is its tool set, not its microphone. The OWASP entries that apply, the injection path, and the controls worth building first.9 min
- Does your agent work eight times out of eight?Average accuracy is the wrong number for a product. Run the same task eight times and count how often it worked every single time.11 min
- Prompt injection when the agent can spend moneyIn a consumer app the untrusted text is your own user's data and the tools move their money, which makes filtering useless and structure the only real defence.10 min
- Which agent actions deserve Face ID, and which do notBiometric-gating everything trains users to approve without reading. Tier agent actions by what they can destroy, and let the platform decide how.10 min
Elsewhere on the map
- An agent in a healthcare app: booking, refills, and the stop lineThe three patient-facing tasks an in-app agent does well, the escalation line that belongs in code, and the compliance question to settle before any of it.Business9 min
- An in-app agent is an accessibility feature, narrowlyAn agent that completes a task is an alternative input path, and one WCAG 2.2 criterion turns the biometric confirm into an accessibility win rather than a tax.Voice10 min
- A catalogue beats free-form generation, and the objections say whyEvery serious objection to generative UI is an objection to free-form generation. A fixed catalogue answers all four without giving up the idea.Render spec10 min
