Language Reference
The policy engine uses a small domain-specific language for writing policy templates. This reference defines the template structure, schemas, type system, expression syntax, runtime input model, and evaluation rules.
What a template contains
A policy template has four parts:
name <identifier>- An optional
intent { ... }block - A required non-empty
evidence { ... }block - A required non-empty
requires { ... }block
Their semantics are:
nameis a human-readable template identifier and is part of the compiled template.intentdeclares the schema for user-supplied policy inputs.evidencedeclares the schema for runtime facts evaluated against the policy.requiresdeclares the boolean constraints evaluated againstintentandevidence.
A schema is the set of field declarations in an intent or evidence block.
A policy evaluation succeeds only if the runtime inputs match the declared
schemas and every constraint in requires is satisfied.
Example:
name clothing_purchase_guard
intent {
acceptable_categories: set<string>
acceptable_colors: optional set<string>
acceptable_brands: optional set<string>
size: string
audience: string
max_price_cents: int
}
evidence {
category: string
color: string
brand: string
size: string
audience: string
price_cents: int
}
requires {
evidence.category in intent.acceptable_categories;
evidence.size == intent.size;
evidence.audience in {"men", "women", "unisex"};
evidence.audience == intent.audience;
evidence.price_cents <= intent.max_price_cents;
optional: evidence.color in intent.acceptable_colors;
optional: evidence.brand in intent.acceptable_brands;
}
Template structure rules:
intentmay be omitted when the template does not need caller-supplied inputs.intent {}is valid.evidencemust be present and must declare at least one field.requiresmust be present and must contain at least one constraint.- each schema field name must be unique within its block.
- top-level blocks may not be repeated.
Features not supported
This version of the language does not support:
- nested input objects
- arrays as first-class language values
- range types
- division
- lexicographic string ordering
- floating-point numbers
- functions
- user-defined types
- loops or recursion
- implicit type coercions
- date arithmetic
- timestamps
- complex conditional schemas
Identifiers and field references
Identifiers are ASCII names matching this shape:
[A-Za-z_][A-Za-z0-9_]*
Reserved words
Reserved words cannot be used as the template name or as field names in
intent or evidence schemas.
The reserved words are:
name
intent
evidence
requires
optional
bool
int
string
date
set
True
False
not
and
or
in
subset
superset
of
Field references are always namespace-qualified:
intent.max_price_cents
evidence.price_cents
The language has exactly two namespaces:
intentevidence
Types
Supported types:
boolintstringdateset<int>set<string>set<date>
Important rules:
intis a signed 64-bit integerstringvalues are UTF-8 stringsdateis a valid calendar date with a four-digit year, no time of day, and no timezone- sets are homogeneous
- only
intentfields may be markedoptional
Example schema declarations:
intent {
approved_brands: optional set<string>
latest_delivery: date
}
evidence {
refurbished: bool
warranty_months: int
}
Literals
Literal forms:
True
False
0
18
-5
"CH"
date(2026-01-01)
{1, 2, 3}
{"CH", "DE", "FR"}
{date(2026-01-01), date(2026-06-01)}
String literals use double quotes. Recognized escapes are:
\\\"\n\r\t
Additional literal rules:
- set literals must contain elements of one type only
- duplicate elements in a template source set literal are rejected
{}is allowed only when its set type can be inferred from context
Dates use date(YYYY-MM-DD) in template source. The year must be four digits
from 0000 through 9999, and the month/day combination must be a valid
calendar date.
Expressions
Arithmetic
Arithmetic works only on integers.
Supported arithmetic operators:
+-*
Integer overflow and underflow are runtime evaluation errors.
Equality and ordering
Equality is allowed when both sides have the same type:
evidence.size == intent.size
evidence.audience == intent.audience
Ordering is allowed only on:
intdate
Examples:
evidence.price_cents <= intent.max_price_cents
evidence.delivery_date <= intent.latest_delivery
Membership and set relations
Supported set operations:
int in set<int>string in set<string>date in set<date>int not in set<int>string not in set<string>date not in set<date>set<int> subset of set<int>set<string> subset of set<string>set<date> subset of set<date>set<int> superset of set<int>set<string> superset of set<string>set<date> superset of set<date>
Examples:
evidence.category in intent.acceptable_categories
optional: evidence.brand in intent.approved_brands
evidence.skus superset of intent.premium_skus
Boolean logic
Supported boolean operators:
notandor
A boolean-valued field or expression may appear directly in a constraint:
requires {
not evidence.refurbished;
}
The language rejects mixed unparenthesized and and or chains.
Allowed:
a and b and c
a or b or c
a and (b or c)
(a and b) or c
Rejected:
a and b or c
a or b and c
Chained comparisons
The language supports chained comparison expressions:
8 <= evidence.memory_gb <= 32
intent.earliest_ship <= evidence.ship_date <= intent.latest_ship
Rules:
- only
==,<,<=,>,>=participate in chained comparisons inandnot inare not part of chained-comparison syntax- direction reversals such as
a < b >= care rejected
Precedence
From tightest to loosest:
- parentheses, literals, and field references
*+and-- unary
not - comparisons, equality, membership, and set relations
- homogeneous chains of
andor homogeneous chains ofor
Because unary not binds more tightly than comparisons, not a == b parses
as (not a) == b.
Optional constraints
Optional intent fields are part of the type system and the runtime behavior.
Example:
intent {
approved_brands: optional set<string>
}
requires {
optional: evidence.brand in intent.approved_brands;
}
Rules:
- an optional intent field may be absent at runtime
- if a constraint references an optional intent field, that constraint must use
optional: - an
optional:constraint must reference at least one optional intent field - if any referenced optional intent field is absent at runtime, the constraint is treated as satisfied without evaluating its expression
- if all referenced optional fields are present, the expression is evaluated normally
Runtime input model
Templates are evaluated against two runtime inputs:
intentevidence
Each input is a map of field names to typed values. The field names and value types must match the corresponding schema declared by the template.
When using the CLI, these input maps are encoded as JSON files. The JSON encoding rules are covered in CLI Reference.
Runtime input rules:
- missing required fields are rejected
- extra fields are rejected
- optional intent fields may be omitted
- if an optional field is present, it must still match the declared type
- duplicate elements in set input values are ignored
- dates must follow the same valid-calendar-date rule as template date literals
Evaluation model
Before constraint evaluation begins, the engine validates the runtime inputs against the declared schemas.
After validation succeeds:
- constraints are evaluated in source order
- every constraint is evaluated, even if earlier constraints fail
- each constraint produces one of: pass, fail, or runtime error
- a policy passes only if every constraint is satisfied
Runtime errors can still occur after successful input validation. Examples include arithmetic overflow and underflow.
Compiled form
Bytecode generation is deterministic: compiling a template always produces the same bytecode and the same template ID.
Whitespace, comments, schema field order, and set literal element order do not define the policy. The template name, declared fields, constraints, and literal values do.
When you run policy-engine print, you see a readable representation of the
compiled template. It may differ from the original source in formatting or
ordering, but it describes the compiled policy that will actually be evaluated.
Practical consequences:
- comments are not preserved
- equivalent source forms may be printed in a normalized way, e.g.:
- schema fields may appear in a normalized order,
- set literals may appear in a normalized order,
- source
a not in bmay be printed as the equivalentnot (a in b)form.
Formatting rules
#starts a line comment and runs to the end of the line- comments may appear on their own line or after code
- newlines separate top-level items and schema field declarations
- constraints inside
requires { ... }are separated by; - newlines do not separate constraints
#inside a string literal is not a comment
Compile-time and runtime failures
Templates can fail at different stages:
- compile-time syntax errors, such as malformed structure or invalid literals
- compile-time type errors, such as mismatched comparisons or invalid boolean operands
- input validation errors, such as missing required fields or wrong input types
- runtime evaluation errors, such as arithmetic overflow
For CLI usage details and output formats, see CLI Reference.