> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Policy Engine

> Policy-based execution control for agent operations

Define allow/deny rules so agents cannot run dangerous tools — attach a `PolicyEngine` before the agent starts.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent
from praisonaiagents.policy import PolicyEngine, Policy, PolicyRule, PolicyAction

engine = PolicyEngine()
engine.add_policy(Policy(
    name="no_delete",
    rules=[
        PolicyRule(
            action=PolicyAction.DENY,
            resource="tool:delete_*",
            reason="Delete operations blocked",
        )
    ],
))

agent = Agent(
    name="SecureAgent",
    instructions="You are a file management assistant.",
)
agent.policy = engine
agent.start("Help me organise my project files")
```

The user requests a risky action; policy rules allow or deny tools before execution.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    Agent[🤖 Agent] --> Engine[🛡️ PolicyEngine]
    Engine --> Check{Rule match?}
    Check -->|deny| Block[🚫 Blocked]
    Check -->|allow| Tool[🔧 Tool runs]

    classDef agent fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef policy fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef result fill:#10B981,stroke:#7C90A0,color:#fff
    classDef deny fill:#F59E0B,stroke:#7C90A0,color:#fff

    class Agent agent
    class Engine,Check policy
    class Tool result
    class Block deny
```

## Quick Start

<Steps>
  <Step title="Simple Usage">
    Block delete tools on a file-management agent:

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    from praisonaiagents import Agent
    from praisonaiagents.policy import (
        PolicyEngine, Policy, PolicyRule, PolicyAction,
        create_read_only_policy,
    )

    engine = PolicyEngine()
    engine.add_policy(create_read_only_policy())

    agent = Agent(name="Assistant", instructions="Manage files safely.")
    agent.policy = engine
    agent.start("List files in the current directory")
    ```
  </Step>

  <Step title="With Configuration">
    Use strict mode and custom deny lists:

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    from praisonaiagents import Agent
    from praisonaiagents.policy import (
        PolicyEngine, PolicyConfig, create_deny_tools_policy,
    )

    engine = PolicyEngine(PolicyConfig(strict_mode=True))
    engine.add_policy(create_deny_tools_policy(
        ["execute_*", "shell_*"],
        reason="System commands are blocked",
    ))

    agent = Agent(name="Reviewer", instructions="Read and summarise code only.")
    agent.policy = engine
    ```
  </Step>

  <Step title="Denial in action">
    Attach a deny policy and watch the tool call get blocked before it runs:

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    from praisonaiagents import Agent
    from praisonaiagents.policy import PolicyEngine, create_deny_tools_policy

    def delete_file(path: str) -> str:
        """Delete a file at the given path."""
        return f"Deleted {path}"

    engine = PolicyEngine()
    engine.add_policy(create_deny_tools_policy(
        ["delete_*"], reason="Delete operations are blocked",
    ))

    agent = Agent(
        name="ReadOnly",
        instructions="You are a read-only assistant.",
        tools=[delete_file],
    )
    agent.policy = engine

    # The agent's tool call is denied by the policy before delete_file runs
    agent.start("Please delete /etc/passwd")
    ```

    Policy denials return an error to the model **before** the tool executes — the same pre-dispatch check applies to native and MCP tools alike. Guardrails run at this same hook: `GuardrailChain.validate_tool_call` / `LLMGuardrail.validate_tool_call` can veto a tool call before dispatch (see the **Guardrails** card below).
  </Step>
</Steps>

***

## Read-only preset — what it blocks

`create_read_only_policy()` returns a `Policy` at priority `100` with **11 deny rules** — 2 file-resource rules and 9 tool-name rules — covering the SDK's built-in mutating tools.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent
from praisonaiagents.policy import PolicyEngine, create_read_only_policy

engine = PolicyEngine()
engine.add_policy(create_read_only_policy())

agent = Agent(
    name="Reviewer",
    instructions="Read and summarise the repo — never modify anything.",
)
agent.policy = engine

# Any of these, if attached as tools, are denied before dispatch:
#   write_file, delete_file, edit_file, apply_patch, copy_file,
#   move_file, append_file, atomic_write, hard_delete, ...
agent.start("Summarise src/main.py in five bullet points")
```

The preset matches by both **prefix** (`tool:write_*`) and **suffix** (`tool:*_write*`), so custom-named tools like `atomic_write` and `file_write` are caught too.

