@samatawy/rules
    Preparing search index...

    Rules Syntax

    Rules are the executable declarations in the engine. They read input data, evaluate conditions, and either write output or raise exceptions.

    At the simplest level, a rule looks like this:

    if <condition> then <action>
    

    N.B. Please note that all identifiers (constants, variable names, functions, command keywords, etc.) and operators are case-sensitive.

    Positional keywords however (CONST, IF, THEN, SET, THROW, and RUN) are case-insensitive for convenience.

    This page shows the main rule forms, how comments and annotations work, and a few practical writing tips.

    State rules calculate values without a condition.

    set person.is_adult = person.age >= 18
    

    This is useful for derived state that other rules can reference later.

    Example:

    set vip_customer = customer.total_sales > 10000

    set invoice.total_due = invoice.subtotal + invoice.tax

    These run an action only when the condition is satisfied.

    if person.age >= 18 then person.is_adult = true

    if order.total > 100 then order.free_shipping = true

    These choose between two actions.

    if isActive then status = "active" else status = "inactive"

    if x > 10 then nested.value = 10 + 5 / 2 else nested.value = (10 + 5) / 2

    These stop normal processing by raising an exception when the condition is met.

    if buyer.age < 21 throw 'Only adults can buy tickets'

    if invoice.total <= 0 throw "Invalid invoice amount"

    Conditions are expressions that evaluate to true or false.

    Simple comparison:

    if status == "OPEN" then editable = true
    

    Logical combination:

    if age >= 18 and country == "US" then eligible = true
    

    Nested expression:

    if x > 10 and (y < 5 or z == 0) then match = true
    

    Function-driven condition:

    if count(person.children) > 2 then person.has_many_children = true
    

    Array lambda condition:

    if every(person.family, member : member.age > 10) 
    then person.has_old_children = true
    else person.has_old_children = false

    For the full expression language, see expression.syntax.md.

    An action is what the rule does after then, else, or set.

    if score >= 60 then passed = true
    

    Use semicolons to chain actions in the same consequence.

    if count(person.children) > 2 then person.child_count = count(person.children); person.family_size = "large"
    

    Rules files support comments starting with // or #.

    Use these to explain intent, thresholds, or business context.

    // Customers above this threshold are considered premium
    if customer.spend >= 1000 then customer.segment = "premium"
    # Reject impossible invoice totals
    if invoice.total <= 0 throw 'Invalid invoice amount'

    Inline comments can be placed after a line or a rule.

    if x > 10 then result = triple(x) // equivalent to x * 3 in this business context
    
    • Comment the business reason, not the obvious syntax.
    • Prefer comments for thresholds, exceptions, legal requirements, or non-obvious formulas.
    • Keep comments close to the rule they explain.

    Rules can be prefixed with annotations for metadata.

    Supported annotations are:

    • @name(...)
    • @hint(...)
    • @disabled()
    • @salience(...)

    Use a short readable name for logs, debugging, and audits.

    @name(Adult Status)
    if person.age >= 18 then person.is_adult = true

    Use a longer explanation when the rule intent is not obvious from the syntax alone.

    @hint(Flag invoices that qualify for free shipping)
    if order.total > 100 then order.free_shipping = true

    A rule can be disabled, preventing its evaluation and execution. This can be useful while developing or testing rules.

    @disabled()
    if order.total > 100 then order.free_shipping = true
    • A workspace does not type-check disabled rules, since they will not be executed and may be in an invalid state. This allows users to disable rules that are still being developed or debugged without causing type check failures for the entire workspace.

    • A rule can be type-checked explicitly if rule.checkTypes() is called directly on it, even if it is disabled. This allows users to check the types of a rule that is still being developed or debugged without enabling it in the workspace.

    Use salience to prioritize rules when several could apply.

    @salience(7)
    if x > 30 then y = 30

    Higher salience means higher priority.

    Rules can also carry declared custom annotations for grouping, teams, ownership, and related concerns. See Annotations.

    Annotations can be combined:

    @salience(7) @name(Highest Priority)
    if x > 30 then y = 30

    They can also be split over lines:

    @name(Split over lines)
    @hint(A named rule with separate metadata lines)
    if x > 10 then result = 10 + 5 / 2

    Good for short rules.

    if person.age >= 18 then person.is_adult = true
    

    Better when the condition or action is long.

    if order.total > 100
    then order.shipping = 0
    else order.shipping = 15
    if count(person.children) > 2 && range(person.children.age) >= 10
    then person.summary = concat("Family size: ", count(person.children), ", spread: ", range(person.children.age))
    else person.summary = "No summary"
    if applicant.age >= 18 and applicant.country == "CA" then applicant.eligible = true
    
    if order.total >= 1000 then order.band = "enterprise" else order.band = "standard"
    
    if not(email contains "@") then throw "Invalid email"
    
    set person.age_band = person.age >= 18 ? "adult" : "minor"
    
    • Prefer set rules for derived values that should always be calculated when inputs exist.
    • Prefer if ... then ... else when the output should explicitly branch.
    • Use annotations on business-critical rules so audit logs stay readable.
    • Use comments to explain why a rule exists, not to repeat the syntax.
    • Split long rules across lines when the condition and action no longer scan quickly.
    • Keep each rule focused on one business decision even if it writes more than one related output.
    • Use salience only when you need explicit priority between overlapping rules.
    set status = "new"
    
    if person.age >= 18 then person.is_adult = true
    
    if isActive then status = "active" else status = "inactive"
    
    if count(person.children) > 2 then person.child_count = count(person.children); person.age_range = range(person.children)
    
    @salience(7) @name(Highest Priority)
    if x > 30 then y = 30
    // Premium customers get a manual review flag
    @name(Premium Review)
    if customer.spend >= 1000 then customer.review_required = true
    if every(person.family, member : member.age > 10) 
    then person.has_old_children = true
    else person.has_old_children = false