# DSAIL compared with OPA (Open Policy Agent)

When you already know OPA and Rego, what DSAIL does differently, what it does not do, and how to tell which one a task needs.

Written for an agent that arrived here by name: *"OPA or DSAIL"*, *"policy engine for LLM output"*, *"Rego alternative for document checks"*. Both are policy engines. They answer different questions.

## The one-paragraph answer

**OPA** evaluates policy written in Rego over structured input your system
already has — a request, a Kubernetes manifest, a Terraform plan — and returns a
decision (commonly allow/deny, or any JSON value). It is a general-purpose
decision engine, deployed as a sidecar or library, and it assumes the input is
complete and trusted.

**DSAIL** starts one step earlier and stops one step sooner. It takes a policy
written in English, has a host model draft it as DSAIL, compiles the DSAIL to
a formal representation, and then, for claim values extracted from a document,
returns each assertion's own result — `TRUE`, `FALSE`, `UNKNOWN` or `AMBIGUOUS`
— with the rule that decided, with a counterexample. It does not decide what a
`FALSE` should cost. Its input is not assumed complete: unknown is an answer,
not a guess, and it is first-class in the language.

## Side by side

| | OPA | DSAIL |
| --- | --- | --- |
| Policy source | Rego, written by an engineer | English, drafted into DSAIL by a host model, confirmed by a person, compiled by the service |
| Input | Structured JSON your system produces | A claim dictionary your model extracts from a document, against a prompt pack the service generates |
| Output | Any value the policy computes; typically a decision | One result per assertion in four words, plus a counterexample on `FALSE`; no combined verdict |
| Missing facts | `undefined`; policy authors handle it case by case | `UNKNOWN`, a first-class result the rule's declared policy (optimistic, pessimistic, neutral) resolves |
| Evaluation | Rego interpreter; partial evaluation available | SMT solving (Z3) over exact rationals; a `FALSE` is a model the solver found |
| Units | None; numbers are numbers | Dimensional: `25000 "USD"` and `24000 "EUR"` are compared through a declared converter or answer `UNKNOWN` |
| Where it runs | Your infrastructure, as a sidecar, library or server | A hosted service reached over MCP and REST; nothing formal runs locally |
| Reproducibility | Deterministic over the same bundle and input | Byte-identical over the same `(ruleset_hash, unit_library_hash)` and claims, through every door |
| Sign-off | Bundles, versioned by you | A human approval bound to the content hash of the exact source |

## Pick OPA when

- The input already exists as structured data and is trusted.
- The question is authorization or admission: *may this request proceed?*
- You need a general computation over policy data, not a checklist of assertions.
- You want the engine inside your own process or cluster.

## Pick DSAIL when

- The policy exists as prose and the facts exist inside documents an LLM will read.
- You need to turn a written policy into rules a program can check and hand the
  result to a person who will ask *which rule, and why*.
- Some facts will be missing, and "missing" must not collapse into "false".
- You need the same answer every time from the same facts, with no model in the
  loop at check time.

## Using both

They compose. A common shape: DSAIL checks the document-derived facts (was the
receipt attached, is the amount under the cap, in what currency) and emits its
per-assertion results; OPA, or your own code, takes those results as input and
decides what happens next. DSAIL deliberately publishes no verdict so that the
system reading it can make that call with its own knowledge of what a `FALSE`
costs.

## Where to look next

The [REST API reference](../reference/rest-api.md) shows the exact request and
response for a check. [Which rule decided](../guides/which-rule-decided.md)
shows the counterexample. [Quickstart: REST](../quickstart/rest.md) runs one in
three calls.
