Skip to main content
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 — both preset (approval="safe" / "read_only") and pattern-based (declarative permissions: from YAML, CLI, .praisonai/config.yaml, or Python) — shape the tool surface advertised to the LLM. The same gate applies uniformly to native tools and MCP tools at call time. 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

2

CLI flags

3

Python

4

In project config

Declare rules directly in .praisonai/config.yaml — automatically inherited by every praisonai run in the directory:
Or use the flat mapping form:

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>:

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:

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.
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:

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