Skip to content

Policy schema

All models are Pydantic v2 models in agentsfence/models.py.

Field Type Default Notes
policy_id str — pol-<hex>
task_id, session_id str | None — Hermes identifiers
purpose str — snake_case, 1–200 chars
summary str "" one sentence
allowed_tools list[str] [] tool names, capabilities, globs, or risk classes
denied_tools list[str] [] same syntax; deny beats allow
allowed_risk_classes list[RiskClass] [READ]
tool_constraints dict[str, ToolConstraint] {} key: tool, capability or glob
allowed_external_domains list[str] [] dot-boundary suffix match
allowed_recipients list[str] [] exact match after normalization
allowed_paths list[str] [] prefix match after resolving .. and ~
allow_local_writes bool false ceiling for LOCAL_WRITE
allow_external_writes bool false ceiling for EXTERNAL_WRITE and COMMUNICATION
allow_destructive_actions bool false ceiling for DELETE
allow_financial_actions bool false ceiling for FINANCIAL
allow_execution bool false ceiling for EXECUTION
allow_permission_changes bool false ceiling for PERMISSION_CHANGE
max_external_writes int | None None task-wide outbound budget
requires_approval list[str] [] always ASK_USER
user_prohibitions list[str] [] risk classes or capabilities; absolute
grants list[Grant] [] runtime approvals
source "llm" | "fallback" | "inherited" | "manual" "llm" only manual policies may allow UNKNOWN tools; fallback turns questions into blocks under auto-approval
compiler_model str | None e.g. openrouter:anthropic/claude-haiku-4.5
request_digest str | None sha256:<16 hex>; the request itself isn’t stored
created_at, expires_at datetime default TTL 12h
revision int 1 incremented by follow-up amendments
Field Type Meaning
allowed_recipients list[str] | None None = unconstrained, [] = nobody
allowed_domains list[str] | None same
allowed_paths list[str] | None same
max_calls int | None calls allowed under this key for the task

grant_id, tool, capability, risk, fingerprint (hash of the action-defining arguments), description (human-readable action), constraint: ToolConstraint, approved_via (once | session | always | host-auto), granted_at. A grant covers a call only when tool, capability, risk and fingerprint all match.

Field Meaning
decision ALLOW | BLOCK | ASK_USER
reason human-readable; shown to the model on BLOCK and to you on ASK_USER
rule_id which check decided (see Evaluation order)
risk, capability the classification
proposed_grant for ASK_USER: the minimal grant approving would create
grant_id for ALLOW via an earlier approval
fingerprint, action the action fingerprint and its human-readable description (the command, recipients, paths)
from agentsfence import compile_policy, evaluate
policy = compile_policy("Summarize my inbox. Do not send anything.")
decision = evaluate(policy, "mcp_gmail_send_message", {"to": "x@evil.com"})
assert decision.decision.value == "BLOCK"