Docs/Magistrate/Policy Language (OPL)/OPL Overview

OPL Overview

OPL, the Octet Policy Language, is how a Magistrate policy is written down. The studio writes it for you, and shows it in its code pane. Read this page to review a policy before you sign it off, or to understand a decision afterwards.

This documentation covers the part of OPL that the Magistrate studio and the Octet policy engine support today. What's Next lists what comes later.

A policy

policy p_3b41af1558a1448b8845fa2821871b5d {
  combine deny_overrides
  rule deny when outside(country("AT")) reason "E-304"
  default permit
  freshness 5m
}

In words: a device outside Austria gets deny. Every other device gets permit. If the proofs can't settle where the device is, the answer is deny. Proofs older than 5 minutes don't count.

Policy structure

A policy is a name and a body in braces. The body is a list of clauses, in any order.

Clause Required Description
policy <name> Yes The policy's name. Policies from the studio are named p_ followed by a UUID. The studio shows a separate, human title
rule Yes, one or more An effect, permit or deny, and the condition under which it applies. See Policy clauses
combine No How the rules combine into one decision. These docs cover only deny_overrides, the default
default No The decision when no rule applies, permit or deny. Without it, no matching rule means deny
on_indeterminate No The decision when the proofs can't settle a rule. Defaults to deny, and these docs cover only deny. The studio doesn't write this clause
freshness No How old a proof may be and still count, for example 5m. Without it, 300 seconds
requires No A minimum precision for the proofs, for example requires proof_level >= country

How a policy is decided

The engine verifies the device's proofs, then evaluates the rules:

%%{init: {"flowchart": {"nodeSpacing": 30, "rankSpacing": 40}}}%%
flowchart LR
    Q(Are the proofs precise<br/>enough for the policy?) -- yes --> D(Does a deny<br/>rule apply?)
    D -- no --> P(Does a permit<br/>rule apply?)
    P -- no --> DEF[the default<br/>answer]
    D -- yes --> DENY[deny]
    P -- yes --> PERMIT[permit]
    Q -- no --> U[UNKNOWN: the<br/>on_indeterminate answer]
    D -- can't tell --> U
    P -- can't tell --> U
  1. The proofs must be precise enough. If the policy has a requires clause and the proofs don't meet it, the policy can't be decided and gets its on_indeterminate answer, with cause other. A proof older than freshness doesn't stop the decision. It only leaves the regions it would have settled unknown, so a deny rule that other proofs settle still wins.
  2. Deny wins. If any deny rule applies, the decision is deny.
  3. A rule that can't be settled stops the decision. If a deny rule might apply but the proofs can't tell, the decision is the on_indeterminate answer. For example, a device that proves only that it is in Ukraine can't settle a rule about Crimea.
  4. Then permit. If a permit rule applies, the decision is permit.
  5. Then the default. If no rule applies, the decision is default, or deny without one.

The engine returns only permit or deny. When the answer came from on_indeterminate, the decision also carries a cause saying why the location couldn't be settled. See Decision Response.

Defaults to know

  • No proof is not a pass. A device with no current proof can't satisfy a rule, so the policy gives its on_indeterminate answer. Every policy the studio writes uses deny.
  • Countries follow ISO 3166 strictly. country("US") doesn't include Puerto Rico or the other territories, which have their own codes. List them if you mean them.
  • No matching rule and no default is deny.
  • A policy decides one question. To check several at once, use decideMany in the Magistrate module.

Next

  • Language: every keyword, region and type.
  • Examples: complete policies to copy.
TermsPrivacy© 2026 Understone, Inc. d/b/a Octet