Policy engine
Xenovia uses Open Policy Agent (OPA) to evaluate Rego policies. Policies are attached per proxy and evaluated synchronously on every request. There are two independent policies per proxy:- Request-stage policy — evaluated before the request is forwarded to the upstream LLM.
- Response-stage policy — evaluated after the LLM responds, before the response is returned to the agent.
(proxy_id, policy_hash). Eval timeout is 200ms; compile timeout is 2s.
Decision actions
Request stage
| Action | HTTP status | Effect |
|---|---|---|
allow | — | Request forwarded to upstream |
block | 403 Forbidden | Request terminated, trace recorded |
redact | — | PII removed from messages/tools before forwarding |
Response stage
| Action | HTTP status | Effect |
|---|---|---|
allow | — | Response returned to agent |
block_response | 403 Forbidden | Response suppressed, trace recorded |
redact_response | — | PII removed from response content before returning |
redact and redact_response, specify which fields to redact with the redact_fields set. Supported patterns:
| Field | Pattern |
|---|---|
email | Standard email regex |
ssn | US Social Security Number format |
Policy input schema
Both request-stage and response-stage policies receive the same base input. The policy engine exposesinput with the following fields:
Request-stage input
Response-stage additional fields
Writing policies
Policies are written in Rego under the packagexenovia.policy. The policy engine reads the deny set and the redact_fields set.
Minimal allow-all policy
Block a specific tool
Require approval for production writes
Redact PII from requests
Block based on intent score
Response-stage: block low-confidence outputs
Allowlist specific models
Policy blocks in your application
When a request is blocked, the runtime returns403 Forbidden. The response body follows the standard error format:
PermissionDeniedError. The X-Xenovia-Trace-Id header is present on blocked responses — use it to look up the full trace.
Approval workflow
For actions that require human review rather than automatic blocking, use the intent plugin’sescalate action (configured per proxy in the platform). When an escalation fires:
- The request is blocked with
403. - An async notification is sent to the control plane with the full request context.
- Operators review the trace — including the session, turn number, messages, tools, and intent score — and approve or deny.