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 "