Skip to content

Permissions API

Types

PermissionAction

pydantic_ai_backends.permissions.types.PermissionAction = Literal['allow', 'deny', 'ask'] module-attribute

PermissionOperation

pydantic_ai_backends.permissions.types.PermissionOperation = Literal['read', 'write', 'edit', 'execute', 'glob', 'grep', 'ls'] module-attribute

PermissionRule

pydantic_ai_backends.permissions.types.PermissionRule

Bases: BaseModel

A rule that matches paths/commands and specifies an action.

Rules are evaluated in order - first matching rule wins. Patterns use fnmatch-style matching with support for ** (recursive).

Example
Python
# Deny access to .env files
PermissionRule(
    pattern="**/.env*",
    action="deny",
    description="Protect environment files",
)

# Ask before writing to config files
PermissionRule(
    pattern="**/config/**",
    action="ask",
    description="Confirm config changes",
)
Source code in src/pydantic_ai_backends/permissions/types.py
Python
class PermissionRule(BaseModel):
    """A rule that matches paths/commands and specifies an action.

    Rules are evaluated in order - first matching rule wins.
    Patterns use fnmatch-style matching with support for `**` (recursive).

    Example:
        ```python
        # Deny access to .env files
        PermissionRule(
            pattern="**/.env*",
            action="deny",
            description="Protect environment files",
        )

        # Ask before writing to config files
        PermissionRule(
            pattern="**/config/**",
            action="ask",
            description="Confirm config changes",
        )
        ```
    """

    pattern: str
    """Glob pattern to match against paths or commands.

    Supports fnmatch patterns:
    - `*` matches any characters except `/`
    - `**` matches any characters including `/` (recursive)
    - `?` matches any single character
    - `[seq]` matches any character in seq
    """

    action: PermissionAction
    """Action to take when pattern matches: "allow", "deny", or "ask"."""

    description: str = ""
    """Human-readable description of why this rule exists."""

pattern instance-attribute

Glob pattern to match against paths or commands.

Supports fnmatch patterns: - * matches any characters except / - ** matches any characters including / (recursive) - ? matches any single character - [seq] matches any character in seq

action instance-attribute

Action to take when pattern matches: "allow", "deny", or "ask".

description = '' class-attribute instance-attribute

Human-readable description of why this rule exists.

OperationPermissions

pydantic_ai_backends.permissions.types.OperationPermissions

Bases: BaseModel

Permissions configuration for a single operation type.

Contains a default action and a list of rules that override the default for specific patterns.

Example
Python
OperationPermissions(
    default="allow",
    rules=[
        PermissionRule(pattern="**/.env*", action="deny"),
        PermissionRule(pattern="**/secrets/**", action="deny"),
    ],
)
Source code in src/pydantic_ai_backends/permissions/types.py
Python
class OperationPermissions(BaseModel):
    """Permissions configuration for a single operation type.

    Contains a default action and a list of rules that override
    the default for specific patterns.

    Example:
        ```python
        OperationPermissions(
            default="allow",
            rules=[
                PermissionRule(pattern="**/.env*", action="deny"),
                PermissionRule(pattern="**/secrets/**", action="deny"),
            ],
        )
        ```
    """

    default: PermissionAction = "allow"
    """Default action when no rule matches."""

    rules: list[PermissionRule] = Field(default_factory=list)
    """Rules evaluated in order - first match wins."""

default = 'allow' class-attribute instance-attribute

Default action when no rule matches.

rules = Field(default_factory=list) class-attribute instance-attribute

Rules evaluated in order - first match wins.

PermissionRuleset

pydantic_ai_backends.permissions.types.PermissionRuleset

Bases: BaseModel

Complete permissions configuration for all operations.

Defines default behavior and per-operation permissions. Each operation can have its own default and rules.

