Patterns / Approval UI

Human-in-the-loop approval UI for AI agents

An agent that changes things should ask first. There are two kinds of asking. The person in the chat allows or denies a tool call before it runs. Or a second person approves a change someone else asked for, because nobody should approve their own.

For the first, the adapters (useCandorChat, useClaudeAgent, useAgUi) give you approvals, the tool calls waiting on a person, and respond(id, approved, reason) to answer one. PermissionPrompt draws one: why it reached the person, the run's permission mode, the input they can edit before allowing it, and "don't ask again" rules nobody has ticked. Or draw your own buttons where you want them.

For the second, ApprovalRequest shows what changes, where, what it touches, whether it can be undone, and a hash that ties the decision to exactly that change. ApprovalQueue lists the requests by what they need from the viewer. A person who can't decide sees why on the button.

The components

  • Permission promptFreeOne tool call waiting on the person: why it asked, the mode, edit before allowing, opt-in "always allow".
  • useCandorChatFreeVercel AI SDK: the tool calls waiting on a person, and respond() to answer them.
  • useClaudeAgentFreeClaude Agent SDK: the same shape, answered through your approve route.
  • useAgUiFreeAG-UI: interrupts waiting on a person; answering them resumes the run.
  • Approval requestProA request for second-person approval, tied to the exact change by a hash.
  • Approval queueProRequests grouped by what they need from the viewer, soonest to expire first.
  • Tool permissionsProPer tool: always, ask first, or never.
  • Blast radiusProWhat a step can reach, or a plain statement that it couldn't be measured.
  • LockedFreeA control that can't be used says why, for example on your own request.
  • Hold to confirmProA risky step the person holds for its full time; letting go cancels, and the reason says what it does and whether it can be undone.
  • Undo windowProAfter the step: Undo for exactly as long as the server allows, then an honest "can't be undone now".

See it working

More in the examples: Approval-gated change

Install

With the shadcn CLI

Each component brings in what it depends on. The free ones install as they are; Pro and Premium ones need a licence key.

Good to know

  • The UI shows a decision; your server enforces it. The approval-gated-change block does both: the agent proposes, a different person approves in a queue, and only the exact change they saw is applied.
  • Decisions show only once they're recorded, so the screen never claims an approval the server doesn't have.