approval=True on any agent to auto-approve, or pass a custom backend for console, webhook, Slack, or any approval channel.
Button-based approvals are now available. On channels that implement the
SupportsPresentation protocol (Telegram, Slack, Discord), approval prompts can render as inline buttons instead of relying on yes/no text replies. Use MessagePresentation.approval(...) to build the prompt. The text-keyword backends documented on this page continue to work unchanged — they are the recommended fallback for channels that do not yet support presentations. See Interactive Bot Messages.Button-based approvals (via MessagePresentation.approval(...)) are actor-bound by default in shared chats. Text-keyword backends (TelegramApproval, SlackApproval, DiscordApproval) require an explicit allowed_approvers=[...] allowlist (or TELEGRAM_APPROVERS / SLACK_APPROVERS / DISCORD_APPROVERS env var) to lock down who may resolve an approval — added in PR #2582. Without an allowlist, any responder in the group can approve. See Interactive Callback Authorization.For unified ApprovalSpec configuration (YAML/CLI/Python), see the Approval documentation. Backend selection uses the same string values inThe user enables approval on an agent; each dangerous tool call pauses until the configured backend allows or denies it.--approvaland YAMLbackend:fields.
Quick Start
1
Auto-Approve (Bots / Trusted Envs)
2
Custom Approval Backend
3
Default (Console Prompt)
How It Works
The Env check and YAML check rows are honoured on both the no-backend and attached-backend paths since PR #4878. Before #4878 an agent with a backend attached (the default
ConsoleBackend and every chat/gateway front-end) skipped these standing grants and prompted anyway. See Standing grants and attached backends.ApprovalRequest fields
The request object a backend receives, describing the tool call awaiting approval.
approval_id, agent_name, and session_id survive a process restart and re-hydrate from a durable ApprovalStore. liveness is a per-turn predicate — it is not persisted and is rebuilt when a turn resumes.ApprovalDecision fields
The decision object a backend returns. Denials can carry a feedback string to steer the agent’s next turn, and a decision may instead be a deferral carrying escalate=True that hands the call to a human.
Configuration Options
Since PR #4878, thePRAISONAI_AUTO_APPROVE env rung is checked even when a backend is attached — not just for bare-SDK use.
Agent Parameter (Recommended)
Other Methods
Built-in Backends
Gateway-wired approvals
Settingchannels.<platform>.allow_shell: true with auto_approve_shell: false on a gateway channel wires one of these backends automatically — no Python required. If none of them resolve, the gateway installs a CallbackBackend that denies shell tools (execute_command, shell_command, acp_execute_command) so shell never silently auto-approves. See Fail-closed behaviour.
The gateway also routes through this same backend precedence when auto_approve_shell: true is downgraded on exposed / multi-user surfaces (see Bot Shell Execution → Exposure-aware auto-approval). The precedence itself is unchanged — only the trigger.
The routing precedence, exactly as implemented:
Bot Shell Execution
Full field reference, per-platform ID resolution, env vars, and recipes.
Durable chat backends:
SlackApproval, TelegramApproval, DiscordApproval, WebhookApproval, and HTTPApproval each accept an optional store= parameter. Pass an ApprovalStore to persist the pending approval before polling, then call backend.rehydrate() on startup to recover in-flight approvals after a restart. The shared DEFAULT_APPROVAL_TIMEOUT (300s) from praisonai_bot.bots._approval_base is the single source of truth for the wait window. See Durable Approvals.Custom Backend
Implementrequest_approval (async) and optionally request_approval_sync to create any approval channel:
ApprovalDecision(approved=False, escalate=True) to signal a deferral to a human. Consumers that only check approved still fail-closed correctly, since escalate=True forces approved=False.
Slack Approval
Route tool approvals to Slack — get a rich message with tool details and reply yes or no to approve or deny.1
Install
2
Set Token
3
Use It
Configuration
Make Slack approvals restart-safe by adding
store=:
Approval Keywords
Cross-Platform: Telegram Bot → Slack Approval
Cross-Platform: Telegram Bot → Slack Approval
You can use any bot platform for user interaction while routing approvals to Slack:
Telegram Approval
Route tool approvals to Telegram — get a message with inline keyboard buttons.Since PR #2582, callback taps are bound to both
message_id and chat_id, so a same-message_id button in a different chat cannot resolve this approval. An unauthorised tap shows the presser a “You are not authorized to approve this action.” alert.Discord Approval
Route tool approvals to Discord — get a rich embed and reply yes or no.Webhook Approval
POST approval requests to any HTTP endpoint and poll for decisions. Ideal for enterprise dashboards, CI/CD, and custom integrations.Agent Approval
Delegate approval decisions to another AI agent. The reviewer sees the tool name and arguments as untrusted data and returns one ofAPPROVE, DENY, or ESCALATE.
- The tool name and arguments are wrapped in an
<arguments>…</arguments>untrusted-data block; forged<arguments>/</arguments>tags in the tool name or values are neutralised to‹arguments›. - Command-like argument values (keys in
{command, cmd, commands, script, shell, code, source, program}) have any trailing# …shell comment stripped before the reviewer sees them; other args pass through unchanged. - The reviewer replies with one of
APPROVE/DENY/ESCALATE. Parsing is fail-closed: empty, ambiguous, mixed, or negated (“DO NOT APPROVE”) responses →DENY;ESCALATEyieldsApprovalDecision(approved=False, escalate=True).
AgentApproval lives in the core SDK (praisonaiagents.approval) — no extra dependencies needed.Handling ESCALATE
When the reviewer is uncertain it returnsescalate=True — route the request to a human instead of guessing.
HTTP Approval
Serve a local web dashboard for approvals. Open the URL in your browser and click Approve or Deny.Multi-Agent Example
Different agents can have different approval policies:Registry (Advanced)
For global or centralized approval control, use the registry directly:The
approval= parameter on Agent takes priority over the global registry.
If an agent has approval=True, it will auto-approve regardless of registry settings.Dangerous Tools (Default)
These tools require approval by default:
Add or remove requirements:
ApprovalStoreProtocol
Optional persistence layer for pending approvals — orthogonal to approval backends. Implementpersist, list_pending, and resolve to survive restarts.
ApprovalStore (SQLite) in praisonai.bots. See Durable Approvals.
All five chat backends (
SlackApproval, TelegramApproval, DiscordApproval, WebhookApproval, HTTPApproval) accept a store= and expose rehydrate() via the shared DurableApprovalMixin in praisonai_bot.bots._approval_base. See Durable Chat-Native Backends.Live-Authority Binding
Since PraisonAI #4950, every approval that flows through the coreApprovalRegistry is bound to the liveness of the originating turn. If the user hits /stop (or a superseding turn takes over) while an approval is parked on a human — a Telegram tap, a Slack reply, a webhook decision, a local dashboard click — the resolution that lands afterwards is dropped fail-closed at the resolution boundary:
- The tool does not run.
- No
sessionoralwaysgrant is persisted for the abandoned turn. - The returned decision is
ApprovalDecision(approved=False, reason="Turn no longer live (stopped or superseded)").
PresentationApprovalBackend, and any custom third-party backend. It also applies when a backend is attached directly to the Agent via approval=... (the direct-backend path).
Backward-compatibility
ApprovalRequest.liveness defaults to None, and both approve_sync / approve_async accept liveness=None. Existing code that constructs an ApprovalRequest by hand and calls the registry keeps the old always-live behaviour. A liveness probe that raises is treated as live (fail-open on the probe, never on the decision) so a buggy predicate can never wedge the approval path.
What the registry does
The predicate the SDK supplies follows the effective per-turn cancel token — the same authority an explicitcancel_token= argument or a /stop targets — and falls back to the agent’s interrupt controller when no per-turn token is registered. When neither is attached the request stays always-live, preserving today’s behaviour.
Best Practices
Use approval=True for bot agents
Use approval=True for bot agents
Set
approval=True directly on agent constructors for unattended bots. This is the simplest, most agent-centric approach.Use environment variable for CI/CD
Use environment variable for CI/CD
Set
PRAISONAI_AUTO_APPROVE=true in your CI environment to avoid blocking on prompts during automated testing.Create custom backends for production
Create custom backends for production
Build webhook or messaging backends that route approvals to the right team. The async protocol supports long-running approval flows.
Use per-agent backends for multi-agent systems
Use per-agent backends for multi-agent systems
Different agents may need different approval policies. Pass different backends to each agent’s
approval= parameter.Related
CLI Tool Approval
--trust, --approve-level, and --approval CLI flagsMessaging Bots
Telegram, Discord, Slack, WhatsApp bots
Schedule Tools
Agent-centric scheduling tools
Tools
Built-in tools reference

