Agent UX: Showing Reasoning, Progress & Approvals
Introduction
This is the finale of Designing AI Product Experiences — and it's the hardest case, because agents break the chat model entirely. A chatbot answers a turn; an agent is given a goal and then works autonomously — planning, calling tools, browsing, writing code — for minutes or hours, and it acts on the world (sends the email, charges the card, edits the repo).
The reframe: with an agent, the user isn't a chatter, they're a supervisor. Your UX job is to make the agent's work legible (you can see what it's doing and why), steerable (you can stop and redirect it), and safe (it can't do something irreversible without your say-so). The whole lesson is one phrase: supervised autonomy — let the agent move fast when it's safe, and stop for a human when it isn't.
The agent-UX trifecta, in this lesson:
- Show reasoning & progress — a legible activity timeline of plan, steps, and tool calls
- Progress as layered status — ambient → progress → attention → summary, without notification fatigue
- Approvals — human-in-the-loop gates that fire before consequential actions
- Interruptibility — stop and steer at any moment
- and a recap of the whole section, because agent UX is where all of it comes together.
Scope: this is the UX of agents. What an agent is and how it works — the loop, planning, tools, memory — is the Agents section. Here we design what the supervising human sees and controls. It builds directly on L224 (Treating Latency as a Product Feature), L226 (Showing Your Work: Citations, Sources & Confidence), and L227 (Defensive UX: Designing for Uncertainty & Failure).

Agents Break the Chat Model
Everything before this lesson assumed a turn: the user asks, the model answers, maybe it streams. Agents violate every part of that:
- They're long. A chat reply is seconds; an agent task is minutes to hours. You can't just show a spinner or stream one reply — you need to represent ongoing work.
- They're autonomous & multi-step. The agent decides its own next action in a loop. The user isn't driving each step — so they need a way to watch, trust, and intervene.
- They act on the world. Tools have side effects — irreversible ones. A wrong chat answer is embarrassing; a wrong action (email sent, money moved, file deleted) is a real incident.
So the mental model flips: the user becomes a project manager of an AI worker. Good agent products behave like a good employee would — they set expectations up front (here's the goal, roughly how long, what it'll cost), report status as they go, ask before doing anything risky, and let you redirect them. Get that relationship right and users trust the agent with bigger jobs; get it wrong and a single silent, irreversible mistake ends the trust permanently.
The throughline of the whole section pays off here: an agent is a slow (L224), streamed (L225), fallible (L227) thing that acts — so it needs perceived-progress design, show-your-work transparency, defensive gates, and session persistence, all at once.
Show the Work — A Legible Activity Timeline
The foundation of agent trust is transparency: the user can see what the agent is doing. The pattern is a live activity timeline — the agent's plan and each action as it happens:
- The plan first. Surface the agent's plan up front ("1) find the leads, 2) draft, 3) send") so the user knows where it's headed and can course-correct before it's spent an hour.
- Each step, with its tool calls. Show the tool name, the arguments, and the result —
search_crm("yesterday") → 3 leads. This is what makes a run auditable (Manus: every action auditable; Claude in the browser: you see every click as it happens). - Reasoning, collapsibly. Offer the agent's reasoning/thinking in an expandable panel — useful for debugging and trust, collapsed by default so the answer/result stays front-and-center.
But carry forward the caveat from L226 (Showing Your Work: Citations, Sources & Confidence): a shown chain-of-thought is a readable, post-hoc summary — not a faithful transcript of the computation. It's an explanation aid, not proof. The verifiable part of an agent run is its actions and their results (the tool calls), not its narrated thoughts — so make the actions legible above all.
Progress Without the Pestering — Layered Status
A minutes-long run creates a hard UX question: how much do you interrupt the user? Too little and they feel abandoned; too much and they tune you out. The answer is a layered status model — four levels, each for a different need:
| Layer | What it is | When |
|---|---|---|
| Ambient | a persistent, unobtrusive badge ("working…") | always, while running |
| Progress | a glanceable panel on demand (current step, plan, ETA) | when the user chooses to look |
| Attention | an interrupting notification | only when the agent needs a decision |
| Summary | a completion report you can read in ~10s | when it finishes |
The rule that makes this work: an interrupt is for a decision, not a status. Every notification you fire spends a little of the user's willingness to look at the next one — burn it on "step 3 of 7 done" and the one alert that matters (an approval, a failure) arrives to someone who's already learned to swipe you away. Push the decisions; let status be pulled.
Two more progress rules:
- Set expectations up front (L224 — Treating Latency as a Product Feature): a rough ETA and scope turn a scary open-ended wait into a tolerable, legible one.
- Never show hallucinated progress. Don't mark a step "done" on the model's say-so — verify it (a deterministic check) before advancing, or you'll cheerfully report success on work that never happened.
Let the user be a relaxed manager: a calm ambient signal they can ignore, a panel they can open when curious, and a tap on the shoulder only when they're actually needed.
See It — The Agent Run Lab
Supervise a real-feeling run. Hit Run, watch the plan and tool calls stream, and handle the approval gate when the agent wants to do something irreversible — read the arguments carefully:

Everything important happened at the gate: the agent wanted to send_email to four recipients — and one, all-staff@, was hallucinated. If you approved without reading, you leaked it; if you edited or rejected, you caught it. That's the whole point of an approval gate — it only protects you if it fires before the send and shows the exact arguments. Next, the principles behind it.
Approvals — Gate the Consequential, Before the Side Effect
This is the safety core of agent UX, and it builds straight on L227 (Defensive UX: Designing for Uncertainty & Failure). When an agent's next action is consequential — irreversible, costly, regulated, or high blast-radius — you pause and ask a human first. The non-negotiable rules:
- Before the side effect, not after. An approval that fires after the email is sent is just retrospective review — useless. The executor must pause the run before the tool fires and resume only on approval.
- Surface the exact arguments. The approval must show the real call the model produced — who the email goes to, how much is being charged — because those args can be hallucinated, and the approver is the last line of defense. Make the arguments easy to scrutinize (the lab's
all-staff@is the whole lesson). - Approve / edit / reject — then resume. Let the human fix a bad argument inline, not just say yes/no, and resume the run from the same state.
- The gate lives outside the model. As in L227, "ask before sending" in the prompt is not a gate — the agent can ignore or hallucinate approval. The gate is infrastructure: the tool is marked approval-required, and the executor refuses to run it until an out-of-band approval clears.
# Supervised autonomy: the agent runs free, but a CONSEQUENTIAL tool pauses for a human.
@tool(approval="always_require") # gate it OUTSIDE the model — config, not a prompt instruction
def send_email(to: list[str], subject: str, body: str): ...
run = agent.run(task)
while run.needs_approval: # SDK pauses BEFORE the side effect and returns the pending call
call = run.pending_action # surface the EXACT args the model produced — they can be wrong
decision = await human_review(call) # approve / EDIT the args / reject — the last line of defense
run = agent.resume(run, decision) # resume from the same state; the email sends only NOW, if approvedSupervised autonomy is the balance: gate only the consequential actions (per the severity × reversibility matrix from L227) so the agent stays fast on the safe 95%, and don't over-gate the trivial — approval fatigue trains users to rubber-stamp, which is the same as no gate at all.
Interruptibility — Keep the Human in Control
An autonomous run the user can't stop is a runaway, not a product. Three controls keep them in the driver's seat:
- Stop, instantly. A always-available halt that actually aborts the work (and stops the spend — the cancellation discipline from L227). The user should never feel trapped watching an agent do the wrong thing.
- Steer mid-run. Let the user course-correct without starting over — "actually, skip the third lead" — so the relationship is a dialogue about the process, not a fire-and-pray.
- Resume & revisit. Long runs span sessions (L229 — Multi-Turn Conversation & Session Management): pause, come back, and the agent's state (its plan, progress, and tree of actions) is intact.
The feeling to engineer is "I'm in control of a capable worker," not "I set off a process and I'm hoping." Stop and steer are what convert an impressive demo into something people trust with real work.
Bringing the Section Together
Agent UX is the finale because it needs everything Designing AI Product Experiences taught — an agent is where all seven principles converge:
- L224 — Treating Latency as a Product Feature: an agent runs for minutes, so you design the perceived wait with layered progress.
- L225 — Streaming UX (TTFT, Token-by-Token, Markdown Buffering): its reasoning and tool output stream in, rendered cleanly.
- L226 — Showing Your Work: Citations, Sources & Confidence: its actions and sources are shown and verifiable (and its reasoning is an aid, not proof).
- L227 — Defensive UX: Designing for Uncertainty & Failure: consequential actions are gated, reversible, and recoverable.
- L228 — Feedback UI & Human-in-the-Loop (The Data Flywheel): the human's approvals, edits, and corrections are the signal that makes the agent better.
- L229 — Multi-Turn Conversation & Session Management: the run is a persistent, branchable session you can resume and steer.
- L230 — Agent UX (this lesson): tie it together into legible, steerable, safe autonomy.
The one sentence for the whole section: you don't just make the model good — you design the experience around it so users can wait, read, trust, recover, improve it, stay coherent, and supervise it. That experience is the product.
🧪 Try It Yourself
Use the Agent Run Lab and what you've learned:
- In the lab, Approve the send without editing. What got emailed, and what does that prove about approval gates?
- Why must the approval gate fire before
send_emailruns — what's wrong with reviewing it after? - Your agent runs for 20 minutes. Design its status: what should be ambient, what's on-demand, and what earns an interrupting notification?
- A teammate secures the agent by adding "always ask before sending email" to the system prompt. Why isn't that a real gate (callback to L227)?
- Which actions should require approval, and which should the agent just do? Give the rule.
→ (1) It emailed all-staff@, a hallucinated recipient — proving an approval gate only protects you if you scrutinize the exact args; rubber-stamping is the same as no gate. (2) After the send, it's irreversible — you can't un-send. The gate must pause before the side effect so a human can stop it; a post-hoc review is just a log. (3) Ambient: a persistent "working…" badge. On-demand (progress): a panel with the plan, current step, and ETA. Interrupt (attention): only a real decision — an approval, or a blocking failure — because an interrupt is for a decision, not a status (and don't show hallucinated progress). (4) A prompt instruction lives inside the probabilistic model — it can be ignored, jailbroken, or have approval hallucinated. A real gate is infrastructure outside the model: the executor refuses to run the tool until an out-of-band approval clears. (5) Gate the consequential — irreversible, costly, regulated, or high-blast-radius (the severity × reversibility matrix from L227); let the agent act autonomously on the safe, reversible majority. Fast when safe, human when not.
Mental-Model Corrections
- “Agent UX is just chat UX for longer.” No — agents are autonomous, long-running, and act on the world. The user is a supervisor, and the UX is legible, steerable, safe.
- “Show a spinner while the agent works.” A minutes-long run needs layered status (ambient / progress / attention / summary), not a spinner — and interrupt only for decisions.
- “Showing the agent's reasoning proves it's right.” Reasoning is a post-hoc summary (L226), not proof. The verifiable part is its actions and results.
- “Log the actions and let users review them.” Review after an irreversible action is too late. Gate consequential actions before the side effect.
- “The approval just needs a yes/no.” Show the exact args (they can be hallucinated) and allow edit, not just yes/no — the approver is the last line of defense.
- “The system prompt tells it to ask first, so it's gated.” A prompt is not a gate. The gate is infrastructure outside the model (callback to L227).
- “Gate everything to be safe.” Over-gating trains rubber-stamping. Gate only the consequential; stay autonomous on the safe majority — supervised autonomy.
Key Takeaways
- Agents need a supervisor's UX: they're autonomous, long-running, and act on the world, so design for legible, steerable, safe — supervised autonomy (fast when safe, human when not).
- Show the work: a live activity timeline (plan → tool calls with args + results) makes the run auditable; offer reasoning collapsibly — but it's an aid, not proof (the actions are the verifiable part).
- Progress is layered: ambient → on-demand progress → interrupt-only-for-a-decision → summary. An interrupt is for a decision, not a status — and never show hallucinated progress (verify before advancing).
- Approvals gate the consequential, before the side effect: surface the exact (possibly hallucinated) args, allow approve / edit / reject, resume from state — and keep the gate outside the model (L227). Gate only irreversible/costly/regulated actions.
- Keep the human in control: instant stop and mid-run steer; a long run is a resumable session (L229).
- The section, in one line: you don't just make the model good — you design the experience around it so users can wait, read, trust, recover, improve, stay coherent, and supervise it. That experience is the product.