Bot Command Access Control

Restrict who can run which bot commands with admin users and per-user command allowlists — applies uniformly to Telegram, Slack, and Discord bots.

python
from praisonaiagents import Agent
from praisonaiagents import BotConfig

agent = Agent(name="assistant", instructions="You are a helpful assistant.")
config = BotConfig(admin_users="123456789", user_allowed_commands={})
agent.start("Restrict /learn to admins only")

Per-command access control layers on top of user allowlists — admins run any command, regular users only run commands you explicitly permit. CommandAccessPolicy applies uniformly to Telegram, Slack, and Discord bots via the shared CommandRegistry.

The user sends a restricted slash command; admins pass the policy check while other users only run commands on their allowlist.

Diagram
graph LR
    subgraph "Command Access Control"
        T[Telegram]
        S[Slack]
        D[Discord]
        T --> Cmd[/command]
        S --> Cmd
        D --> Cmd
        Cmd --> Policy{Policy Check}
        Policy -->|Admin| Run[Run]
        Policy -->|Allowed| Run
        Policy -->|Denied| Block[⛔ Denied]
    end

    classDef agent fill:#8B0000,color:#fff
    classDef tool fill:#189AB4,color:#fff

    class Run agent
    class T,S,D,Cmd,Policy,Block tool

Privileged Commands

Privileged commands (/learn today) are admin-only by default whenever any policy is configured. They stay open when neither admin_users nor user_allowed_commands is set, so existing deployments are unaffected. To grant a regular user a privileged command, add it explicitly to user_allowed_commands.

The conversation-control commands (/undo, /sessions, /resume, /retry, /reasoning) are not privileged — they follow the same rules as /stop, /model, and /usage. Regular users can run them whenever the policy allows non-privileged commands.

GroupWhat’s allowed by default when a policy is configured
Admins (admin_users)Every command, always.
Regular users with no user_allowed_commandsEverything except privileged commands.
Regular users with user_allowed_commands setOnly commands on the allow-list (plus ALWAYS_ALLOWED).
Anyone when no policy is configuredEvery command (legacy permissive default).

Quick Start

  1. Set admin_users in YAML
    yaml
    channels:
      telegram:
        token: ${TELEGRAM_BOT_TOKEN}
        admin_users: "123"
      slack:
        bot_token: ${SLACK_BOT_TOKEN}
        app_token: ${SLACK_APP_TOKEN}
        admin_users: "U01ABCDEF"
      discord:
        token: ${DISCORD_BOT_TOKEN}
        admin_users: "555000000000000000"

    Once admin_users is set, /learn is admin-only on every channel. No allow-list needed for the privileged guard to activate.

  2. Or configure in Python

    Telegram

    python
    from praisonaiagents import Agent
    from praisonaiagents import BotConfig
    from praisonai.bots import TelegramBot
    
    bot = TelegramBot(
        token="YOUR_TOKEN",
        agent=Agent(name="assistant"),
        config=BotConfig(admin_users="123"),
    )

    Slack

    python
    from praisonaiagents import Agent
    from praisonaiagents import BotConfig
    from praisonai.bots import SlackBot
    
    bot = SlackBot(
        agent=Agent(name="assistant"),
        config=BotConfig(admin_users="U01ABCDEF"),
    )

    Discord

    python
    from praisonaiagents import Agent
    from praisonaiagents import BotConfig
    from praisonai.bots import DiscordBot
    
    bot = DiscordBot(
        agent=Agent(name="assistant"),
        config=BotConfig(admin_users="555000000000000000"),
    )
  3. Grant /learn to a specific regular user
    yaml
    admin_users: "123"
    user_allowed_commands: "help,status,learn"

    User 123 is admin (everything). Regular users can also run /learn, /status, and /help.

How It Works