Example
Python
ruleset = PermissionRuleset(
    default="deny",  # Default deny everything
    read=OperationPermissions(default="allow"),  # But allow reads
    write=OperationPermissions(
        default="ask",  # Ask before writing
        rules=[
            PermissionRule(pattern="**/temp/**", action="allow"),
        ],
    ),
)
Source code in src/pydantic_ai_backends/permissions/types.py
Python
class PermissionRuleset(BaseModel):
    """Complete permissions configuration for all operations.

    Defines default behavior and per-operation permissions.
    Each operation can have its own default and rules.

    Example:
        ```python
        ruleset = PermissionRuleset(
            default="deny",  # Default deny everything
            read=OperationPermissions(default="allow"),  # But allow reads
            write=OperationPermissions(
                default="ask",  # Ask before writing
                rules=[
                    PermissionRule(pattern="**/temp/**", action="allow"),
                ],
            ),
        )
        ```
    """

    default: PermissionAction = "ask"
    """Global default action when operation has no specific config."""

    read: OperationPermissions | None = None
    """Permissions for read operations."""

    write: OperationPermissions | None = None
    """Permissions for write operations."""

    edit: OperationPermissions | None = None
    """Permissions for edit operations."""

    execute: OperationPermissions | None = None
    """Permissions for execute operations (shell commands)."""

    glob: OperationPermissions | None = None
    """Permissions for glob operations."""

    grep: OperationPermissions | None = None
    """Permissions for grep operations."""

    ls: OperationPermissions | None = None
    """Permissions for ls operations."""

    def get_operation_permissions(self, operation: PermissionOperation) -> OperationPermissions:
        """Get permissions for a specific operation.

        Returns the operation-specific permissions if defined,
        otherwise creates default permissions using the global default.

        Args:
            operation: The operation type to get permissions for.

        Returns:
            OperationPermissions for the specified operation.
        """
        op_perms: OperationPermissions | None = getattr(self, operation, None)
        if op_perms is not None:
            return op_perms
        return OperationPermissions(default=self.default)

default = 'ask' class-attribute instance-attribute

Global default action when operation has no specific config.

read = None class-attribute instance-attribute

Permissions for read operations.

write = None class-attribute instance-attribute

Permissions for write operations.

edit = None class-attribute instance-attribute

Permissions for edit operations.

execute = None class-attribute instance-attribute

Permissions for execute operations (shell commands).

glob = None class-attribute instance-attribute

Permissions for glob operations.

grep = None class-attribute instance-attribute

Permissions for grep operations.

ls = None class-attribute instance-attribute

Permissions for ls operations.

get_operation_permissions(operation)

Get permissions for a specific operation.

Returns the operation-specific permissions if defined, otherwise creates default permissions using the global default.

Parameters:

Name Type Description Default
operation PermissionOperation

The operation type to get permissions for.

required

Returns:

Type Description
OperationPermissions

OperationPermissions for the specified operation.

Source code in src/pydantic_ai_backends/permissions/types.py
Python
def get_operation_permissions(self, operation: PermissionOperation) -> OperationPermissions:
    """Get permissions for a specific operation.

    Returns the operation-specific permissions if defined,
    otherwise creates default permissions using the global default.

    Args:
        operation: The operation type to get permissions for.

    Returns:
        OperationPermissions for the specified operation.
    """
    op_perms: OperationPermissions | None = getattr(self, operation, None)
    if op_perms is not None:
        return op_perms
    return OperationPermissions(default=self.default)

Checker

PermissionChecker

pydantic_ai_backends.permissions.checker.PermissionChecker

Checks operations against a permission ruleset.

The checker evaluates rules in order and uses the first matching rule's action. If no rule matches, the operation's default action is used. If no operation-specific permissions exist, the global default is used.

Example
Python
from pydantic_ai_backends.permissions import (
    PermissionChecker,
    DEFAULT_RULESET,
)

async def ask_user(op: str, target: str, reason: str) -> bool:
    return input(f"Allow {op} on {target}? ").lower() == "y"

checker = PermissionChecker(
    ruleset=DEFAULT_RULESET,
    ask_callback=ask_user,
)

# Synchronous check (returns action without asking)
action = checker.check_sync("read", "/path/to/file")

