Behaviors & the policy input
A Behavior is one intended action, described to the kernel before it runs. Policy never sees your raw HTTP request — it sees a Behavior plus collected facts, assembled into a versioned policy input document.
Behavior types
Section titled “Behavior types”| Type | What it represents | Key payload fields |
|---|---|---|
LLM_CALL |
A prompt to a model | model, prompt / messages |
PROMPT_SUBMIT |
A user prompt entering the agent | prompt, role |
EMBEDDING_CALL |
An embedding request | model, inputs |
TOOL_CALL |
A tool/function invocation | tool, args |
CREDENTIAL_ACCESS |
A read of a secret, token, or credential | provider, scope, secret_ref (never the value) |
CODE_EXEC |
Code execution (shell, script, sandboxed runtime) | runtime, source, command_hash, isolation |
SOR_WRITE |
A write to a system of record | {target}.{field}, old/new value |
STATE_TRANSITION |
An agent state change | from, to, trigger |
TOOL_LIST |
Tool discovery (e.g. MCP tools/list) |
— |
Payloads are validated against a strict schema before evaluation; an unknown or malformed payload never reaches policy.
CREDENTIAL_ACCESS and CODE_EXEC are first-class risk types: secret reads and code execution get dedicated types so taint and containment rules don’t depend on tool-name conventions (“no CODE_EXEC after any CREDENTIAL_ACCESS in this session”). The Claude Code hook and MCP bridge emit them automatically — Bash arrives as CODE_EXEC, a read of .env/.pem/.key as CREDENTIAL_ACCESS.
The policy input: five axes
Section titled “The policy input: five axes”Every rule reads from the same document, built fresh per call:
{ "request": { // the action itself "tool": "send_email", // or "{target}.{field}" for SOR_WRITE "model": "gpt-4o", "provider": "openai", // derived from the model name "model_tier": "frontier", // from your org's model catalog "model_location": "us", "tool_args": { "to": "…", "subject": "…" }, "estimated_tokens": 412, "url_domain": "acme.com", // lifted structurally from args "path": "/srv/data/report.csv", "reasoning_effort": "medium" }, "subject": { // who is acting "id": "agent-123", "role": "support-agent", "trust_tier": "internal", "end_user": "user@acme.com", "approval": { /* granted approval, if this call resumes one */ }, "user": { /* directory lookup, if the policy reads it */ } }, "environment": { // when and where "now": "2026-07-21T09:14:03Z", "hour": 9, "day_of_week": "Tue", "region": "eu" }, "state": { // accumulated session state "session": { "event_count": 17, "unique_resources": 4 }, "path": { "tools": ["read_file", "query_db", "read_file"] }, "spend": { /* windowed spend */ }, "tokens_used_today": 182340, "tool_rate": { /* per-tool call rate */ } }, "findings": { // detector output "pii": [ /* detected PII entities */ ], "secrets": [ /* detected secrets */ ], "injection_score": 0.0, "unicode": [ /* zero-width / bidi / confusable findings */ ], "tool_integrity": { /* tool-definition drift */ }, "tool_baseline": { /* anomaly vs this agent's learned arg baseline */ } }}Response-side evaluation (govern_response, the POST phase of enforce) gets the same document plus findings.response.* — PII, secrets and indirect-injection findings from the model’s output — and, when the LLM judge is enabled, findings.judge.grounded scores.
Producers: facts on demand
Section titled “Producers: facts on demand”Each block above is supplied by a producer. Producers run only when the agent’s policy actually reads their paths — a policy that never references findings.pii never pays for PII detection. Producers run only when policy references their facts.
If a producer fails, the decision fails closed (fact_collection_failed). A session-store outage yields state.session = {"unavailable": true} — a policy can distinguish “no history” from “history unknown” and refuse either way.
The detectors
Section titled “The detectors”| Finding | Detector | Notes |
|---|---|---|
findings.pii |
PII detector | 20+ PII entity types including EU recognizers |
findings.secrets |
100+ provider secret patterns plus entropy analysis | AWS, GCP, Azure, OpenAI, Anthropic, GitHub, Slack, Stripe… |
findings.injection_score |
Injection detector | detects structural, jailbreak, obfuscation, indirect and multilingual injection; score 0–1 |
findings.unicode |
Codepoint scanner | Zero-width, bidi overrides, confusables |
findings.judge |
LLM judge (response side) | Groundedness and per-rule conformance scores in [0, 1] |
Detectors are the kernel’s eyes; policy is the brain. A detector never blocks anything itself — it emits findings, and your rules decide what they mean.
Next steps
Section titled “Next steps”- Verdicts, obligations & mandates — what the kernel returns
- Sessions & path-aware policy — how
state.pathaccumulates