Status: Draft · Date: 2026-05-16 · Authors: Agent Governance Toolkit team
This specification defines the policy evaluation engine for Agent OS. All SDK implementations (Python, TypeScript, Rust, .NET, Go) MUST conform to this specification.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
- Introduction
- Terminology
- Policy Document Schema
- Policy Rule Schema
- Condition Operators
- Policy Actions
- Evaluation Semantics
- Integration-Layer Policy (GovernancePolicy)
- Pattern Matching
- Tool Call Interception
- Policy Merge (Folder-Level Hierarchy)
- Policy Discovery
- Conflict Resolution
- External Policy Backends
- Concurrency and Backpressure
- Failure Semantics
- Audit and Observability
- Policy Composability
- Serialization
- Conformance Requirements
- Worked Examples
- Security Considerations
- References
This document specifies the behavioral contract for the Agent OS policy engine: the component that evaluates governance policies against agent actions and returns structured allow/deny decisions with full audit metadata.
The policy engine is the single enforcement point through which all governed agent actions flow. It operates at two layers:
- Declarative layer: YAML/JSON
PolicyDocumentfiles evaluated by thePolicyEvaluatoragainst execution context dictionaries. - Integration layer:
GovernancePolicyobjects applied by framework adapters (OpenAI, LangChain, CrewAI, etc.) to intercept tool calls, enforce token limits, and check blocked patterns at runtime.
This specification covers:
- Policy document structure, rule schemas, and condition operators
- Evaluation order, priority semantics, and default actions
- Folder-level policy discovery, inheritance, and merge
- Multi-policy conflict resolution strategies
- External policy backend integration (OPA/Rego, Cedar)
- Tool call interception and pattern matching
- Failure semantics and fail-closed behavior
- Concurrency control and backpressure
- Audit entry structure and observability hooks
This specification does NOT cover:
- Identity and trust scoring (see future Identity and Trust spec)
- Execution ring enforcement (see future Hypervisor spec)
- Multi-agent coordination policies (see future AgentMesh Trust spec)
- SLO/SLI governance (see future Agent SRE spec)
This specification uses two markers to distinguish normative requirements from implementation guidance:
- [Pure Specification] marks behavioral requirements that all conforming implementations MUST satisfy.
- [Default Implementation] marks behaviors that the reference implementation provides but that other implementations MAY vary, provided they satisfy the surrounding pure-specification constraints.
| Term | Definition |
|---|---|
| PolicyDocument | A declarative governance policy file (YAML/JSON) containing rules, defaults, and metadata. |
| PolicyRule | A single condition-action pair within a PolicyDocument. |
| PolicyCondition | A field-operator-value triple that matches against execution context. |
| PolicyAction | The prescribed outcome when a rule matches: allow, deny, audit, or block. |
| PolicyEvaluator | The engine that evaluates PolicyDocuments against execution contexts. |
| GovernancePolicy | Integration-layer policy object enforced by framework adapters at runtime. |
| ExecutionContext | Runtime state (agent ID, session ID, call count, token usage) passed through the governance layer. |
| PolicyDecision | Structured result of evaluating policies: allowed/denied with rule, reason, and audit metadata. |
| Conflict Resolution | The strategy for resolving disagreements when multiple rules or policies match. |
| External Backend | A pluggable policy evaluator using a third-party language (OPA/Rego, Cedar). |
[Pure Specification]
A PolicyDocument MUST contain the following fields:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
version |
string | No | "1.0" |
Schema version identifier. |
name |
string | No | "unnamed" |
Human-readable policy name for audit logs. |
description |
string | No | "" |
Free-form description. |
rules |
array | No | [] |
Ordered list of PolicyRule objects. |
defaults |
object | No | See 3.2 | Default settings when no rule matches. |
inherit |
boolean | No | true |
Whether parent policies are loaded during discovery. |
scope |
string or null | No | null |
Glob pattern restricting which action paths this policy applies to. |
[Pure Specification]
The defaults object MUST support the following fields:
| Field | Type | Default | Description |
|---|---|---|---|
action |
PolicyAction | "allow" |
Default action when no rule matches. |
max_tokens |
integer | 4096 |
Maximum tokens per request. |
max_tool_calls |
integer | 10 |
Maximum tool invocations per request. |
confidence_threshold |
float | 0.8 |
Minimum confidence score (0.0-1.0). |
Implementations MAY support additional default fields for sandbox
resource constraints (max_cpu, max_memory_mb, timeout_seconds,
network_default). These fields are consumed by sandbox providers and
MUST be ignored by the rule engine itself.
[Pure Specification]
Conforming implementations MUST support loading PolicyDocuments from YAML. Implementations SHOULD also support JSON.
YAML files MUST use .yaml or .yml extensions. JSON files MUST use
.json extension.
[Pure Specification]
Each PolicyRule MUST contain:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | Yes | -- | Unique rule identifier within the document. |
condition |
PolicyCondition | Yes | -- | The matching condition. |
action |
PolicyAction | Yes | -- | Action to take when condition matches. |
priority |
integer | No | 0 |
Evaluation priority. Higher values are evaluated first. |
message |
string | No | "" |
Human-readable explanation included in decisions and audit entries. |
override |
boolean | No | false |
If true, replaces a parent rule with the same name during folder-level merge. |
[Pure Specification]
A PolicyCondition MUST contain exactly three fields:
| Field | Type | Description |
|---|---|---|
field |
string | Dot-path into the execution context (e.g., "tool_name", "token_count"). |
operator |
PolicyOperator | Comparison operator. |
value |
any | Target value for comparison. |
[Pure Specification]
Conforming implementations MUST support all of the following operators:
| Operator | Semantics | Example |
|---|---|---|
eq |
Context value equals target value. | tool_name eq "execute_code" |
ne |
Context value does not equal target value. | agent_id ne "admin" |
gt |
Context value is greater than target. | token_count gt 4096 |
lt |
Context value is less than target. | priority lt 5 |
gte |
Context value is greater than or equal to target. | confidence gte 0.8 |
lte |
Context value is less than or equal to target. | retries lte 3 |
in |
Context value is a member of target collection. | tool_name in ["read", "write"] |
contains |
Target value is contained within context value. | arguments contains "password" |
matches |
Context value matches target regex pattern. | tool_name matches "^exec_.*" |
[Pure Specification]
If the condition references a context field that does not exist (returns
null/None), the condition MUST evaluate to false. A missing field MUST
NOT cause an error or exception.
[Pure Specification]
For the matches operator, both the context value and the target value
MUST be coerced to strings before regex evaluation. For all other
operators, no implicit type coercion is performed. If the types are
incompatible (e.g., comparing a string with gt), the behavior is
implementation-defined, but the implementation MUST NOT raise an
unhandled exception.
[Pure Specification]
| Action | Allowed | Semantics |
|---|---|---|
allow |
Yes | The action is permitted. |
deny |
No | The action is blocked. The agent MUST NOT proceed. |
audit |
Yes | The action is permitted but MUST be logged for review. |
block |
No | Alias for deny. The action is blocked. |
An action is considered "allowing" if it is allow or audit. An
action is considered "denying" if it is deny or block.
[Pure Specification]
When evaluating a set of rules against an execution context:
- Rules MUST be sorted by
priorityin descending order (highest priority first). - Rules MUST be evaluated in sorted order.
- The first rule whose condition matches the context determines the decision. Subsequent rules are NOT evaluated.
- If no rule matches and external backends are registered, backends MUST be consulted in registration order. The first backend that returns a non-error result determines the decision.
- If no rule matches and no backend produces a result, the default
action from the policy's
defaultsobject is applied.
[Pure Specification]
When a root_dir is configured and the execution context contains a
path field:
- The evaluator MUST use folder-scoped evaluation (see Section 12).
- Governance files are discovered from the action path up to the root, loaded, filtered by scope, and merged before evaluation.
When no root_dir is configured or the context lacks a path field:
- The evaluator MUST use flat evaluation against the loaded policy list.
[Pure Specification]
When using flat evaluation, if no rule matches, the default action MUST
be taken from the first loaded PolicyDocument's defaults.action field.
If no PolicyDocument is loaded, the default action MUST be allow.
When using scoped evaluation, the default action MUST be taken from the most specific (last) PolicyDocument in the merged chain.
[Pure Specification]
The GovernancePolicy is the runtime policy object used by framework
adapters. It provides direct constraint checking without requiring
PolicyDocument evaluation. Framework adapters MUST enforce
GovernancePolicy constraints on every governed agent action.
[Pure Specification]
| Field | Type | Default | Constraints |
|---|---|---|---|
name |
string | "default" |
Non-empty. |
max_tokens |
integer | 4096 |
MUST be > 0. |
max_tool_calls |
integer | 10 |
MUST be >= 0. 0 disables tool calls. |
allowed_tools |
string[] | [] |
Empty list means all tools permitted. |
blocked_patterns |
array | [] |
Each entry is a string or (string, PatternType) tuple. |
require_human_approval |
boolean | false |
When true, tool calls require human approval. |
timeout_seconds |
integer | 300 |
MUST be > 0. |
confidence_threshold |
float | 0.8 |
MUST be in [0.0, 1.0]. |
drift_threshold |
float | 0.15 |
MUST be in [0.0, 1.0]. |
log_all_calls |
boolean | true |
Whether all calls are audit-logged. |
checkpoint_frequency |
integer | 5 |
MUST be > 0. Create checkpoint every N calls. |
max_concurrent |
integer | 10 |
MUST be > 0. |
backpressure_threshold |
integer | 8 |
MUST be > 0. |
version |
string | "1.0.0" |
MUST be non-empty. |
[Pure Specification]
Policy validation MUST occur at construction time. Implementations MUST reject invalid policies with a clear error message. The following invariants MUST hold:
max_tokens,timeout_seconds,max_concurrent,backpressure_threshold,checkpoint_frequencyMUST be positive integers.max_tool_callsMUST be a non-negative integer.confidence_thresholdanddrift_thresholdMUST be floats in [0.0, 1.0].- Every entry in
allowed_toolsMUST be a string. - Every entry in
blocked_patternsMUST be a string (substring match) or a (string, PatternType) tuple. versionMUST be a non-empty string.
[Default Implementation]
Implementations SHOULD provide a detect_conflicts() method that
returns warnings for contradictory settings:
backpressure_threshold >= max_concurrent(backpressure never triggers)max_tool_calls == 0with non-emptyallowed_tools(tools allowed but no calls permitted)confidence_threshold == 0.0(confidence checking effectively disabled)timeout_seconds < 5(unreasonably low timeout)
[Pure Specification]
A policy A is "stricter than" policy B if and only if:
-
ALL of the following hold:
A.max_tokens <= B.max_tokensA.max_tool_calls <= B.max_tool_callsA.timeout_seconds <= B.timeout_secondsA.max_concurrent <= B.max_concurrentA.backpressure_threshold <= B.backpressure_thresholdA.confidence_threshold >= B.confidence_thresholdA.checkpoint_frequency <= B.checkpoint_frequencylen(A.blocked_patterns) >= len(B.blocked_patterns)- If B requires human approval, A must also require it.
-
AND at least one field is strictly more restrictive (not merely equal).
[Pure Specification]
Three pattern types MUST be supported:
| Type | Semantics |
|---|---|
substring |
Case-insensitive substring search. The pattern is a plain string. |
regex |
Case-insensitive regular expression search (PCRE-compatible). |
glob |
Case-insensitive glob pattern (e.g., *.exe), internally converted to regex. |
[Pure Specification]
When a blocked pattern is specified as a plain string (not a tuple), it
MUST be treated as a substring pattern.
[Default Implementation]
Regex and glob patterns SHOULD be compiled at policy construction time. Invalid regex patterns MUST cause a validation error at construction time, not at match time.
[Pure Specification]
- Substring matching MUST be case-insensitive.
- Regex matching MUST use search semantics (not full-match). The pattern need not match the entire input string.
- Glob matching MUST follow POSIX glob semantics as implemented by
fnmatch, with case-insensitive comparison. - The
matches_pattern(text)method MUST return ALL patterns that match, not just the first.
[Pure Specification]
A tool call request MUST carry:
| Field | Type | Description |
|---|---|---|
tool_name |
string | Name of the tool being invoked. |
arguments |
dict | Arguments passed to the tool. |
call_id |
string | Optional unique call identifier. |
agent_id |
string | Optional agent identifier. |
metadata |
dict | Optional metadata (e.g., content hashes). |
[Pure Specification]
A tool call interception result MUST carry:
| Field | Type | Description |
|---|---|---|
allowed |
boolean | Whether the call is permitted. |
reason |
string or null | Explanation for denial. |
modified_arguments |
dict or null | Sanitized arguments (if the interceptor rewrites them). |
audit_entry |
dict or null | Structured audit metadata. |
[Pure Specification]
The default PolicyInterceptor MUST check constraints in the following
order. The first failing check short-circuits evaluation:
- Human approval: If
require_human_approvalis true, DENY. - Allowed tools: If
allowed_toolsis non-empty and the tool name is not in the list, DENY. - Blocked patterns: If the string representation of the arguments matches any blocked pattern, DENY.
- Call count: If the current call count >=
max_tool_calls, DENY.
If all checks pass, ALLOW.
[Pure Specification]
A composite interceptor chains multiple interceptors. ALL interceptors MUST allow the call for it to proceed. The first interceptor that denies terminates the chain immediately (short-circuit deny).
[Default Implementation]
Implementations SHOULD provide a ContentHashInterceptor that verifies
tool identity via SHA-256 content hashing. In strict mode, tools with no
registered hash MUST be blocked. In non-strict mode, unknown tools
SHOULD be allowed with a warning.
[Pure Specification]
When multiple PolicyDocuments are discovered in a folder hierarchy, they MUST be merged into a single flat rule list following these rules:
- PolicyDocuments are provided in root-first order (root at index 0, most specific directory last).
- Rules from all levels are collected.
- When a child rule has
override: trueand the samenameas a parent rule:- If the parent rule has action
deny: the child override MUST be dropped. Parent deny rules are immutable. This is a security invariant. - Otherwise: the child rule replaces the parent rule.
- If the parent rule has action
- When a child rule has the same
nameas a parent rule butoverride: false(or omitted): the child rule MUST be dropped. The parent version is kept. - Rules with unique names are appended normally.
- The final merged list MUST be sorted by priority descending.
[Pure Specification]
A parent deny rule MUST NOT be overridden by a child rule. This invariant ensures that security-critical deny rules set at higher levels of the hierarchy cannot be circumvented by more specific policies. This matches Azure Policy semantics where deny assignments cannot be overridden.
Rationale: Without this invariant, a child policy could set
override: true and a higher priority on a rule of the same name,
effectively defeating the parent deny at evaluation time.
[Pure Specification]
When multiple PolicyDocuments are merged, the effective defaults MUST come from the most specific (last) PolicyDocument in the chain.
[Pure Specification]
Policy discovery walks the directory tree from the action path upward to the configured root directory:
- At each directory level, check for
governance.yamlorgovernance.yml(in that order). If found, add to the candidate list. - Stop when the root directory is reached or no parent exists.
- Reverse the candidate list to produce root-first order.
[Pure Specification]
If a PolicyDocument declares inherit: false, all parent policies above
that level MUST be excluded from the chain. The policy with
inherit: false becomes the new effective root.
Inheritance is checked from most specific to least specific. The first
inherit: false encountered determines the cut point.
[Pure Specification]
If a PolicyDocument declares a scope glob pattern, the document MUST
only apply when the action path (relative to root, forward-slash
normalized) matches the glob pattern. Documents with scope: null apply
to all action paths under their directory.
[Pure Specification]
If the resolved action path is NOT relative to the configured root
directory (e.g., due to symlinks, .. segments, or attacker-influenced
path fields), the evaluator MUST refuse to discover policies and MUST
return an empty policy chain. This prevents path-traversal attacks on
the policy chain.
[Pure Specification]
When multiple policies produce competing decisions for the same agent action, a conflict resolution strategy determines the final outcome.
[Pure Specification]
Conforming implementations MUST support the following strategies:
If ANY candidate decision is a deny, the action is denied. Among multiple denies, the highest-priority deny wins. If no deny exists, the highest-priority allow wins.
This is the safest strategy and aligns with XACML deny-overrides semantics.
If ANY candidate decision is an allow, the action is allowed. Among multiple allows, the highest-priority allow wins. If no allow exists, the highest-priority deny wins.
Use this for exception-based governance where explicit allow rules should override default-deny policies.
Candidates are sorted by priority descending. The highest-priority candidate wins regardless of action type.
This is the default strategy and preserves backward compatibility.
Candidates are ranked by scope specificity (Agent > Organization > Tenant > Global). Within the same scope, priority breaks ties.
[Pure Specification]
Four scope levels are defined, ordered from least to most specific:
| Scope | Specificity | Description |
|---|---|---|
global |
0 | Organization-wide defaults. |
tenant |
1 | Tenant or team scoped. |
organization |
2 | Organization unit scoped. |
agent |
3 | Specific agent instance. |
[Pure Specification]
A conflict resolution result MUST include:
- The winning decision
- The strategy that was used
- Number of candidates evaluated
- Whether a genuine conflict was detected (mix of allow and deny)
- A trace of the resolution logic (for audit purposes)
[Pure Specification]
If zero candidates are provided for resolution, the resolver MUST raise an error. This is a programming error, not a policy decision.
[Pure Specification]
External policy backends MUST implement:
- A
nameproperty returning a human-readable identifier. - An
evaluate(context)method accepting an execution context dict and returning aBackendDecision.
[Pure Specification]
| Field | Type | Description |
|---|---|---|
allowed |
boolean | Whether the action is permitted. |
action |
string | The policy action (default: "allow"). |
reason |
string | Human-readable explanation. |
backend |
string | Backend identifier for audit. |
evaluation_ms |
float or null | Evaluation time in milliseconds. |
error |
string or null | Error message if evaluation failed. |
[Pure Specification]
External backends are consulted only when no YAML/JSON rule matches.
Backends are evaluated in registration order. The first backend that
returns a result with error == null determines the decision.
If a backend returns a result with a non-null error, the evaluator
MUST skip that backend and try the next. If all backends error, the
evaluator MUST fall through to the default action.
[Default Implementation]
The reference implementation provides:
- OPABackend: Evaluates Rego policies via the OPA CLI or library.
- CedarBackend: Evaluates Cedar policies via the Cedar CLI or library.
Implementations MAY provide additional backends.
[Pure Specification]
Implementations MUST enforce concurrency limits:
- When active executions reach
max_concurrent, new requests MUST be rejected. - When active executions reach
backpressure_threshold(which SHOULD be less thanmax_concurrent), implementations SHOULD begin applying backpressure (e.g., throttling, queuing, or adding latency).
[Pure Specification]
Slot acquisition MUST be atomic (no TOCTOU races). The response MUST indicate whether the slot was acquired and, if not, the reason for rejection.
[Pure Specification]
If the policy engine encounters an unhandled exception during evaluation, it MUST deny the action. The engine MUST NOT allow an action when it cannot determine whether the action is permitted.
This applies to:
- Errors during condition matching
- Errors during policy loading or parsing
- Errors communicating with external backends
- Any other unexpected exception
[Pure Specification]
The fail-closed decision MUST include:
allowed: falseaction: "deny"- A reason indicating policy evaluation error
- An audit entry with
error: true
[Pure Specification]
All fail-closed events MUST be logged at ERROR level with full exception context (stack trace, original context snapshot).
[Pure Specification]
Every policy decision MUST produce an audit entry containing:
| Field | Required | Description |
|---|---|---|
policy |
Yes | Name of the policy or "folder-scoped". |
rule |
Yes | Name of the matched rule, or null. |
action |
Yes | The action taken (allow, deny, audit, block). |
context_snapshot |
Yes | The execution context at decision time. |
timestamp |
Yes | ISO 8601 UTC timestamp. |
Scoped evaluations MUST also include:
| Field | Description |
|---|---|
policy_chain |
Ordered list of policy names in the merge chain. |
Backend evaluations MUST also include:
| Field | Description |
|---|---|
backend |
Backend name. |
evaluation_ms |
Backend evaluation time. |
[Pure Specification]
The policy engine MUST emit the following event types:
| Event | When |
|---|---|
policy_check |
Every policy evaluation. |
policy_violation |
A rule or constraint is violated. |
tool_call_blocked |
A tool call is denied by an interceptor. |
checkpoint_created |
A governance checkpoint is created. |
drift_detected |
Semantic drift exceeds the configured threshold. |
[Pure Specification]
Policy composition follows these rules:
- Additive deny: Deny rules from multiple sources accumulate. A deny from any source blocks the action.
- Immutable parent deny: Parent deny rules cannot be overridden by children (see Section 11.2).
- Last-specific-wins for defaults: In a merge chain, the most specific policy's defaults take precedence.
- Most-restrictive for limits: When comparing policies via
is_stricter_than(), the comparison is per-field and all fields must be at least as restrictive.
[Pure Specification]
Every GovernancePolicy MUST carry a version string. Policy version
changes MUST be auditable. Implementations MUST support comparing two
policy versions and reporting field-level diffs.
[Pure Specification]
A GovernancePolicy serialized to YAML and deserialized back MUST produce a semantically equivalent policy. The round-trip MUST NOT lose any field values.
[Pure Specification]
A GovernancePolicy serialized to a dictionary via to_dict() and
reconstructed via from_dict() MUST produce a semantically equivalent
policy.
[Pure Specification]
When deserializing, unknown fields MUST be silently ignored. This enables forward compatibility when newer policy versions add fields.
A conforming implementation MUST:
- Support the full PolicyDocument schema (Section 3).
- Support all nine condition operators (Section 5).
- Support all four policy actions (Section 6).
- Implement priority-ordered, first-match evaluation (Section 7).
- Implement folder-level policy discovery and merge (Sections 11-12).
- Enforce the deny immutability invariant (Section 11.2).
- Implement path traversal protection (Section 12.4).
- Support all four conflict resolution strategies (Section 13).
- Support the ExternalPolicyBackend protocol (Section 14).
- Enforce fail-closed semantics on all evaluation errors (Section 16).
- Produce structured audit entries for every decision (Section 17).
- Support YAML serialization for PolicyDocuments (Section 19).
Framework adapters that use GovernancePolicy MUST additionally:
- Validate policies at construction time (Section 8.3).
- Support all three pattern types (Section 9).
- Enforce the tool call interception order (Section 10.3).
- Enforce concurrency limits (Section 15).
Policy:
version: "1.0"
name: "no-code-execution"
rules:
- name: block-execute
condition:
field: tool_name
operator: eq
value: execute_code
action: deny
priority: 100
message: "Code execution is not permitted in this environment"
defaults:
action: allowContext:
{"tool_name": "execute_code", "agent_id": "assistant-1"}Expected Decision:
allowed: falsematched_rule: "block-execute"action: "deny"reason: "Code execution is not permitted in this environment"
Root governance.yaml:
version: "1.0"
name: "org-security"
rules:
- name: no-delete
condition:
field: tool_name
operator: eq
value: delete_resource
action: deny
priority: 200
message: "Deletion blocked by org policy"Subfolder governance.yaml:
version: "1.0"
name: "dev-environment"
rules:
- name: no-delete
condition:
field: tool_name
operator: eq
value: delete_resource
action: allow
priority: 300
override: true
message: "Dev environment allows deletion"Expected Behavior: The child's override attempt MUST be dropped
because the parent rule is a deny. The no-delete deny rule from the
root MUST remain in effect regardless of the child's higher priority.
Scenario: YAML rules have no match. An OPA backend is registered.
Expected Behavior:
- YAML rules evaluated first: no match.
- OPA backend consulted: returns
{allowed: true, action: "allow"}. - Decision: allowed, with audit entry including
backend: "opa".
Scenario: A regex pattern in a condition is somehow malformed at evaluation time (should have been caught at construction, but edge case).
Expected Behavior:
- Decision:
allowed: false,action: "deny" - Reason: "Policy evaluation error -- access denied (fail closed)"
- Audit entry includes
error: true - Exception logged at ERROR level
Candidates:
- Rule "allow-read" from agent-scope policy:
action: allow, priority: 50 - Rule "block-all" from global policy:
action: deny, priority: 10
Strategy: DENY_OVERRIDES
Expected Result:
- Winner: "block-all" (deny overrides regardless of priority)
conflict_detected: true- Trace:
["DENY_OVERRIDES: 1 deny rule(s) found", "Winner: block-all ..."]
Policy discovery walks the filesystem. Implementations MUST validate that action paths are within the configured root to prevent loading policies from arbitrary locations (see Section 12.4).
Regex patterns in blocked_patterns and matches conditions are
compiled from user-provided strings. Implementations MUST catch
compilation errors at construction time. Implementations SHOULD consider
ReDoS (Regular Expression Denial of Service) when accepting patterns
from untrusted sources.
The execution context is supplied by the framework adapter. If the adapter runs in the same process as the agent, a compromised agent could tamper with its own context. Implementations SHOULD use out-of-process policy evaluation or signed context fields for high-security deployments.
The fail-closed behavior (Section 16) is a deliberate security design. Systems that default to allow on error create exploitable failure modes. Never change the default to fail-open.