Policies

How Gateway-Level, Surface-Level, and model Rego policies, evaluated by an embedded OPA engine, decide whether a request is allowed.

Guardrails decide whether content is safe. Policy decides whether a caller is allowed to make the request at all, based on identity, context, and organisational rules. On an LLM Surface, the appliance-wide (global) policies for that surface type run before the surface’s own OPA policy. Both are deny-overrides and fail-closed, so a deny from either stops the request. A global policy set to Monitor only is the exception: it records its decision without blocking. Cost and usage governance →

OPA

OPA is the embedded Rego policy engine used by Agent Stream, so policies are compiled and evaluated in-process with no sidecar or network round trip.

Gateway-Level Policy

Gateway-Level Policy is the Trust Fabric policy type, attached to the appliance’s own gateway or to a gateway connection, or enforced appliance-wide. It gates fabric traffic, the gateway-to-gateway (DIDComm) traffic between appliances, rather than LLM Surface requests.

Surface-Level Policy

Surface-Level Policy is the OPA policy attached to a Surface and evaluated after the global policies for its surface type. LLM Surface policies use the package llm.policy; IDE Surface policies use the package ide.policy.

How front-door policy tells discovery apart from dispatch

The IDE Surface’s OPA input distinguishes, in input.request.purpose, discovery (GET /v1/models, which a policy can allow unauthenticated) from dispatch (POST /v1/chat/completions, which requires the signed-in caller), so sign-in never hits a chicken-and-egg where a client cannot fetch the sign-in profile because it is not yet signed in.

How a policy reference points to a reusable definition

  • Policy Reference: A pointer from a Surface or a Gateway field to a stored OPA policy definition.
  • Policy Definition: Stored Rego source plus metadata that can be reused by many Surfaces or Gateways. Definitions are immutable per version and carry a content hash so audit evidence can prove the exact bytes that ran.

A surface or gateway can also enforce more than one policy at once. The combination is deny-overrides, so every referenced policy must allow a request for it to proceed. An administrator can additionally mark one or more policies as enforced globally across every surface of a type, ANDed with that surface’s own policy set, with a monitor-only rollout mode for observing the effect of a global policy before it blocks anything.

The Policies page showing its type tabs and a policy row with its Global switch on, a Monitor badge, and the Monitor only checkbox checked

Model Allow-List

A Model Allow-List is a member-level list of models the Member is permitted to invoke. A request to a model that is not on the allow-list is rejected with 403 model_not_allowed.

What each policy type checks

You create policies of three types, each with its own Rego package. The Policies page shows them on the Trust Fabric, LLM Policies, and IDE Policies tabs:

Policy typePackageApplies to
Trust Fabricagentstream.policyAppliance-to-appliance (DIDComm) fabric traffic, rather than LLM Surface requests.
LLM Policiesllm.policyLLM Surfaces.
IDE Policieside.policyThe IDE catalogue’s front door, then any per-member Model Policy once the front door passes. After dispatch, the member LLM Surface’s own policies, global and surface-level, still apply.
Request
→
Global policies
→
Surface policy
→
Request continues

What a policy can see

Agent Stream builds this input document automatically before every evaluation. A policy only ever reads from it and never declares or constructs input itself. Optional fields appear only when they apply to the current request. An abridged example for a chat request to an LLM Surface:

{
  "schema_version": 1,
  "http": { "method": "POST", "path": "/v1/chat/completions" },
  "source_auth": { "method": "jwt_bearer", "subject": "user-123", "claims": { "role": "admin" } },
  "resource": { "model": "gpt-5.5", "surface_type": "llm" },
  "action": "dispatch",
  "environment": { "now": "2026-01-01T00:00:00Z" },
  "identity_binding": { "verified": true, "agent_did": "did:web:agent.example", "issuer_did": "did:web:issuer.example" }
}

schema_version versions the input contract itself. source_auth.method names how the caller authenticated: jwt_bearer, api_key, or mtls. action is dispatch for a request to a model, and connect when a realtime voice session opens.

A policy reads a value with plain dot notation, such as input.source_auth.claims.role == "admin" to check a JWT claim, or input.resource.model to gate on the requested model. See Input document → for the complete field-by-field reference, including the fields not shown here.

Policies are immutable and versioned

Editing a policy never overwrites it: each save appends a new, numbered version, and prior versions are kept for as long as the policy exists. A denial recorded in a governance record names the policy, its version, and its content hash, so it can be proven against the precise policy that produced it. A policy change can also be dry-run against a sample input before it is activated, so a bad global policy doesn’t lock out every surface it applies to.

A policy's Test (dry-run) panel above its Version history, with a side-by-side diff between two saved versions

Why an embedded, in-process engine matters

Because policy evaluation runs in-process rather than as a network call to a sidecar, a policy decision adds no network latency and has no separate service to keep available.