# Async check (handles "ask" via callback)
allowed = await checker.check("write", "/path/to/file", "Save changes")
Source code in src/pydantic_ai_backends/permissions/checker.py
Python
class PermissionChecker:
    """Checks operations against a permission ruleset.

    The checker evaluates rules in order and uses the first matching rule's
    action. If no rule matches, the operation's default action is used.
    If no operation-specific permissions exist, the global default is used.

    Example:
        ```python
        from pydantic_ai_backends.permissions import (
            PermissionChecker,
            DEFAULT_RULESET,
        )

        async def ask_user(op: str, target: str, reason: str) -> bool:
            return input(f"Allow {op} on {target}? ").lower() == "y"

        checker = PermissionChecker(
            ruleset=DEFAULT_RULESET,
            ask_callback=ask_user,
        )

        # Synchronous check (returns action without asking)
        action = checker.check_sync("read", "/path/to/file")

        # Async check (handles "ask" via callback)
        allowed = await checker.check("write", "/path/to/file", "Save changes")
        ```
    """

    def __init__(
        self,
        ruleset: PermissionRuleset,
        ask_callback: AskCallback | None = None,
        ask_fallback: AskFallback = "error",
    ):
        """Initialize the permission checker.

        Args:
            ruleset: The permission ruleset to check against.
            ask_callback: Async callback for "ask" actions. Receives
                (operation, target, reason) and returns True to allow.
            ask_fallback: What to do when ask_callback is None or needed
                but not available. "deny" returns False, "error" raises.
        """
        self._ruleset = ruleset
        self._ask_callback = ask_callback
        self._ask_fallback = ask_fallback

    @property
    def ruleset(self) -> PermissionRuleset:
        """The permission ruleset being used."""
        return self._ruleset

    def check_sync(
        self,
        operation: PermissionOperation,
        target: str,
    ) -> PermissionAction:
        """Check permission synchronously without invoking callbacks.

        This method evaluates rules and returns the action without
        executing any callbacks. Use this when you need to know what
        action would be taken.

        Args:
            operation: The operation type (read, write, etc.).
            target: The path or command being accessed.

        Returns:
            The permission action: "allow", "deny", or "ask".
        """
        op_perms = self._ruleset.get_operation_permissions(operation)

        # Check rules in order - first match wins
        for rule in op_perms.rules:
            if _matches_pattern(target, rule.pattern):
                return rule.action

        # No rule matched, use default
        return op_perms.default

    def _find_matching_rule(
        self,
        operation: PermissionOperation,
        target: str,
    ) -> PermissionRule | None:
        """Find the first matching rule for an operation and target.

        Args:
            operation: The operation type.
            target: The path or command.

        Returns:
            The matching rule, or None if no rule matches.
        """
        op_perms = self._ruleset.get_operation_permissions(operation)

        for rule in op_perms.rules:
            if _matches_pattern(target, rule.pattern):
                return rule

        return None

    async def check(
        self,
        operation: PermissionOperation,
        target: str,
        reason: str = "",
    ) -> bool:
        """Check permission asynchronously with callback support.

        Evaluates rules and handles "ask" actions via the callback.
        For "allow" returns True, for "deny" raises PermissionDeniedError.

        Args:
            operation: The operation type (read, write, etc.).
            target: The path or command being accessed.
            reason: Human-readable reason for the operation.

        Returns:
            True if the operation is allowed.

        Raises:
            PermissionDeniedError: If the operation is explicitly denied.
            PermissionError: If ask_fallback="error" and callback unavailable.
        """
        action = self.check_sync(operation, target)

        if action == "allow":
            return True

        if action == "deny":
            rule = self._find_matching_rule(operation, target)
            raise PermissionDeniedError(operation, target, rule)

        # Action is "ask"
        if self._ask_callback is not None:
            allowed = await self._ask_callback(operation, target, reason)
            if allowed:
                return True
            raise PermissionDeniedError(operation, target)

        # No callback available
        if self._ask_fallback == "error":
            raise PermissionError(operation, target, reason)

        # ask_fallback == "deny"
        raise PermissionDeniedError(operation, target)

    def is_allowed(
        self,
        operation: PermissionOperation,
        target: str,
    ) -> bool:
        """Check if an operation would be immediately allowed.

        This is a convenience method that returns True only if the
        operation would be allowed without needing to ask.

        Args:
            operation: The operation type.
            target: The path or command.

        Returns:
            True if action is "allow", False otherwise.
        """
        return self.check_sync(operation, target) == "allow"

    def is_denied(
        self,
        operation: PermissionOperation,
        target: str,
    ) -> bool:
        """Check if an operation would be immediately denied.

        Args:
            operation: The operation type.
            target: The path or command.

        Returns:
            True if action is "deny", False otherwise.
        """
        return self.check_sync(operation, target) == "deny"

    def requires_approval(
        self,
        operation: PermissionOperation,
        target: str,
    ) -> bool:
        """Check if an operation would require user approval.

        Args:
            operation: The operation type.
            target: The path or command.

        Returns:
            True if action is "ask", False otherwise.
        """
        return self.check_sync(operation, target) == "ask"

