Language Reference

Everything you need to write deterministic business rules. No prior DSL experience required.

Contents

  1. Overview
  2. Rule Structure
  3. Expressions & Operators
  4. Decision Types
  5. Data Types
  6. Assignments & Computed Values
  7. Lists & Pattern Matching
  8. Time & Velocity Limits
  9. Missing Values
  10. Determinism Guarantees
  11. Complete Examples
  12. Quick Reference

Overview

RuleDSL is a purpose-built language for writing business decision rules. It compiles to bytecode that evaluates deterministically: same input, same bytecode, same decision — every time, on every platform.

A rule file contains one or more named rules. Each rule has a condition (when) and an action (then). Rules are evaluated in priority order. The first rule whose condition matches produces the decision.

Design philosophy: The engine decides. The host application computes. RuleDSL deliberately excludes aggregation, date arithmetic, and string manipulation. These belong in your application. The engine evaluates the fields you provide and returns a decision.

Rule Structure

Every rule follows this pattern:

rule rule_name priority 100 {
  when <condition>;
  then <actions>;
}

Components

PartRequiredDescription
ruleYesKeyword. Starts a rule block.
rule_nameYesIdentifier. Appears in decision results.
priority NNoHigher number = evaluated first. Default is 0.
whenYesCondition expression. Must resolve to true/false.
thenYesOne or more actions, separated by commas.

Evaluation Order

Rules are evaluated by priority (highest first). Among rules with equal priority, source order applies. The first match wins — no further rules are evaluated after a decision is reached.

Expressions & Operators

Comparison Operators

OperatorMeaningExample
==Equalcurrency == "USD"
!=Not equalstatus != "blocked"
<Less thanamount < 100
<=Less than or equalamount <= 500
>Greater thanamount > 1000
>=Greater than or equalrisk_score >= 80

Logical Operators

OperatorMeaningExample
andBoth must be trueamount > 1000 and currency == "USD"
orEither can be truecountry == "US" or country == "GB"
notNegationnot is_verified

Use parentheses to control evaluation order: (a or b) and c

Arithmetic Operators

OperatorMeaningExample
+Additionamount + fee
-Subtractionbalance - amount
*Multiplicationrate * 100
/Divisionamount / 100

Standard precedence: * and / bind tighter than + and -. Use parentheses when in doubt.

Operator Precedence (Highest to Lowest)

LevelOperatorsAssociativity
1not, unary -Right
2* /Left
3+ -Left
4< <= > >=Left
5== !=Left
6andLeft
7orLeft

Decision Types

allow

Approve the request. Transaction proceeds.

decline

Reject the request. Transaction is blocked.

review

Flag for manual review. Requires human decision.

limit

Apply a velocity cap. E.g., max 200 USD per day.

# Simple decisions
then allow;
then decline;
then review;

# Velocity limit (requires now_utc_ms in input)
then limit 200 USD per 1 D;

Data Types

TypeLiteral ExampleDescription
Number1200.0, 1e6, 100 USDIEEE 754 binary64. Integer, decimal, and exponent forms. Optional currency tag.
String"USD", "hello"Double-quoted. Used in comparisons and MATCH.
Booleantrue, falseUsed in conditions directly.
Identifieramount, customer.levelReferences input fields. Dotted paths supported.
MissingField not provided. Operations on missing safely fail.

Numeric Literals

Numbers support integer, decimal, and scientific notation:

when amount > 10000;        # integer
when rate > 0.05;           # decimal
when amount > 1e6;          # scientific notation (1,000,000)
when rate > 2.5e-3;         # decimal + exponent (0.0025)

Currency-Tagged Numbers

Append a 3-letter currency code to a numeric literal for currency-aware comparisons:

when amount >= 1e4 USD;     # 10,000 USD
when amount >= 8000 EUR;    # 8,000 EUR

Dotted Paths

Access nested fields with dot notation:

when customer.risk_level > 70 and merchant.category == "gambling";

Assignments & Computed Values

The then clause can set output fields alongside the decision. These appear in the result and can be used by downstream systems.

