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.
from plyra_guard.exceptions import ExecutionBlockedError, ActionEscalatedErrortry: 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 fileCreate `guard_config.yaml` in your project root:```yamlversion: "1.0"global: default_verdict: BLOCKpolicies: - 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"