ruleset property

The permission ruleset being used.

__init__(ruleset, ask_callback=None, ask_fallback='error')

Initialize the permission checker.

Parameters:

Name Type Description Default
ruleset PermissionRuleset

The permission ruleset to check against.

required
ask_callback AskCallback | None

Async callback for "ask" actions. Receives (operation, target, reason) and returns True to allow.

None
ask_fallback AskFallback

What to do when ask_callback is None or needed but not available. "deny" returns False, "error" raises.

'error'
Source code in src/pydantic_ai_backends/permissions/checker.py
Python
def __init__(
    self,
    ruleset: PermissionRuleset,
    ask_callback: AskCallback | None = None,
    ask_fallback: AskFallback = "error",
):
    """Initialize the permission checker.

    Args:
        ruleset: The permission ruleset to check against.
        ask_callback: Async callback for "ask" actions. Receives
            (operation, target, reason) and returns True to allow.
        ask_fallback: What to do when ask_callback is None or needed
            but not available. "deny" returns False, "error" raises.
    """
    self._ruleset = ruleset
    self._ask_callback = ask_callback
    self._ask_fallback = ask_fallback

check_sync(operation, target)

Check permission synchronously without invoking callbacks.

This method evaluates rules and returns the action without executing any callbacks. Use this when you need to know what action would be taken.

Parameters:

Name Type Description Default
operation PermissionOperation

The operation type (read, write, etc.).

required
target str

The path or command being accessed.

required

Returns:

Type Description
PermissionAction

The permission action: "allow", "deny", or "ask".

Source code in src/pydantic_ai_backends/permissions/checker.py
Python
def check_sync(
    self,
    operation: PermissionOperation,
    target: str,
) -> PermissionAction:
    """Check permission synchronously without invoking callbacks.

    This method evaluates rules and returns the action without
    executing any callbacks. Use this when you need to know what
    action would be taken.

    Args:
        operation: The operation type (read, write, etc.).
        target: The path or command being accessed.

    Returns:
        The permission action: "allow", "deny", or "ask".
    """
    op_perms = self._ruleset.get_operation_permissions(operation)

    # Check rules in order - first match wins
    for rule in op_perms.rules:
        if _matches_pattern(target, rule.pattern):
            return rule.action

    # No rule matched, use default
    return op_perms.default

check(operation, target, reason='') async

Check permission asynchronously with callback support.

Evaluates rules and handles "ask" actions via the callback. For "allow" returns True, for "deny" raises PermissionDeniedError.

Parameters:

Name Type Description Default
operation PermissionOperation

The operation type (read, write, etc.).

required
target str

The path or command being accessed.

required
reason str

Human-readable reason for the operation.

''

Returns:

Type Description
bool

True if the operation is allowed.

Raises:

Type Description
PermissionDeniedError

If the operation is explicitly denied.

PermissionError

If ask_fallback="error" and callback unavailable.