| Rule name                  | Resource pattern    | What it blocks                           |
| -------------------------- | ------------------- | ---------------------------------------- |
| `deny_write`               | `file:write`        | `check_file()` write path                |
| `deny_delete`              | `file:delete`       | `check_file()` delete path               |
| `deny_write_tools`         | `tool:write_*`      | `write_file`, `write_json`, etc.         |
| `deny_write_tools_suffix`  | `tool:*_write*`     | `file_write`, `atomic_write`, etc.       |
| `deny_delete_tools`        | `tool:delete_*`     | `delete_file`, `delete_row`, etc.        |
| `deny_delete_tools_suffix` | `tool:*_delete*`    | `soft_delete`, `hard_delete`, etc.       |
| `deny_edit_tools`          | `tool:edit_*`       | `edit_file`, `edit_json`, etc.           |
| `deny_patch_tools`         | `tool:apply_patch*` | `apply_patch`, `apply_patch_batch`, etc. |
| `deny_copy_tools`          | `tool:copy_*`       | `copy_file`, `copy_folder`, etc.         |
| `deny_move_tools`          | `tool:move_*`       | `move_file`, `move_folder`, etc.         |
| `deny_append_tools`        | `tool:append_*`     | `append_file`, `append_json`, etc.       |

An explicit `ALLOW` rule at higher priority still wins — a deny does not silently override it. Add `ALLOW` rules for any specific tool you need to permit.

<Warning>
  **Upgrade note (PraisonAI PR #3632)**: earlier releases shipped `create_read_only_policy()` with glob patterns that never matched the SDK's real tool names. If you relied on the preset as a safety net before this release, your agent could still call `write_file` / `delete_file` / `edit_file` / etc. Upgrade to the fixed release and re-run your safety tests.
</Warning>

***

## How It Works

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant Agent
    participant Engine as PolicyEngine
    participant Tool

    Agent->>Engine: check("tool:delete_file")
    alt denied
        Engine-->>Agent: PolicyResult(allowed=false)
    else allowed
        Engine-->>Agent: PolicyResult(allowed=true)
        Agent->>Tool: execute
    end
```

| Component      | Purpose                                                          |
| -------------- | ---------------------------------------------------------------- |
| `PolicyRule`   | Wildcard resource patterns with `ALLOW`, `DENY`, `ASK`, or `LOG` |
| `PolicyEngine` | Evaluates rules by priority; optional strict mode                |
| `agent.policy` | Attach the engine before `start()`                               |

Pattern examples: `tool:read_file`, `tool:delete_*`, `tool:*`.

***

## Configuration Options

| Option        | Type           | Default | Description                                 |
| ------------- | -------------- | ------- | ------------------------------------------- |
| `strict_mode` | `bool`         | `False` | Deny operations not explicitly allowed      |
| `action`      | `PolicyAction` | —       | `ALLOW`, `DENY`, `ASK`, `LOG`, `RATE_LIMIT` |
| `resource`    | `str`          | `None`  | Glob pattern (e.g. `tool:shell_*`)          |
| `priority`    | `int`          | `0`     | Higher priority rules evaluate first        |

***

## Best Practices

<AccordionGroup>
  <Accordion title="Attach policy before the first turn">
    Set `agent.policy = engine` immediately after creating the agent.
  </Accordion>

  <Accordion title="Start with read-only presets">
    `create_read_only_policy()` blocks the SDK's built-in mutating tools — `write_*`, `delete_*`, `edit_*`, `apply_patch*`, `copy_*`, `move_*`, `append_*`, and the `*_write*` / `*_delete*` suffix forms. Attach it, then add explicit `ALLOW` rules at higher priority for any specific tool you need to permit.
  </Accordion>

  <Accordion title="Use wildcards sparingly">
    Prefer `tool:delete_*` over `tool:*` deny rules so read tools keep working.
  </Accordion>

  <Accordion title="Enable strict mode in production">
    `PolicyConfig(strict_mode=True)` blocks unknown tool names by default.
  </Accordion>
</AccordionGroup>

***

## Related

<CardGroup cols={2}>
  <Card title="Guardrails" icon="shield" href="/docs/features/guardrails">
    Validate agent output before returning to users
  </Card>

  <Card title="Approval" icon="hand" href="/docs/features/approval">
    Require human confirmation for sensitive actions
  </Card>
</CardGroup>
