Skip to main content
Xenovia evaluates Open Policy Agent (OPA) Rego policies on every proxied request. Policies are created in the control plane, attached to a proxy, and enabled. Each proxy can run policies at two stages:
  • Request stage — before the request is forwarded to the upstream model.
  • Response stage — after the model responds, before the reply reaches your app.
Enabled policies are compiled to a per-proxy snapshot, pushed to the runtime, and revalidated by each runtime instance about every five minutes. OPA evaluates with a 2-second compile timeout and a 200-millisecond per-stage evaluation timeout.

The decision contract

A policy returns a single decision object. This is the only value the runtime reads — allow/deny rules or a bare redact_fields set are ignored.
  • Write package xenovia. The control plane strips your package line and re-packages the rule under a system namespace, so the package name you choose does not matter.
  • action is required; rule is a short identifier recorded on the trace. Any other key (including reason) is ignored by the runtime.
  • Multiple complete decision rules must have mutually exclusive conditions. If two can be true at once, OPA reports a conflict and the request fails closed. Guard each rule with distinct conditions (for example on input.agent_role).
The Rego is compiled with opa check --strict when you save it. Compilation errors are returned as 422 with the OPA diagnostics.

Actions

When several enabled policies run at the same stage, the strongest action wins: block over escalate over redact over allow (and block_response over redact_response at the response stage). An unrecognised action ranks below allow and can never block.

Redaction

Return the labels to strip in redact_fields:
Supported labels: email, ssn, phone, creditcard (Luhn-validated), ip, url. Redaction applies to message text, tool descriptions, and the Responses instructions field at the request stage, and to the reply text at the response stage. Redaction is not applied mid-stream; a streamed response that matches a redact_response rule is passed through unredacted and the event is recorded.

Monitor vs enforce

Enforcement is a property of the policy, set in the dashboard (Monitor or Enforced) or through the API, not something you express in Rego:
  • Enforced policies apply their action.
  • Monitor policies are evaluated and their would-be decision is recorded on the trace, but the action is never applied. Use monitor mode to trial a policy against live traffic before enforcing it.

Policy input

Both stages receive the same base fields; each stage adds its own.

Base fields (both stages)

Request stage adds

intent_score and intent_action are not available at the request stage — policy runs before intent scoring. They are available at the response stage.

Response stage adds

Examples

Block a tool

Require the proxy’s model to be on an allowlist

input.model is the model configured on the proxy, so this rule guards against a proxy pointed at an unapproved model rather than a client choosing one.

Cap output tokens (request stage)

Block a refusal in the reply (response stage)

What a block looks like to your app

A blocked request returns 403. The runtime uses the gateway error envelope:
The OpenAI SDK raises this as PermissionDeniedError. The message is deliberately generic; the rule that fired is recorded on the trace, not returned to the caller. The X-Xenovia-Trace-Id response header identifies the trace.

Escalations

escalate is for actions you want flagged for human attention. When a request-stage rule (or the intent guardrail) escalates:
  1. The request is blocked with 403 (request escalated for human review).
  2. An escalation signal is recorded, carrying the proxy, score, and matched rule.
  3. Any alert rule watching for escalations fires (see Alerts).
There is no approve/deny queue today. An escalation blocks the request and raises a signal; it does not pause the request for an operator to release. Review escalations in Sessions and in Alerts, then adjust the policy or intent configuration. Reasons are recorded server-side and are never returned to the agent.