Source code in src/pydantic_ai_backends/permissions/checker.py
Python
async def check(
    self,
    operation: PermissionOperation,
    target: str,
    reason: str = "",
) -> bool:
    """Check permission asynchronously with callback support.

    Evaluates rules and handles "ask" actions via the callback.
    For "allow" returns True, for "deny" raises PermissionDeniedError.

    Args:
        operation: The operation type (read, write, etc.).
        target: The path or command being accessed.
        reason: Human-readable reason for the operation.

    Returns:
        True if the operation is allowed.

    Raises:
        PermissionDeniedError: If the operation is explicitly denied.
        PermissionError: If ask_fallback="error" and callback unavailable.
    """
    action = self.check_sync(operation, target)

    if action == "allow":
        return True

    if action == "deny":
        rule = self._find_matching_rule(operation, target)
        raise PermissionDeniedError(operation, target, rule)

    # Action is "ask"
    if self._ask_callback is not None:
        allowed = await self._ask_callback(operation, target, reason)
        if allowed:
            return True
        raise PermissionDeniedError(operation, target)

    # No callback available
    if self._ask_fallback == "error":
        raise PermissionError(operation, target, reason)

    # ask_fallback == "deny"
    raise PermissionDeniedError(operation, target)

is_allowed(operation, target)

Check if an operation would be immediately allowed.

This is a convenience method that returns True only if the operation would be allowed without needing to ask.

Parameters:

Name Type Description Default
operation PermissionOperation

The operation type.

required
target str

The path or command.

required

Returns:

Type Description
bool

True if action is "allow", False otherwise.

Source code in src/pydantic_ai_backends/permissions/checker.py
Python
def is_allowed(
    self,
    operation: PermissionOperation,
    target: str,
) -> bool:
    """Check if an operation would be immediately allowed.

    This is a convenience method that returns True only if the
    operation would be allowed without needing to ask.

    Args:
        operation: The operation type.
        target: The path or command.

    Returns:
        True if action is "allow", False otherwise.
    """
    return self.check_sync(operation, target) == "allow"

is_denied(operation, target)

Check if an operation would be immediately denied.

Parameters:

Name Type Description Default
operation PermissionOperation

The operation type.

required
target str

The path or command.

required

Returns:

Type Description
bool

True if action is "deny", False otherwise.

Source code in src/pydantic_ai_backends/permissions/checker.py
Python
def is_denied(
    self,
    operation: PermissionOperation,
    target: str,
) -> bool:
    """Check if an operation would be immediately denied.

    Args:
        operation: The operation type.
        target: The path or command.

    Returns:
        True if action is "deny", False otherwise.
    """
    return self.check_sync(operation, target) == "deny"

requires_approval(operation, target)

Check if an operation would require user approval.

Parameters:

Name Type Description Default
operation PermissionOperation

The operation type.

required
target str

The path or command.

required

Returns:

Type Description
bool

True if action is "ask", False otherwise.

Source code in src/pydantic_ai_backends/permissions/checker.py
Python
def requires_approval(
    self,
    operation: PermissionOperation,
    target: str,
) -> bool:
    """Check if an operation would require user approval.

    Args:
        operation: The operation type.
        target: The path or command.

    Returns:
        True if action is "ask", False otherwise.
    """
    return self.check_sync(operation, target) == "ask"

PermissionError

pydantic_ai_backends.permissions.checker.PermissionError

Bases: Exception

Raised when a permission check fails with ask_fallback="error".

Source code in src/pydantic_ai_backends/permissions/checker.py
Python
class PermissionError(Exception):
    """Raised when a permission check fails with ask_fallback="error"."""

    def __init__(
        self,
        operation: PermissionOperation,
        target: str,
        reason: str = "",
    ):
        self.operation = operation
        self.target = target
        self.reason = reason
        message = f"Permission required for {operation} on '{target}'"
        if reason:
            message += f": {reason}"
        super().__init__(message)

PermissionDeniedError

pydantic_ai_backends.permissions.checker.PermissionDeniedError

Bases: Exception

Raised when a permission is explicitly denied.

