--approval secure is a hardened approval backend that persists decisions across restarts, authorises approvers against an allowlist, and binds each decision to an unguessable approval ID — not to a message ID that anyone could race.
How It Works
A risky tool call is stored durably until an authorised actor resolves it by unguessable approval ID.Telegram: zero-config wiring
When the transport is a Telegram bot,Agent(approval="secure") (alias "presentation") is auto-wired on TelegramBot.start() — the bot supplies the channel renderer and target, and calls rehydrate() to restore pending approvals. No register_approval_backend() call is required. See Telegram Durable Approval.
Quick Start
1
Enable via CLI
Run the gateway with the secure approval backend:The alias
--approval presentation is equivalent.2
Set Allowed Approvers
PRAISONAI_APPROVAL_ACTORS is required and must be non-empty when using --approval secure. The gateway fails closed if this variable is not set:3
Programmatic Usage
4
Rehydrate on Restart
After a restart, rehydrate pending approvals so late decisions still resolve:
Security Properties
The secure backend fixes four gaps in the per-channel backends (TelegramApproval, SlackApproval, etc.):
Unguessable Approval ID
Each approval request carries a cryptographically unguessableapproval_id in the button callback payload. A deny or approve decision binds to that specific ID — not to the Telegram/Slack message ID, which an attacker could observe or guess. Replays are rejected: once an ID is resolved it cannot be re-used.
Persistence and Rehydration
Pending approvals are written to~/.praisonai/state/approvals.sqlite (honouring PRAISONAI_HOME). On restart, rehydrate() restores all pending approvals with the original allowed_actors re-applied — a restored approval cannot become unrestricted just because the process restarted.
CLI Flags
Environment Variables
Storage
Approvals persist to SQLite at:PRAISONAI_HOME:
API Reference
Best Practices
Always set PRAISONAI_APPROVAL_ACTORS
Always set PRAISONAI_APPROVAL_ACTORS
The backend is fail-closed: without an allowlist it cannot authorise any actor and will reject all approvals. Set this variable in your deployment environment before starting the gateway.
Call rehydrate() at startup
Call rehydrate() at startup
In a long-lived gateway, call
await backend.rehydrate() after construction so any approval that was pending when the process last stopped can still be resolved. Without rehydration, pending approvals are invisible.Use SQLite persistence for production
Use SQLite persistence for production
Passing a
store=ApprovalStore(...) makes approvals durable across restarts. Without a store, the backend uses in-memory state only and pending approvals are lost on restart.Scope actor IDs to one platform
Scope actor IDs to one platform
Actor IDs are platform-specific strings (Telegram user IDs, Slack user IDs, etc.). If you run bots on multiple platforms, ensure the IDs in
PRAISONAI_APPROVAL_ACTORS match the platform your approvers use.Related
Approval (Concept)
High-level approval lifecycle model
Durable Approvals
Durable approval storage
Message Presentation
Interactive buttons and keyboards
Interactive Approval
Approval via chat interactions

