Rule DSL

Write BlazeRules rule files in YAML: schema, fields, lookups, decisions, and the condition tree.

A BlazeRules rule file is a single YAML document. The engine compiles it once into an immutable execution plan and then reuses that plan for every batch. This page walks the file top to bottom so you know exactly which keys go where.

A complete file at a glance

A rule file has a small set of top-level keys. Most are optional — the only thing you always need is a ruleset.

KeyRequiredPurpose
schema_versionYesYAML format version. Use "2.1".
fieldsOptionalType hints for input fields. Omit them and BlazeRules infers types from the first batch.
lookupsOptionalNamed CSV sets used by in_lookup / not_in_lookup. See Lookups.
decisionsOptionalDefault action and precedence ladder. See Decisions & Scoring.
rulesetYesThe rules themselves: name, version, and a list of rules.
📘

The agent has one extra key

A top-level instances: block configures the multi-instance ingest agent (blazerules_agent). It is not part of rule evaluation. See Production YAML Guide for a complete multi-instance file and CLI & Agent for agent runtime behavior.

Minimal example

The smallest useful file declares a version, an optional field hint, and one rule:

schema_version: "2.1"

fields:
  amount: {type: float32, nullable: false}

ruleset:
  name: My Ruleset
  version: "1.0.0"
  rules:
    - id: high_amount_emulator
      action: review
      severity: HIGH
      weight: 25
      conditions:
        and:
          - {field: amount, op: gt, value: 1000}
          - {field: device_type, op: eq, value: emulator}

Fields are optional hints

The fields: block declares the type — and optionally the nullability and allowed values — of each input field. You do not have to provide it. When you omit a field, BlazeRules infers its type from the first evaluated batch (see schema inference in Core Concepts).

📘

Why give hints at all?

Hints make types explicit and stable across batches, catch typos in field names early, and let you pin a categorical field to a known set of values. Inference is convenient for prototyping; hints are better for production.

Field type hints use these column types:

float32 · float64 · int32 · int64 · categorical · entity_key · timestamp_ms · boolean · string

A few real declarations from the canonical sample file:

fields:
  event_id: {type: string, nullable: false}
  card_token: {type: entity_key, nullable: false}
  amount: {type: float32, nullable: false}
  account_age_days: {type: int32}
  country_code:
    type: categorical
    values: [US, GB, IN, DE, BR, CN, RU]
  device_type:
    type: categorical
    values: [ios, android, web, emulator]
  merchant_bin: {type: int64}
  ip_address: {type: string}
  event_ts_ms: {type: timestamp_ms}
  optional_note: {type: string, nullable: true}

The entity_key type marks the field used to group an entity's history for Windows (here, card_token).

Per-rule fields

Each entry in ruleset.rules is one rule. The fields you will use most:

FieldPurpose
idUnique identifier for the rule. Appears in winning_rule_ids on the result.
actionOne of approve, flag, review, block, score.
severityOne of LOW, MEDIUM, HIGH, CRITICAL.
weightInteger added to the record's score when the rule matches.
conditionsThe condition tree (below).

A rule also supports priority, reason_code, and shadow. Those drive how a verdict is chosen and how you roll rules out safely — see Decisions & Scoring for full treatment.

The condition tree

conditions is a tree. A leaf is a single test on one field; branches combine leaves with boolean logic.

A leaf usually looks like {field, op, value} or {field, op, values}:

- {field: amount, op: gt, value: 1000}
- {field: country_code, op: in, values: [US, GB]}

Some operators take extra keys instead of value — for example cross-field operators use other_field:, bitfield operators use mask:, lookups use lookup:, and geo operators use lat_field / lon_field / other_lat_field / other_lon_field. The full list lives in the Operator Reference.

Branches nest with and, or, and not:

conditions:
  and:
    - {field: amount, op: gt, value: 1000}
    - or:
        - {field: country_code, op: not_in, values: [US, GB]}
        - {field: device_type, op: eq, value: emulator}

SQL and expression forms

Two forms let you express richer logic inside a leaf.

A sql: leaf accepts a SQL-style boolean expression, including any_match(...) over arrays of objects:

- sql: "amount > 100 AND account_age_days >= 0"
- sql: "any_match(items, x -> x.price > 100 AND x.category = 'electronics')"

An expr: leaf computes arithmetic (add, sub, mul, div) and then compares the result with an op / value:

- op: gt
  expr:
    op: div
    left: amount
    right: available_credit
  value: 0.8

Derived forms build on these ideas: ML Scoring for model_score, Vector Similarity for vector_distance, and Windows for velocity aggregates.

Nested YAML vs SQL for the same logic

The condition tree and a sql: leaf can express the same predicate. Here is amount > 1000 AND country_code in [US, GB] written both ways:

   conditions:
     and:
       - {field: amount, op: gt, value: 1000}
       - {field: country_code, op: in, values: [US, GB]}

Where to go next