Source code in src/pydantic_ai_backends/permissions/checker.py
Python
class PermissionDeniedError(Exception):
    """Raised when a permission is explicitly denied."""

    def __init__(
        self,
        operation: PermissionOperation,
        target: str,
        rule: PermissionRule | None = None,
    ):
        self.operation = operation
        self.target = target
        self.rule = rule
        message = f"Permission denied for {operation} on '{target}'"
        if rule and rule.description:
            message += f": {rule.description}"
        super().__init__(message)

Presets

DEFAULT_RULESET

pydantic_ai_backends.permissions.presets.DEFAULT_RULESET = PermissionRuleset(default='ask', read=(OperationPermissions(default='allow', rules=(_create_deny_rules(SECRETS_PATTERNS, 'Protect sensitive files')))), write=(OperationPermissions(default='ask', rules=(_create_deny_rules(SECRETS_PATTERNS, 'Protect sensitive files')))), edit=(OperationPermissions(default='ask', rules=(_create_deny_rules(SECRETS_PATTERNS, 'Protect sensitive files')))), execute=(OperationPermissions(default='ask', rules=(_create_deny_rules(DANGEROUS_COMMANDS, 'Block dangerous commands')))), glob=(OperationPermissions(default='allow')), grep=(OperationPermissions(default='allow')), ls=(OperationPermissions(default='allow'))) module-attribute

PERMISSIVE_RULESET

pydantic_ai_backends.permissions.presets.PERMISSIVE_RULESET = PermissionRuleset(default='allow', read=(OperationPermissions(default='allow', rules=(_create_deny_rules(SECRETS_PATTERNS, 'Protect sensitive files')))), write=(OperationPermissions(default='allow', rules=(_create_deny_rules(SECRETS_PATTERNS + SYSTEM_PATTERNS, 'Protect sensitive and system files')))), edit=(OperationPermissions(default='allow', rules=(_create_deny_rules(SECRETS_PATTERNS + SYSTEM_PATTERNS, 'Protect sensitive and system files')))), execute=(OperationPermissions(default='allow', rules=(_create_deny_rules(DANGEROUS_COMMANDS, 'Block dangerous commands')))), glob=(OperationPermissions(default='allow')), grep=(OperationPermissions(default='allow')), ls=(OperationPermissions(default='allow'))) module-attribute

READONLY_RULESET

pydantic_ai_backends.permissions.presets.READONLY_RULESET = PermissionRuleset(default='deny', read=(OperationPermissions(default='allow', rules=(_create_deny_rules(SECRETS_PATTERNS, 'Protect sensitive files')))), write=(OperationPermissions(default='deny')), edit=(OperationPermissions(default='deny')), execute=(OperationPermissions(default='deny')), glob=(OperationPermissions(default='allow')), grep=(OperationPermissions(default='allow')), ls=(OperationPermissions(default='allow'))) module-attribute

STRICT_RULESET

pydantic_ai_backends.permissions.presets.STRICT_RULESET = PermissionRuleset(default='ask', read=(OperationPermissions(default='ask', rules=(_create_deny_rules(SECRETS_PATTERNS, 'Protect sensitive files')))), write=(OperationPermissions(default='ask', rules=(_create_deny_rules(SECRETS_PATTERNS, 'Protect sensitive files')))), edit=(OperationPermissions(default='ask', rules=(_create_deny_rules(SECRETS_PATTERNS, 'Protect sensitive files')))), execute=(OperationPermissions(default='ask', rules=(_create_deny_rules(DANGEROUS_COMMANDS, 'Block dangerous commands')))), glob=(OperationPermissions(default='ask')), grep=(OperationPermissions(default='ask')), ls=(OperationPermissions(default='ask'))) module-attribute

create_ruleset

pydantic_ai_backends.permissions.presets.create_ruleset(*, default='ask', allow_read=True, allow_write=False, allow_edit=False, allow_execute=False, allow_glob=True, allow_grep=True, allow_ls=True, deny_secrets=True)

Create a custom permission ruleset.

A convenience factory for creating rulesets with common configurations.

Parameters:

Name Type Description Default
default str

Global default action ("allow", "deny", or "ask").