rule fraud_signal priority 100 {
  when amount > 3000 and ip_country in [NG, RU];
  then risk_score = 95,
       reason = "multi_signal_fraud",
       category = "high_risk",
       decline;
}

Assignments support arithmetic expressions:

then risk_score = (amount / 100) + velocity_1h, review;

Lists & Pattern Matching

IN Lists

Check if a value is a member of a list:

when ip_country in [TR, NG, RU, KP];
when channel in [ECOM, APP, WEB];

List items can be identifiers (bare words) or strings.

MATCH (Substring Matching)

Check if a text field contains a substring:

when email match "@example.com";
when card_bin match "41111";
Safety: Applying MATCH to a non-text field (e.g., a number) raises a runtime error (MATCH_EXPECTS_TEXT). Always ensure the matched field is a string.

Time & Velocity Limits

The limit decision enforces velocity caps over time windows:

then limit 500 USD per 1 D;    # max 500 USD per day
then limit 3 TRY per 1 H;      # max 3 transactions per hour

Time Units

CodeUnit
SSecond
MMinute
HHour
DDay
Determinism: The engine never reads the system clock. Time must be provided as now_utc_ms in the input context. The Python and C# bindings auto-inject this; the C API requires explicit injection.

Missing Values

If a referenced field is not provided in the input, it resolves to missing.

This means you do not need defensive null checks. If a field might not exist, the rule safely skips:

# If customer.loyalty_tier is not in the input, this rule is skipped
rule vip_bypass {
  when customer.loyalty_tier == "platinum";
  then allow;
}

Determinism Guarantees

RuleDSL is deterministic by contract. These are not aspirational goals — they are enforced by the engine architecture:

No implicit time

The engine never reads the system clock. Time is explicitly injected via now_utc_ms.

Stable evaluation order

Rules are evaluated by priority, then source order. No randomness, no hash-map iteration artifacts.

IEEE 754 numeric behavior

All arithmetic uses binary64. No fast-math. No platform-dependent rounding. NaN and Inf are rejected.

No locale dependency

Identifiers use raw UTF-8 octet matching. No Unicode normalization. No collation surprises.

The result: same bytecode + same input + same engine version = same decision. Always. On every platform.

Complete Examples

Transaction Risk Scoring

rule block_sanctioned priority 200 {
  when ip_country in [KP, IR, SY];
  then reason = "sanctioned", decline;
}

rule high_risk_geo priority 100 {
  when amount > 5000 and ip_country in [NG, RU];
  then risk_score = 90, reason = "geo_high", decline;
}

rule review_medium priority 50 {
  when amount > 1000 and amount <= 5000;
  then risk_score = 60, reason = "medium_amount", review;
}

rule allow_default {
  when true;
  then risk_score = 10, reason = "baseline", allow;
}

Spending Limits with Device Trust

rule block_new_device_high priority 100 {
  when is_new_device and amount > 2000;
  then reason = "new_device_risk", decline;
}

rule limit_daily priority 50 {
  when amount > 1000;
  then reason = "daily_cap", limit 500 USD per 1 D;
}

rule trusted_device priority 10 {
  when card_present and not is_new_device;
  then reason = "trusted", allow;
}

rule default_review {
  when true;
  then review;
}

Email & Channel Controls

rule flag_internal_email priority 100 {
  when email match "@internal\\.corp$";
  then reason = "internal_email", review;
}

rule block_risky_channel priority 50 {
  when channel in [ECOM, APP] and amount > 1000;
  then reason = "risky_channel", decline;
}

rule allow_other {
  when true;
  then allow;
}

Quick Reference

Keywords

KeywordContext
ruleStarts a rule block
prioritySets evaluation order (optional)
whenBegins condition expression
thenBegins action clause
and or notLogical operators
inList membership check
matchPattern match on text fields
allow decline reviewDecision outcomes
limit perVelocity limit decision
true falseBoolean literals

Keywords are case-insensitive: WHEN, When, and when are equivalent.

Reserved Input Field

FieldTypeRequired For
now_utc_msNumber (epoch milliseconds)limit ... per rules

Further Reading