Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.plyra.dev/llms.txt

Use this file to discover all available pages before exploring further.

Install

pip install plyra-guard

Protect a tool

from plyra_guard import ActionGuard, RiskLevel

guard = ActionGuard.default()

@guard.protect("file.delete", risk_level=RiskLevel.HIGH)
def delete_file(path: str) -> str:
    import os
    os.remove(path)
    return f"Deleted {path}"
When the agent calls delete_file, plyra-guard intercepts first:
delete_file("/tmp/report.txt")   # Verdict: ALLOW — executes normally
delete_file("/etc/passwd")       # Verdict: BLOCK — ExecutionBlockedError raised
ExecutionBlockedError carries three fields that explain exactly what happened: what_happened, policy_triggered, and how_to_fix. Catch it to handle blocks gracefully in your agent loop.

Handle blocked calls

from plyra_guard.exceptions import ExecutionBlockedError, ActionEscalatedError

try:
    delete_file("/etc/passwd")
except ExecutionBlockedError as e:
    print(e.what_happened)      # "File path matches block rule: system config"
    print(e.policy_triggered)   # "block-system-config"
    print(e.how_to_fix)         # "Use a path under /tmp/ or update your policy"
except ActionEscalatedError as e:
    print(e.reason)             # Why escalation was triggered
    print(e.escalate_to)        # Where the escalation was routed
Both exceptions carry structured context. Your agent loop should catch them and decide whether to retry with a different approach, surface to the user, or abort the task.

## Load a policy file

Create `guard_config.yaml` in your project root:

```yaml
version: "1.0"

global:
  default_verdict: BLOCK

policies:
  - name: block-env-files
    action_types: ["*"]
    condition: '".env" in parameters.get("path", "")'
    verdict: BLOCK
    message: "No .env access"

  - name: block-system-config
    action_types: ["*"]
    condition: 'parameters.get("path", "").startswith("/etc/")'
    verdict: BLOCK
    message: "System config is off-limits"

  - name: allow-tmp
    action_types: ["*"]
    condition: 'parameters.get("path", "").startswith("/tmp/")'
    verdict: ALLOW

  - name: escalate-schema-changes
    action_types: ["*"]
    condition: '"DROP TABLE" in str(parameters)'
    verdict: ESCALATE
    message: "Schema changes require human approval"
guard = ActionGuard.from_config("guard_config.yaml")

Wrap a list of tools

safe_tools = guard.wrap([read_file, write_file, delete_file])
Pass safe_tools to any framework that accepts a tool list.

Launch the dashboard

pip install "plyra-guard[sidecar]"
plyra-guard serve
# → http://localhost:8765

Policy reference

Learn the full rule syntax.

Framework integrations

LangGraph, AutoGen, CrewAI, and more.