'ask'
allow_read bool

Whether to allow read operations by default.

True
allow_write bool

Whether to allow write operations by default.

False
allow_edit bool

Whether to allow edit operations by default.

False
allow_execute bool

Whether to allow execute operations by default.

False
allow_glob bool

Whether to allow glob operations by default.

True
allow_grep bool

Whether to allow grep operations by default.

True
allow_ls bool

Whether to allow ls operations by default.

True
deny_secrets bool

Whether to deny access to sensitive file patterns.

True

Returns:

Type Description
PermissionRuleset

A configured PermissionRuleset.

Example
Python
# Create a ruleset that allows reads and writes but asks for execute
ruleset = create_ruleset(
    allow_read=True,
    allow_write=True,
    allow_execute=False,
)
Source code in src/pydantic_ai_backends/permissions/presets.py
Python
def create_ruleset(
    *,
    default: str = "ask",
    allow_read: bool = True,
    allow_write: bool = False,
    allow_edit: bool = False,
    allow_execute: bool = False,
    allow_glob: bool = True,
    allow_grep: bool = True,
    allow_ls: bool = True,
    deny_secrets: bool = True,
) -> PermissionRuleset:
    """Create a custom permission ruleset.

    A convenience factory for creating rulesets with common configurations.

    Args:
        default: Global default action ("allow", "deny", or "ask").
        allow_read: Whether to allow read operations by default.
        allow_write: Whether to allow write operations by default.
        allow_edit: Whether to allow edit operations by default.
        allow_execute: Whether to allow execute operations by default.
        allow_glob: Whether to allow glob operations by default.
        allow_grep: Whether to allow grep operations by default.
        allow_ls: Whether to allow ls operations by default.
        deny_secrets: Whether to deny access to sensitive file patterns.

    Returns:
        A configured PermissionRuleset.

    Example:
        ```python
        # Create a ruleset that allows reads and writes but asks for execute
        ruleset = create_ruleset(
            allow_read=True,
            allow_write=True,
            allow_execute=False,
        )
        ```
    """

    def _action(allowed: bool) -> str:
        return "allow" if allowed else "ask"

    secret_rules = (
        _create_deny_rules(SECRETS_PATTERNS, "Protect sensitive files") if deny_secrets else []
    )

    return PermissionRuleset(
        default=default,  # type: ignore[arg-type]
        read=OperationPermissions(default=_action(allow_read), rules=secret_rules),  # type: ignore[arg-type]
        write=OperationPermissions(default=_action(allow_write), rules=secret_rules),  # type: ignore[arg-type]
        edit=OperationPermissions(default=_action(allow_edit), rules=secret_rules),  # type: ignore[arg-type]
        execute=OperationPermissions(default=_action(allow_execute)),  # type: ignore[arg-type]
        glob=OperationPermissions(default=_action(allow_glob)),  # type: ignore[arg-type]
        grep=OperationPermissions(default=_action(allow_grep)),  # type: ignore[arg-type]
        ls=OperationPermissions(default=_action(allow_ls)),  # type: ignore[arg-type]
    )

Patterns

SECRETS_PATTERNS

pydantic_ai_backends.permissions.presets.SECRETS_PATTERNS = ['**/.env', '**/.env.*', '**/*.pem', '**/*.key', '**/*.crt', '**/credentials*', '**/secrets*', '**/*secret*', '**/*password*', '**/.aws/**', '**/.ssh/**', '**/.gnupg/**'] module-attribute

SYSTEM_PATTERNS

pydantic_ai_backends.permissions.presets.SYSTEM_PATTERNS = ['/etc/**', '/var/**', '/usr/**', '/bin/**', '/sbin/**', '/boot/**', '/sys/**', '/proc/**'] module-attribute

Callback Types

AskCallback

pydantic_ai_backends.permissions.checker.AskCallback = Callable[[PermissionOperation, str, str], Awaitable[bool]] module-attribute

AskFallback

pydantic_ai_backends.permissions.checker.AskFallback = Literal['deny', 'error'] module-attribute