Skip to main content
Agents can request human approval before running a tool.

Quick Start

1

Simple Usage

Set approval: true to gate every tool behind an interactive y/n prompt on the terminal.
2

With an ApprovalManager

Pass an ApprovalManager to add auto-approve / auto-deny rules and a custom handler.
approval accepts only boolean | ApprovalManager. Per-tool rules live on the ApprovalManager (via addAutoApprove / addAutoDeny), not on the agent.

User Interaction Flow


How approval: true behaves

approval: true builds an ApprovalManager for you and wires createCLIApprovalPrompt() as its handler, so the default is a blocking y/n prompt on stdin. Without a handler, requestApproval() waits on respond() — which nobody calls in a plain CLI session — so it would otherwise stall until the 5-minute default-deny timeout. Wiring the prompt is what keeps the default usable.
Denials are fed back to the model, not thrown. When a call is denied, the agent returns this string as the tool result so the model can course-correct and continue the run:

Correlation with toolInvocationId

The gate passes the LLM’s tool_call.id as toolInvocationId on every approval request. Handlers and out-of-band UIs use it to correlate a decision back to the exact pending call — never positionally. This keeps multiple in-flight tool calls disambiguated.

Custom Handler

Register handlers with onApprovalRequest. The first handler to resolve true approves; if all resolve false, the call is denied.
Auto-deny is checked first (safety), then auto-approve, then handlers.

Configuration Options

ApprovalManager constructor options: ApprovalManager instance methods:

Advanced

Per-tool wrapper: withApproval

Wrap a single tool so it gates itself. Throws ToolApprovalDeniedError on deny unless you provide onDenied.

Global manager: getApprovalManager / setApprovalManager

withApproval uses a process-global manager when none is passed. Configure it once.

Dangerous-pattern helpers

Pre-built regexes and checkers flag risky inputs so you can require approval only when needed.
DANGEROUS_PATTERNS exposes fileDelete, dbDestructive, shellDangerous, and networkSensitive.

Events

ApprovalManager is an event emitter — subscribe with .on(...) to drive an out-of-band UI (e.g. a web dashboard that answers via respond()).

Errors

Python parity: the Python approval API exposes ApprovalDecision.scope ("once" | "session" | "always") and ApprovalDecision.feedback. The TypeScript gate re-prompts every call and returns a fixed refusal string — there is no scope or per-decision feedback channel yet.

Best Practices

Reading data is usually safe. approver.addAutoApprove(/^(read|list|search)_/) skips the prompt for read-only tools.
Auto-deny is checked first. Block deletions and destructive commands with approver.addAutoDeny(/^delete_/).
The default is 5 minutes and default-denies on timeout. Lower it for interactive flows: new ApprovalManager({ defaultTimeout: 60_000 }).
In UIs with concurrent calls, always route decisions by request.toolInvocationId, never by order — positional matching authorises the wrong call.

Guardrails

Input/output validation

Security

Security features