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

# Permission Rule

> Write allow, deny, and ask patterns for specific tools and calls

A `PermissionRule` maps a specific tool and call pattern to one of three behaviors: `ALLOW`, `DENY`, or `ASK`. Rules are evaluated with the highest priority in every [mode](/versions/2.0.5dev/en/building-blocks/permission-system/permission-mode): deny and ask rules first, allow rules after the tool's own checks.

Each rule consists of the following fields. When the permission engine evaluates a rule, it calls the tool's `match_rule()` method with `rule_content` and the actual call input to determine whether the rule applies.

<ParamField path="tool_name" type="str" required>
  Tool this rule applies to: `"Bash"`, `"Read"`, `"Write"`, `"Edit"`, or any custom tool name.
</ParamField>

<ParamField path="rule_content" type="str | None" required>
  Match pattern, whose semantics depend on `tool_name`:

  * **Bash**: wildcard prefix pattern (`npm run:*` matches `npm run build`, `npm run test`)
  * **Read / Write / Edit**: glob pattern (`src/**/*.py` matches any `.py` under `src/`)
  * **Other tools**: exact JSON-serialized parameter match
</ParamField>

<ParamField path="behavior" type="PermissionBehavior" required>
  `ALLOW`, `DENY`, or `ASK`
</ParamField>

<ParamField path="source" type="str" required>
  Origin of the rule: `"userSettings"`, `"projectSettings"`, `"session"`, etc.
</ParamField>

## Pattern Examples

`rule_content` is consumed by each tool's `match_rule()` method and auto-generated by `ToolBase.generate_suggestions()`. Because both methods are part of the tool interface, each tool can define its own pattern syntax and matching logic independently.

For AgentScope's built-in tools, the patterns are as follows:

<Tabs>
  <Tab title="Bash">
    Matches against the **`command`** parameter. Pattern format is `COMMAND_PREFIX:*`: the prefix is the leading token of the command, and `*` matches any arguments that follow.

    | Pattern        | Matches                         | Does Not Match |
    | -------------- | ------------------------------- | -------------- |
    | `npm run:*`    | `npm run build`, `npm run test` | `npm install`  |
    | `git commit:*` | `git commit -m "fix"`           | `git push`     |
    | `rm:*`         | `rm file.txt`, `rm -rf /tmp/x`  | `ls`           |

    ```python theme={null}
    PermissionRule(
        tool_name="Bash",
        rule_content="npm run:*",
        behavior=PermissionBehavior.ALLOW,
        source="userSettings",
    )
    ```
  </Tab>

  <Tab title="File Tools (Read / Write / Edit)">
    Matches against the **`file_path`** parameter using a glob pattern via `fnmatch`.

    | Pattern       | Matches                   |
    | ------------- | ------------------------- |
    | `src/**`      | Any file under `src/`     |
    | `src/**/*.py` | Python files under `src/` |
    | `config.json` | Exact file match          |

    ```python theme={null}
    PermissionRule(
        tool_name="Write",
        rule_content="src/**",
        behavior=PermissionBehavior.ALLOW,
        source="userSettings",
    )
    ```
  </Tab>
</Tabs>

## Configure Rules

Rules enter the engine in two ways: statically at initialization, or dynamically when the user accepts a suggested rule at runtime.

**At initialization**: pass rules into `PermissionContext` when creating the agent:

```python theme={null}
from agentscope.agent import Agent
from agentscope.state import AgentState
from agentscope.permission import (
    PermissionContext, PermissionMode, PermissionRule, PermissionBehavior
)

agent = Agent(
    name="my_agent",
    system_prompt="...",
    model=model,
    state=AgentState(
        permission_context=PermissionContext(
            mode=PermissionMode.DEFAULT,
            allow_rules={
                "Bash": [PermissionRule(tool_name="Bash", rule_content="npm run:*",
                                        behavior=PermissionBehavior.ALLOW, source="userSettings")],
                "Write": [PermissionRule(tool_name="Write", rule_content="src/**",
                                         behavior=PermissionBehavior.ALLOW, source="userSettings")],
            },
            deny_rules={
                "Bash": [PermissionRule(tool_name="Bash", rule_content="rm:*",
                                        behavior=PermissionBehavior.DENY, source="userSettings")],
            },
        )
    ),
)
```

**At runtime via suggestions**: when the permission system returns ASK, it auto-generates suggested rules from the current call. Pass accepted rules back in `UserConfirmResultEvent.rules`; the agent adds them to the engine automatically:

```python theme={null}
from agentscope.event import UserConfirmResultEvent

# The ASK decision includes suggested_rules generated from the current call.
# To accept a suggestion, include it in the result event:
result = UserConfirmResultEvent(
    confirmed=True,
    rules=[suggested_rule],  # accepted rules are persisted to the engine
)
```

<Note>
  An allow rule cannot override a tool-emitted **safety ASK** (`bypass_immune=True`), such as a write into `~/.ssh/`. See the [safety check contract](/versions/2.0.5dev/en/building-blocks/permission-system/tool-check#safety-check-contract).
</Note>
