Skip to main content
from praisonaiagents import Agent

agent = Agent(name="ci-agent", instructions="Run safely with pre-declared tool permissions.")
agent.start("Run tests and deploy to staging.")
Declarative permissions let you pre-declare which tool calls to allow, deny, or ask about — so unattended CLI/CI runs stay safe without interactive prompts.
Since PR #2208, bash: / shell: rules are matched against every sub-operation in a compound command. See Command-Aware Permissions.
The user starts an unattended run; declarative rules resolve each tool call to allow, deny, or ask.
deny rules now also shape the tool surface advertised to the LLM (since v1.6.91). The model never sees tools it can’t call — fewer denied-call loops, fewer wasted tokens. See Approval › How tools are pruned from the LLM.

Quick Start

1

YAML

# agents.yaml
permissions:
  "read:*": allow
  "bash:rm *": deny
  "*": ask

agents:
  assistant:
    role: Assistant
    instructions: Help safely
praisonai run agents.yaml
2

CLI flags

praisonai run "deploy the app" \
  --allow 'read:*' \
  --allow 'bash:git *' \
  --deny 'bash:rm *' \
  --permission-default ask
3

Python

from praisonaiagents import Agent

agent = Agent(
    name="CI Worker",
    instructions="Run safely in CI",
    approval={
        "permissions": {
            "read:*": "allow",
            "bash:rm *": "deny",
        },
    },
)
4

In project config

Declare rules directly in .praisonai/config.yaml — automatically inherited by every praisonai run in the directory:
# .praisonai/config.yaml
permissions:
  default: ask
  rules:
    - { pattern: "bash:git *", action: allow }
    - { pattern: "bash:rm *",  action: deny }
Or use the flat mapping form:
# .praisonai/config.yaml
permissions:
  "read:*": allow
  "bash:rm *": deny
  "*": ask

How It Works

On each tool call, the backend builds a target string (tool_name:arg) and PermissionManager.check() returns allow, deny, or ask. Non-interactive runs honour declared rules; ask without a human present falls back to deny.

Pattern Syntax

Patterns use <tool_name>:<arg-glob>:
PatternMeaning
read:*Any read tool call
bash:git *Git shell commands
write:/etc/*Writes under /etc/ (including truncating redirections)
external_dir:/data/*Allow access to /data/ when workspace_root is set
external_dir:~/*Allow access to home directory when workspace_root is set
external_dir:*Deny all out-of-workspace access (hard block, no ask prompt)

external_dir: targets

external_dir:<parent>/* is emitted for any path that resolves outside workspace_root. Use these patterns to pre-authorise or hard-block external filesystem access without interactive prompts. See Workspace Boundary.

Compound shell commands

bash: and shell: targets are decomposed into their constituent operations — &&, ;, |, subshells, $(...), backticks, and truncating redirections. A single deny rule fires when the blocked executable appears anywhere inside the compound command. For example, deny: bash:rm * blocks cd /tmp && rm -rf x and echo $(rm -rf x), not just a bare rm call.

Command-Aware Permissions

Full behaviour details, evasion table, and aggregation rules
Detailed dict form supports is_regex, priority, agent_name, and description:
permissions:
  "read:*": allow
  "bash:rm *":
    action: deny
    description: Block destructive shell ops
    priority: 100

Configuration Surfaces

Coming soon: Interactive persistent approvals will be able to auto-derive a command-prefix glob instead of storing the literal command. Until PraisonAI PR #2576 is merged, pass the glob explicitly — e.g. manager.approve("bash:git status *", True, scope="always") — to cover every git status variant without re-prompting. See Reusable Approval Scopes.
SurfaceWhereExample
Per-agent definitionmode: / permission: in .praisonai/agents/*.{md,yaml}mode: read-only
Project config.praisonai/config.yaml permissions:"bash:rm *": deny
YAMLTop-level or per-agent approval.permissions: in agents.yaml"bash:rm *": deny
CLI--allow, --deny, --permissions <file>, --permission-default--deny 'bash:rm *'
PythonApprovalConfig(permissions={...}){"read:*": "allow"}
Precedence: agent definition mode: / permission: → agent-level approval.permissions → top-level agents.yaml permissions:.praisonai/config.yaml permissions: → CLI --allow/--deny (override file) → --permission-default → built-in defaults. CLI flags override config-yaml rules per-pattern. See Agent Presets & Modes for the full per-agent permission reference. Load from file:
praisonai run agents.yaml --permissions permissions.yaml --deny 'bash:curl *'

Common Patterns

Read-only CI runner--permission-default deny with --allow 'read:*'. Git-only worker — allow bash:git *, deny everything else. Deny destructive commands — baseline "bash:rm *": deny and "write:/etc/*": deny. Lock down external filesystem access — add "external_dir:*": deny when workspace_root is set for a hard block on everything outside the project.

Best Practices

Use --permission-default deny or "*": deny so undeclared tools are blocked.
Higher-priority rules win — declare bash:git push * before broad bash:*.
Keep permissions.yaml next to agents.yaml in git.
Verify rules before deploying to CI.

Single-Source Config

Model + MCP + permissions in one config file

Command-Aware Permissions

How compound commands are decomposed and checked

Permissions

Programmatic PermissionManager API

Workspace Boundary

Gate shell and file access outside your project root

Approval

Interactive approval backends

Tool Approval CLI

CLI flags reference