Policy rules
The rule schema evaluated on every scan, and the directives it can contribute to a verdict.
Every scan accepts a policyOverrides/policy_overrides array — additive
rules evaluated on top of your app's saved policy, not a replacement for
it. A matched rule contributes directives to the result's policy
field; your application decides what to actually do with them, the same
way it decides what to do with action (see
Enforcing a policy below).
{
"text": "…",
"policyOverrides": [
{
"id": "block-finance-tool-for-guests",
"when": { "tool_name": "transfer_funds", "caller_role": "guest" },
"directives": ["block"]
}
]
}{
"policy": {
"directives": ["block"],
"matchedRuleIds": ["block-finance-tool-for-guests"]
}
}A rule
id— your own identifier, echoed back inmatchedRuleIdswhen the rule fires.when— conditions, ANDed together. A rule with an emptywhenmatches every request.directives— strings your rule contributes to the verdict when it matches. Free-form except for a couple the engine treats specially (see below) — define whatever vocabulary makes sense for your application and branch on it at the call site.force(optional) —"block"or"allow". A matchingforcerule short-circuits every other rule;force: "block"always wins if both a block and an allow force-rule somehow match (safety-first).
What you can match on
| Key | Matches |
|---|---|
tool_injection_flag, prompt_extraction_flag, jailbreak_flag | Boolean detection flags for this scan |
risk_gte, risk_lte | The scan's risk score |
provenance | What kind of content this is (user_prompt, rag_chunk, tool_call, ...) |
tool_name, tool_name_in | The tool being called (agent protection only) |
caller_role, caller_role_not | The role you passed for whoever initiated the call |
operation_type | Your own operation classification, if you set one |
tool_call_scope | A coarse scope classification of the tool's arguments |
sensitive_data | Whether sensitive data was detected |
keywords_any | Any of a list of keywords appearing in the text |
length_gte, length_lte | The text's length |
Directives with built-in meaning
Two directive strings get special handling by the engine on top of the normal union-of-matched-rules behavior:
"block"— as aforcerule's directive (or viaforce: "block"itself), short-circuits every other rule. As a plain directive from a normal rule, it's just unioned in like anything else — your app decides whether to treat it as authoritative."disable_tools"— automatically suffixed with the tool name at match time ("disable_tools:run_query"), so one rule can disable whichever tool triggered it without hardcoding the name.
"redact_pii" and "log_security_event" can also appear automatically,
contributed by your app's PII detection settings rather than a rule you
wrote — same field, same union.
Everything else is your own vocabulary — define whatever directive
strings make sense ("strip_system_prompt", "require_human_review",
...) and branch on them where you enforce the policy.
The worker only signals directives — it never withholds a tool call or
otherwise enforces anything on your behalf. Enforcement is always your
application's responsibility, matching how action works.
Enforcing a policy
Activating a template or a custom rule in the dashboard's Policy Studio
only changes what result.policy contains on future scans — it never
blocks anything by itself. For the exact pattern per integration (raw
HTTP, the SDKs, and the framework integrations), see: