Skip to main content
Policy-as-Code · authored, tested, enforced

Define AI policy once. Test it before you activate it. Then enforce it at the gateway, not in ten repos.

DVARA expresses which models and tools a caller may use, and under which conditions, in one declarative language that changes without shipping application code. Dry-run a draft against a request you describe, shadow it against real traffic to see what it would have done, then promote it — versioned and reversible.

A static model allow/deny list runs keyless; the policy language and its lifecycle are licensed.

Why shouldn't AI governance live in application code?

When AI rules live in scattered application code, nobody can answer “what is allowed?” without reading ten repos. Changing a rule means a deploy, testing one means hoping, and there is no record of who changed what or what it would have done. Moving the rules into one versioned engine makes the question answerable — for the traffic that routes through the gateway, which is the boundary worth being precise about.

What can a policy actually say?

Less than the phrase “policy engine” suggests, and that is the useful part: a closed set of conditions and exactly two actions, so what a rule can do is something you can hold in your head.

Nine condition types, and only nine

Match on the model, requested tools, an MCP server, tool or arguments, the token ceiling, data residency, time of day, or how much of a budget cap is used. The schema is closed — an unrecognised key fails the submit rather than quietly matching nothing.

Two actions, and only two

A rule either denies the call with a message you wrote, or warns the agent and lets it through with the warning attached. There is no allow action, no routing action, and no approval action — approval gates live on the MCP and A2A planes, not in this DSL.

CEL where the matchers cannot compose

For anything needing OR, NOT, or arithmetic across fields, a rule takes a CEL expression instead of the closed-form conditions — the same sandboxed language Kubernetes admission policies use, compiled and type-checked when you submit. One rule instead of three.

A closed evaluation surface

CEL rules see the model, tenant, message count, a coarse size proxy, request metadata, the gateway and tenant regions, and budget utilization — not the message text. Time functions are not in this version, so time windows use the closed-form matcher.

Scope is on the policy, not the rule

A policy is either platform-wide or scoped to one tenant, decided when you create it. There is no tenant condition inside a rule, and a tenant cannot stamp another tenant’s ID on a policy it authors.

What a tenant cannot see

From the tenant portal, another customer’s policies are not in the list, and the operator’s platform-wide policies are not editable — they apply, but changing one is the operator’s change-control, not the tenant’s.

What does a rule look like?

An allowlist of approved models, denying anything outside it. Every key here is one the parser accepts — an unrecognised key fails the submit rather than becoming a rule that quietly never matches.

version: "1"
rules:
  - id: only-approved-models
    priority: 10
    conditions:
      model:
        allowlist: [gpt-4o, gpt-4o-mini, claude-sonnet-4-5]
    action: DENY
    deny_message: "Model not on the approved list"

The rule runs at priority 10, so it is evaluated before anything left at the default of 100. A request for a model outside the list is denied with that message; a request for one on it matches nothing else and proceeds.

What happens when two rules could both apply?

Ordering is explicit and the outcome is decidable by reading the rules, which is the property that makes a policy reviewable rather than something you test by trying it.

Rules run in priority order

Each rule carries a priority, where a lower number goes first and the default is 100. Ordering is something you set deliberately rather than something inferred from how specific a rule looks.

The first matching deny wins

Evaluation stops at the first rule that denies, and its message is what the caller gets. Warn rules do not stop anything — they collect their warnings and evaluation continues.

No match means allowed

A request that matches no rule proceeds. Policy is a set of denials over an open default, so a model nobody wrote a rule about is usable — write an allowlist rule if that is not what you want.

Both scopes apply

Platform-wide policies apply to every tenant and a tenant’s own policies apply to it. A deny from either stops the call, so a tenant cannot widen what the platform has narrowed.

How does a policy go from draft to enforced?

Six steps, and two of them are tests that answer different questions. Draft, active, shadow and archived are statuses rather than a pipeline — shadow comes before active, not after it.

  1. 1

    Author it as a draft

    Write the rules in YAML in the editor. The YAML is compiled when you submit, not when the policy is later activated, so a typo fails immediately rather than silently disabling a rule. A draft is saved and affects nothing.

  2. 2

    Dry-run it against a synthetic request

    The dry-run panel walks one request you describe through the draft and returns the decision, the rule that matched, and how long evaluation took. It is stateless, calls no model, and stores nothing — it proves the rule fires, not how often it would fire.

  3. 3

    Ship it to shadow to see real traffic

    A shadow policy evaluates alongside your active ones on real requests and blocks nothing. Every divergence is recorded with the decision it would have made and a sample of the request, so after a day or two you can tell intent from false positives.

  4. 4

    Read the divergence before promoting

    The shadow dashboard shows total evaluations, how often the shadow would have denied where the active policy allowed, that rate over time, a breakdown per rule, and the recent divergent requests themselves.

  5. 5

    Promote it to active

    Confirm the promotion and conflict detection runs against the currently-active policies. Conflicts come back as warnings and the policy activates anyway — read them. Enforcement starts on the next request, and shadow data for that policy is cleared.

  6. 6

    Reverse it if it is wrong

    Set the status back to shadow or draft to stop enforcing, or restore an earlier version from the version list. Every create, update, and status change is recorded.

What does each safeguard actually prove?

Each one answers a narrower question than its name suggests. Knowing which question is which is the difference between a tested policy and a policy you feel good about.

What dry-run proves

That a rule you wrote fires on a request you describe, and that a rule you did not want to fire does not. It says nothing about how much of your live traffic the rule would touch — the request is synthetic.

What shadow proves

