execute_command to an inbound bot meant building the agent, attaching an approval backend, and lifting the default deny — all in Python. Now the operator flips one flag and the gateway wires everything at bot construction.
Behaviour change (PraisonAI ≥ 2026-07-24). Bots now honour
auto_approve_shell: true for execute_command end-to-end. On older builds the tool could still prompt because the auto-approve backend was attached to the agent instance but not the global approval registry. Upgrade to fix — see Auto-approve still prompting.Quick Start
1
Turn it on
Add Start the gateway:Now
allow_shell: true to any channel. In a dev or trusted workspace, auto-approve every command:@your-bot run ls executes on the server.2
Require approval for real workloads
Turn off auto-approve and route the prompt to the owner. Every shell call now sends a Slack Block Kit approval message to
UOWNER, and only UOWNER can approve:Configuration Options
Eight new per-channel fields control shell execution and approval routing.auto_approve_shell accepts string truthy values "1", "true", "yes", "on" (case-insensitive).
Choosing an approval_mode
Pick the backend that matches where you want to answer approval prompts. The routing precedence, exactly as wired at bot construction:Fail-closed behaviour
Whenauto_approve_shell: false is set but no approval backend can be wired, shell commands are denied instead of silently auto-approved.
apply_bot_smart_defaults() may install an AutoApproveBackend when auto_approve_tools is on. If the shell wiring then finds no SlackApproval / TelegramApproval / DiscordApproval / GatewayApprovalBackend / HTTPApproval / WebhookApproval, leaving that backend in place would auto-approve shell despite the explicit opt-out. The gateway now swaps in a deny-by-default CallbackBackend.
The warning line to watch for at startup:
With routing rules
Routing rules on a shell-enabled channel keepexecute_command — routed agents are shell-enabled too, not just the default channel clone.
Previously a routing rule swapped in a raw agent that never saw enable_shell_tools(), so execute_command disappeared for any turn that hit a routing rule — even with allow_shell: true. The gateway now re-applies the channel’s shell setup to routed agents, and runs the full smart-defaults pipeline first.
What allow_shell changes on the agent
Setting the flag runs enable_shell_tools() on the per-channel cloned agent, after smart defaults are applied.
The five side effects, in order:
Step 5 closes the gap that made
auto_approve_shell: true still prompt. execute_command is decorated with @require_approval, which consults the global approval registry — often with agent_name=None. Attaching a backend only to the agent instance was not enough. enable_shell_tools() now calls set_backend(backend, agent_name=agent.name) after installing the backend, so auto-approval takes effect end-to-end. The related core fix honours mark_approved() even for critical-risk tools like execute_command.Per-platform routing
Each platform resolves the approval target from a fallback chain, then builds its native backend.approval_users accepts a comma-separated string or a list. An empty allowlist passes allowed_approvers=None to the platform backend, whose native default lets anyone in the channel approve.
Environment Variables
Every fallback the feature reads, in one place.Webhook without a URL falls back safely. If
approval_mode=webhook but neither approval_webhook_url nor APPROVAL_WEBHOOK_URL is set, the gateway logs a warning and falls through to GatewayApprovalBackend. It does not build a broken WebhookApproval("None").Recipes
Copy-paste-ready configurations for common setups.- Slack auto-approve (dev)
- Slack owner-DM approval
- WhatsApp gateway queue
- Multi-channel policy
Fastest to demo — every shell call runs immediately in a trusted workspace.
HTTP dashboard approvals
Serve a built-in approval page and answer from the browser.User Flow
A Slack workspace owner wants their support team to type@bot run pytest -q and see results in-thread, but only after they personally approve each command. They edit gateway.yaml on the server, add allow_shell: true, auto_approve_shell: false, and approval_channel: "UOWNER" to their slack: block, then restart the gateway. From that moment, every shell request from any Slack user triggers a Block Kit approval prompt in the owner’s DMs — they tap Approve and the command runs; they tap Deny and the agent replies “That command needs approval and was denied.” No Python was written.
Troubleshooting
Bot still asks for approval with auto_approve_shell: true
Bot still asks for approval with auto_approve_shell: true
Upgrade to a PraisonAI build with the approval-registry sync fix (≥ 2026-07-24). On older builds,
auto_approve_shell: true attached AutoApproveBackend to the agent instance only, but execute_command is decorated with @require_approval and consults the global approval registry (often with agent_name=None) — so it kept prompting. The fix mirrors the backend into the registry keyed by agent.name, and honours mark_approved() even for critical-risk tools like execute_command.Best Practices
Never auto-approve on a public channel
Never auto-approve on a public channel
Set
auto_approve_shell: true only in trusted workspaces. On any channel that untrusted users can reach, keep it false and route approvals to an owner.Set approval_users explicitly
Set approval_users explicitly
Prefer an explicit
approval_users allowlist over relying on SLACK_APPROVERS / TELEGRAM_APPROVERS / DISCORD_APPROVERS env vars — it keeps the policy visible in the config and avoids env-var leakage.Use approval_mode: gateway for channels without native wiring
Use approval_mode: gateway for channels without native wiring
WhatsApp, email, and other channels have no in-channel approval UI. Route them to
approval_mode: gateway so approvals queue in the control plane instead of falling silently.Validate the YAML before starting
Validate the YAML before starting
Run
praisonai gateway lint — the fail-closed approval_mode validator rejects typos at load time, catching chanel/webook before they strand approvals.Watch the startup log for '— shell commands will be denied'
Watch the startup log for '— shell commands will be denied'
When
auto_approve_shell: false resolves no approval backend, the gateway logs a warning and denies shell tools. If your bot suddenly refuses commands with “needs approval and was denied”, that log line lists the missing knobs — add approval_channel, set approval_mode, or wire a custom backend.Routing rules inherit shell on shell-enabled channels
Routing rules inherit shell on shell-enabled channels
Adding
allow_shell: true to a channel with routing rules grants execute_command to every routed agent on that channel, not just the default one. Keep routing rules narrow on shell-enabled channels, and remove allow_shell on reload to drop the cached shell clones.Related
Approval Protocol
Approval backend reference for Slack, Telegram, Discord, webhook, and HTTP.
Bot Gateway
Gateway config, channel security, and hot-reload.
Bot Default Tools
How tools get injected on bot agents.
Durable Approvals
Survive gateway restarts across in-flight approvals.

