Skip to main content
A policy is an ordered list of rules. The first rule that matches a tool call wins. If no rule matches, the default_verdict applies.
Plyra Guard Policy Flow

YAML policy

Policies are defined in your guard_config.yaml file. Each policy has a name, a list of action types to match, a condition expression, and a verdict:
version: "1.0"

global:
  default_verdict: BLOCK

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

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

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

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

Policy fields

FieldTypeDescription
namestrUnique identifier for the rule
action_typeslist[str]Action types to match. ["*"] matches all.
conditionstrPython expression evaluated against the ActionIntent
verdictstrOne of ALLOW, BLOCK, ESCALATE, DEFER, WARN
messagestrHuman-readable reason shown when the rule fires
escalate_tostr | NoneTarget for escalation (e.g. "human")

Verdict types

VerdictBehaviour
ALLOWTool executes normally
BLOCKTool not called. ExecutionBlockedError raised.
ESCALATEExecution paused. ActionEscalatedError raised. Pending human approval.
DEFERDeferred for async evaluation. ActionDeferredError raised.
WARNExecutes but emits a warning to the audit log

Default verdict

Always set default_verdict: BLOCK in production. This fails closed — any tool call that doesn’t match a policy rule is blocked. Unmatched calls are the most common source of unexpected agent behaviour.

Risk levels

The RiskLevel enum sets a baseline risk score for a protected action. The dynamic risk scorer adjusts it based on context (agent trust, parameters, etc.).
from plyra_guard import RiskLevel

@guard.protect("db.delete", risk_level=RiskLevel.HIGH)
def delete_record(id: str): ...
LevelBase scoreIntent
RiskLevel.LOW0.1Read operations
RiskLevel.MEDIUM0.3Reversible writes (default)
RiskLevel.HIGH0.6Destructive or irreversible
RiskLevel.CRITICAL0.9System-level or wide-scope

Trust levels

The TrustLevel enum classifies agents in multi-agent systems. Trust determines what risk thresholds an agent can execute under.
from plyra_guard import TrustLevel

guard.register_agent("researcher", trust_level=TrustLevel.PEER)
LevelTrust scoreDescription
TrustLevel.HUMAN1.0Human operator — full trust
TrustLevel.ORCHESTRATOR0.8Top-level orchestrating agent
TrustLevel.PEER0.5Peer agent in a collaborative system
TrustLevel.SUB_AGENT0.3Delegated sub-agent
TrustLevel.UNKNOWN0.0Unregistered or unknown agent

Dry-run evaluation

Test a policy without executing anything:
from plyra_guard import ActionIntent, Verdict

intent = ActionIntent(
    action_type="file.delete",
    tool_name="delete_file",
    parameters={"path": "/etc/passwd"},
    agent_id="default",
)

result = guard.evaluate(intent)
print(result.verdict)    # Verdict.BLOCK
print(result.reason)     # "System config is off-limits"
guard.evaluate() takes an ActionIntent object, not a plain string. See the API reference for all ActionIntent fields.