What the policy would have done to traffic that actually happened. This is the step that turns "I think this rule is right" into a number, and the reason to run it for a day or two rather than an hour.

What conflict detection does — and skips

At promotion it checks the candidate against every active policy across the nine condition types and reports overlaps as warnings. The policy still activates. For CEL rules it is skipped altogether — expression equivalence is undecidable — and you get a "verify manually" warning per rule instead.

What versioning gives you

Every save creates a version and the last ten are kept. Restoring an earlier one is a few steps with a confirmation, and it creates a new version carrying the old configuration rather than rewinding history.

How fast a change lands

Active and shadow policies take effect on the next data-plane request, picked up by a config poll rather than a restart. Seconds, not instant — worth knowing when you change a rule and immediately test it.

What it does not replace

This decides whether a call is allowed to be made. It is not your application’s authorization layer, and a caller who never routes through the gateway is not governed by it.

Where do you author a policy?

In DVARA Flightdeck, with the YAML editor on one side and the version history, status controls, and dry-run panel on the other.

The policy editor in DVARA Flightdeck, showing the YAML rules in an in-browser editor with the version history, status controls, and dry-run panel alongside it.The policy editor in DVARA Flightdeck, showing the YAML rules in an in-browser editor with the version history, status controls, and dry-run panel alongside it.
The policy editor. The panel on the right is where a draft is dry-run, moved through its statuses, and restored from an earlier version.

How does DVARA compare on policy and governance?

Against the three alternatives that score strongest on policy and governance in the matrix behind how DVARA compares — chosen by score, not by how weak they are. Each row is checkable against that product's own public documentation.

CapabilityDVARAKong AITrueFoundryAWS Bedrock
Policy-as-Code engine (YAML DSL)
Policy dry-run before activation
Policy versioning + rollback
RBAC access control
SSO (OIDC / SAML)
Pricing modelLicensed, sized by request volume — no hard stop on overageSee their pricingFree tier, then $499/mo tiers + usage overage (source)Token-metered on-demand, or provisioned throughput (source)

Capabilities last verified June 2026; pricing models August 2026. A stale mark is worse than no claim — every row is checkable against each product's own public documentation. For the full matrix across ten alternatives, see how DVARA compares.

What do you need to author policies?

A licence. What runs without one is narrower than it sounds, and the difference is worth reading before planning around it. See what a licence covers.

Common questions about Policy-as-Code

What is Policy-as-Code for LLM and agent traffic?

Rules about which models and tools a caller may use, and under what conditions, written in one declarative language, versioned, tested before activation, and evaluated at the gateway rather than scattered through application code. It decides whether a call is allowed to be made — it is not your application’s authorization layer.

Which planes does this policy language govern?

Model calls through the LLM Gateway and tool calls through the MCP Gateway — the same DSL covers both, since it carries conditions for MCP servers, tools, and arguments. Agent-to-agent hops are governed by a separate engine with its own rules and different semantics, so a policy written here does not govern an A2A hop.

What conditions and actions are supported?

Nine conditions: model as an allowlist or denylist, token ceiling, requested tools, MCP server, MCP tool, MCP arguments, data residency, time of day, and budget utilization. Exactly two actions: deny with a message, or warn the agent and continue. Where the closed-form conditions cannot express a rule, a CEL expression can — against a closed set of request, context, and budget fields that does not include the message text.

How do platform and tenant policies combine?

Both apply to a tenant’s traffic, and a deny from either stops the call — so a tenant cannot widen what the platform narrowed. Within evaluation, rules run in priority order and the first matching deny returns immediately; warnings collect and evaluation continues. A request matching no rule is allowed.

What happens when policies conflict?

At promotion, the candidate is checked against every active policy across the nine condition types and overlaps come back as warnings — the policy still activates, so the warnings are for you to read rather than a gate. For CEL rules the check is skipped entirely, because deciding whether two arbitrary expressions conflict is not generally possible; you get one "verify manually" warning per CEL rule instead.

What is the difference between dry-run and shadow mode?

Dry-run walks a single synthetic request you describe through a draft and returns the decision, the matching rule, and the evaluation time. It is stateless, calls no model, and proves the rule fires — not how much traffic it would touch. Shadow evaluates on real production traffic without blocking anything, and records each divergence with the decision it would have made. Dry-run answers "is this rule right"; shadow answers "what would this rule have done".

How are policies promoted and rolled back?

Promotion is a confirmed action that runs conflict detection, flips the status to active, and clears that policy’s shadow data. To reverse it, set the status back to shadow or draft, which stops enforcement, or restore an earlier version from the version list — every save creates a version and the last ten are kept. Restoring creates a new version carrying the old configuration rather than rewinding history.

How quickly does a change take effect?

On the next data-plane request, picked up by a configuration poll rather than a restart or a deploy. That is seconds rather than instant, which matters when you change a rule and immediately send a test request through.

Who can author or activate a policy?

Platform-wide policies are managed by whoever operates the gateway, from the console. A tenant authors and promotes its own policies from the portal, cannot see or edit another customer’s, cannot edit the operator’s platform policies, and cannot stamp a different tenant’s ID on a policy it creates. Every create, update, and status change is recorded.

Which edition includes which capability?

Without a licence key, what you get is a static model allow/deny list set by the operator — which models may be called, and nothing else. The policy language and everything around it is licensed: the nine conditions, CEL rules, per-tenant scoping, dry-run, shadow mode, conflict detection, versioning, and rollback.

Write one rule, and watch it before you enforce it.

Shadow is the step worth taking first: the policy evaluates on real traffic, blocks nothing, and tells you how often it would have. Promote once that number says what you expected.

Last updated