Approval buttons are weirdly easy to overestimate.
The product has a scary action. The agent wants to do something with side effects. The team adds an approval step. There is a button. The user has to click it. The system now feels safer.
Maybe.
The button only helps if the person clicking it can make a real decision. If the user sees “Approve” next to a vague agent sentence, the product has mostly transferred anxiety from the system to the human. That is not review. That is a ritual.
Agent approval needs context at the exact moment the interface is most tempted to hide it.
the decision should be about the work
I do not want approval copy that asks whether the agent can “continue.”
Continue is too broad. It makes the human approve the agent’s confidence instead of the actual work. The interface should name the action in terms the user already understands.
Weak:
Approve tool call?
Better:
Replace the draft introduction in
chatgpt-work-made-desktop-agents-feel-inevitable.mdx.
Better still:
Replace 4 paragraphs in
chatgpt-work-made-desktop-agents-feel-inevitable.mdx, then runpnpm markdown:checkon that file.
That version gives the human something to inspect. The target is named. The scope is visible. The follow-up command is explicit. If the user expected a grammar cleanup and the agent is about to rewrite the whole argument, the mismatch has a chance to surface before the action happens.
Approval should point at the work, not at the agent.
show the thing that changes
The most useful approval surface is usually a diff, preview, or structured summary of the side effect.
For file edits, show the diff. For an email, show the exact recipient, subject, and body. For a calendar event, show the date, time, attendees, and description. For a database operation, show the table, filter, row count, and fields being changed. For a GitHub action, show the repository, issue or pull request target, comment body, labels, and account.
The user should not have to infer the side effect from the tool name.
Tool names are developer language. updateRecord, sendMessage, createIssue, and runCommand can each be harmless or dangerous depending on arguments. A good approval prompt treats arguments as first-class product copy.
I like this shape for a human-facing approval card:
action
edit local file
target
src/content/blog/approval-buttons-need-context.mdx
change
replace current body with a rewritten article draft
why
current post is generated template residue
after approval
write file, run markdown check
undo
restore previous file contents from git diff
That is not fancy, but it answers the right questions. What is happening? Where? Why? What follows? How do I get back?
hide less when risk goes up
Approval UI should change shape based on risk.
A low-risk read action can be compact. If the agent wants to read a file inside the active project, a short inline prompt may be enough. The user probably does not need a modal full of ceremony.
A write action needs more room. A destructive action needs even more. A credentialed external action needs identity and destination. A shell command needs working directory, command text, expected output, and whether it can modify files or reach the network.
The interface should not treat all approvals as the same little confirmation.
This is where I get picky about collapsed details. Hiding details by default can make sense for routine actions, but risky actions should start expanded. If the user has to click “more” to discover that the agent is sending data outside the workspace, the UI is working against them.
The product can still stay calm. Context does not require panic styling. It requires visible facts.
timing is part of context
An approval prompt can be accurate and still arrive too late.
If the user asked the agent to make a plan, then walked away, then came back after the conversation drifted, the approval needs to reconnect them to the current state. The prompt should explain which user request caused the proposed action and whether anything changed since then.
Stale approvals are a real failure mode. The model proposes an action based on old context. The user approves because the prompt looks reasonable in isolation. The result is technically authorized and still wrong.
I want approval prompts to carry a little history:
- original request
- current plan step
- files or resources already inspected
- assumptions the agent is using
- what will remain undone after this action
That last one is easy to miss. Approval does not mean the whole task is finished. It means one step is allowed. If the action is part of a longer run, the user should know whether the agent will stop afterward, continue automatically, or ask again.
evidence beats persuasion
The agent should not argue the user into approval.
This is a subtle problem because models are good at sounding helpful. “I need to do this to complete your request” is not evidence. It is pressure with friendly grammar.
A better prompt shows the evidence that led to the action:
- the file contains the broken generated text
- the requested scope was “rewrite this post”
- the target path matches the current checklist item
- the command is the configured Markdown checker
Evidence lets the human verify the chain without trusting the model’s confidence. It also gives reviewers something to inspect later if the approval was a mistake.
I would rather see three blunt facts than one polished paragraph about why the agent believes the action is appropriate.
denial should be useful
Rejecting an approval should not be a dead end.
The product should let the user say why, at least cheaply. “Wrong file,” “too broad,” “show me the diff first,” “use a different command,” and “stop the run” are different decisions. If every denial becomes a generic failure, the agent loses information it could have used to recover.
Denial reasons also help the product improve. If users keep rejecting actions after expanding details, the approval summary is probably too vague. If they reject because the target is wrong, the agent may be carrying stale context. If they reject shell commands more than file edits, the command prompt may need clearer risk language.
The button should not be the end of the conversation. It should be a fork in the workflow.
approval needs a receipt the user can read
After approval, the product should leave a record that says what was approved and what actually happened.
This is where a lot of systems get lazy. They log the tool call but not the human decision. Or they log the decision but not the final side effect. Or they keep everything in an internal trace that the user cannot see.
For agent work, I want a receipt that can be shown in the product:
approved by
jeremy
approved action
edit local markdown file
approved target
src/content/blog/approval-buttons-need-context.mdx
executed
yes
verification
pnpm markdown:check passed for this file
The receipt does two jobs. It helps the user trust the run, and it gives the next review pass a starting point. If something went wrong, the question changes from “what did the agent do?” to “where did the approved plan diverge from the result?”
That is a much better debugging problem.
a good button slows the right moment
I do not want approval steps everywhere. Too many prompts turn users into click-through machines. The product should reserve them for moments where the decision matters.
But when the decision matters, the button has to earn the click.
Show the plan. Show the affected resource. Show the data or diff. Show the identity. Show what happens next. Show how to recover. Keep the copy concrete. Let denial teach the system something.
The approval button is small. The context around it is the feature.
Related posts

About Jeremy London
Engineering leader and builder in Denver. I write about AI platforms, agents, security, reliability, homelab infrastructure, and the parts of engineering work that have to survive production.