Diagram
CommandAccessPolicyBot (Telegram/Slack/Discord)UserCommandAccessPolicyBot (Telegram/Slack/Discord)Useralt[user_id in admin_users][“learn” in PRIVILEGED_COMMANDSand policy is_configured][“learn” in ALWAYS_ALLOWED][user_allowed_commands is None][“learn” in user_allowed_commands]/learn …can_run(user_id, “learn”)Trueonly True if “learn” in user_allowed_commandsTrueTrue (no policy → permissive)TrueFalse⛔ You are not permitted to run /learn

Policy truth table (from the SDK test suite):

SetupResult
No policy configuredAll commands allowed for everyone (legacy permissive default).
admin_users set, no allow-listAdmins run anything; regular users run everything except PRIVILEGED_COMMANDS.
user_allowed_commands={"learn","status"}Regular users can run /learn and /status; ALWAYS_ALLOWED also apply.
user_allowed_commands={"status"} (no learn)/learn is denied for regular users; admins still bypass.
admin_users and user_allowed_commands={"learn","status"}Admins run anything; regular users run only what’s on the explicit allow-list.
user_allowed_commands="" (empty string)Deliberate “allow nothing extra” — regular users can only run ALWAYS_ALLOWED.

Built-in Commands

CommandDescriptionAlways allowed?Privileged?
/helpShow help (filtered to caller’s permissions)YesNo
/whoamiUser ID, username, role, allowed commandsYesNo
/statusAgent name, model, platform, uptimeNoNo
/newReset the conversation sessionNoNo
/stopCancel the current agent taskNoNo
/modelSwitch LLM for this conversationNoNo
/usageShow token usage and costNoNo
/compressCompress conversation historyNoNo
/queueQueue a follow-up messageNoNo
/learnAuthor a grounded SKILL.md from sourcesNoYes — admin-only by default once a policy is configured

ALWAYS_ALLOWED = {"help", "whoami"} — these cannot be locked away from any user.

PRIVILEGED_COMMANDS = {"learn"} — admin-only whenever a policy is configured (admin_users or user_allowed_commands set). Available to all users when no policy is configured (backward-compatible).

Configuration

OptionTypeDefaultDescription
admin_usersstrNoneComma-separated user IDs who can run any command. Setting this activates the privileged-command guard.
user_allowed_commandsstrNoneComma-separated commands regular users may run. None = no allow-list (regular users get everything except privileged commands when a policy is active). Empty string "" is a deliberate “allow nothing extra” — ALWAYS_ALLOWED still apply.

A policy is “configured” if either admin_users is non-empty or user_allowed_commands is not None (even if empty). Once configured, the privileged-command guard is active.

Choosing a Setup

Diagram

What do you need?

Only admins author skills

Let a specific user run /learn

Read-only public bot

Same access for everyone

admin_users: my_id
(no allow-list needed)

admin_users: my_id
user_allowed_commands: help,status,learn

user_allowed_commands: help,status,whoami

leave both fields unset

Best Practices

admin_users alone is enough to lock down /learn

You don’t need user_allowed_commands to restrict /learn. Setting admin_users alone is enough — regular users lose /learn automatically. Add learn to user_allowed_commands only if you want a specific non-admin to keep access.

Pair with allowed_users

Per-command access layers on top of user allowlists — it does not replace them.

Reserve /new and /stop for admins in production

Both have side effects: resetting state and cancelling tasks.

Use /whoami when debugging permissions

Shows the exact allow list resolved for the caller, including which commands are blocked.

Add custom commands to user_allowed_commands

Register with bot.register_command("ping", handler) then include "ping" in the allowlist for non-admins.

File & entry-point commands are gated identically

CommandAccessPolicy gates apply equally to file-based (.praisonai/commands/*.md) and entry-point (praisonai.bot_commands) commands — not just Python-registered ones. Add their names to user_allowed_commands for non-admins, and denied commands stay hidden from the / menu too. See File-based & Entry-point Commands in Bot Chats.

Related