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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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
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
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
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
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
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.
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 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.
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.
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.
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.
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.
Which planes does this policy language reach?
Two of the three, and the third is genuinely a different engine rather than the same one applied elsewhere. Worth knowing before you write a rule and assume it covers everything your agents do.
The DSL on this page governs them: model, tokens, residency, time, budget.
The same DSL reaches them, through the MCP server, tool, and argument conditions. One policy language covers both planes.
Agent-to-agent hops are governed by a separate policy engine with its own rules, its own store, and different semantics — it matches source, target, and skill, its effects are allow and deny, and it is first-match-wins. A rule written here does not govern a hop there.
Authoring, dry-run, the shadow dashboard, promotion, and version history are control-plane functions. The data planes read the active policy and enforce 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.


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.
| Capability | DVARA | Kong AI | TrueFoundry | AWS Bedrock |
|---|---|---|---|---|
| Policy-as-Code engine (YAML DSL) | ✓ | ∼ | ∼ | — |
| Policy dry-run before activation | ✓ | — | — | — |
| Policy versioning + rollback | ✓ | ∼ | — | — |
| RBAC access control | ✓ | ✓ | ✓ | ✓ |
| SSO (OIDC / SAML) | ✓ | ✓ | ✓ | ✓ |
| Pricing model | Licensed, sized by request volume — no hard stop on overage | See their pricing | Free 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.
A static model allow/deny list, set by whoever operates the gateway. It answers "which models may be called" and nothing else.
The policy language itself and everything around it: the nine conditions, CEL rules, per-tenant scoping, dry-run, shadow mode with divergence, conflict detection, versioning, and rollback.
The MCP and A2A Gateways are licensed and have no keyless tier at all, so policy on tool calls and agent hops arrives with those planes rather than with the free gateway.
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.
Guides on Policy-as-Code for LLMs
A practical definition, its lineage from Terraform and OPA to Kubernetes CEL, and why AI teams need it now — the concept, start here.
What it means, why governance in app code can’t be reviewed or rolled back, and the YAML + CEL rule model — with the dry-run → shadow → promote lifecycle.
The content half of governance — injection, PII, content, and output checks that scan every request and response, versioned and tuned per tenant instead of hard-coded in prompts.
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.