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 withonApprovalRequest. The first handler to resolve true approves; if all resolve false, the call is denied.
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
Auto-approve safe actions
Auto-approve safe actions
Reading data is usually safe.
approver.addAutoApprove(/^(read|list|search)_/) skips the prompt for read-only tools.Auto-deny dangerous patterns
Auto-deny dangerous patterns
Auto-deny is checked first. Block deletions and destructive commands with
approver.addAutoDeny(/^delete_/).Set reasonable timeouts
Set reasonable timeouts
The default is 5 minutes and default-denies on timeout. Lower it for interactive flows:
new ApprovalManager({ defaultTimeout: 60_000 }).Correlate with toolInvocationId
Correlate with toolInvocationId
In UIs with concurrent calls, always route decisions by
request.toolInvocationId, never by order — positional matching authorises the wrong call.Related
Guardrails
Input/output validation
Security
Security features

