Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Basit-Ali0/Yggdrasil/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Yggdrasil supports 12 core operators for building rule conditions. Each operator handles type coercion automatically for CSV string values.

Supported Operators

OperatorAliasesDescriptionExample
>=greater_than_or_equal, gteGreater than or equalamount >= 10000
>greater_than, gtGreater thanamount > 5000
<=less_than_or_equal, lteLess than or equalamount <= 1000
<less_than, ltLess thanamount < 10000
==equals, eq, equalEquality (with type coercion)status == "approved"
!=not_equals, neq, ne, not_equalInequalitytype != "CASH_OUT"
INSet membershiptype IN ["DEBIT", "WIRE"]
BETWEENRange check [min, max]amount BETWEEN [8000, 10000]
existsField is present and non-emptyemail exists
not_existsField is missing or emptydpo_contact not_exists
containsincludesCase-insensitive substring matchdescription contains "crypto"
MATCHregexRegular expression testemail MATCH "^[a-z]+@"

Operator Normalization

The engine normalizes operator aliases from LLM extraction to standard forms:
// From in-memory-backend.ts:223-244
private normalizeOperator(op: string): string {
    const normalized = op.trim().toLowerCase();
    const map: Record<string, string> = {
        // Standard
        '>=': '>=', '>': '>', '<=': '<=', '<': '<',
        '==': '==', '!=': '!=', 'in': 'IN', 'between': 'BETWEEN',
        // Gemini aliases
        'equals': '==', 'equal': '==', 'eq': '==',
        'not_equals': '!=', 'not_equal': '!=', 'neq': '!=', 'ne': '!=',
        'greater_than': '>', 'gt': '>',
        'greater_than_or_equal': '>=', 'gte': '>=',
        'less_than': '<', 'lt': '<',
        'less_than_or_equal': '<=', 'lte': '<=',
        'exists': 'EXISTS', 'not_exists': 'NOT_EXISTS',
        'contains': 'CONTAINS', 'includes': 'CONTAINS',
        'match': 'MATCH', 'regex': 'MATCH',
    };
    return map[normalized] || op;
}

Numeric Comparisons

Operators: >=, >, <=, < Numeric comparisons use parseFloat() on both sides to handle CSV string values:
// From in-memory-backend.ts:182-189
case '>=':
    return parseFloat(leftValue) >= parseFloat(rightValue);
case '>':
    return parseFloat(leftValue) > parseFloat(rightValue);
case '<=':
    return parseFloat(leftValue) <= parseFloat(rightValue);
case '<':
    return parseFloat(leftValue) < parseFloat(rightValue);

Example

{
  "field": "amount",
  "operator": ">=",
  "value": 10000
}
Matches records where amount >= 10000.

Equality Operators

Operators: ==, != Equality uses type coercion to handle CSV string values:
// From in-memory-backend.ts:59-84
function coerceEquals(left: any, right: any): boolean {
    // Same type — direct comparison
    if (typeof left === typeof right) return left === right;

    // Rule value is boolean, CSV value is string
    if (typeof right === 'boolean' && typeof left === 'string') {
        return (left.toLowerCase() === 'true') === right;
    }

    // Rule value is number, CSV value is string
    if (typeof right === 'number' && typeof left === 'string') {
        return parseFloat(left) === right;
    }

    // Rule value is string, CSV value is number/boolean
    if (typeof left === 'boolean' && typeof right === 'string') {
        return left === (right.toLowerCase() === 'true');
    }
    if (typeof left === 'number' && typeof right === 'string') {
        return left === parseFloat(right);
    }

    // Fallback: loose equality
    return left == right;
}

Type Coercion Examples

CSV ValueRule ValueMatch?
"true"true
"false"false
"16"16
"10000"10000
"approved""approved"

Set Membership

Operator: IN Checks if a value exists in an array:
// From in-memory-backend.ts:198-199
case 'IN':
    return Array.isArray(rightValue) && rightValue.includes(leftValue);

Example

{
  "field": "transaction_type",
  "operator": "IN",
  "value": ["DEBIT", "WIRE", "TRANSFER"]
}
Matches records where transaction_type is one of the listed values.

Range Check

Operator: BETWEEN Checks if a value is within a range (inclusive):
// From in-memory-backend.ts:200-205
case 'BETWEEN':
    return (
        Array.isArray(rightValue) &&
        (leftValue as number) >= rightValue[0] &&
        (leftValue as number) <= rightValue[1]
    );

Example

{
  "field": "amount",
  "operator": "BETWEEN",
  "value": [8000, 10000]
}
Matches records where 8000 <= amount <= 10000.

Existence Operators

Operators: exists, not_exists These operators test for field presence/absence before checking for null:
// From in-memory-backend.ts:162-167
if (op === 'EXISTS') {
    return leftValue !== undefined && leftValue !== null && leftValue !== '';
}
if (op === 'NOT_EXISTS') {
    return leftValue === undefined || leftValue === null || leftValue === '';
}

Example: Required Field

{
  "field": "dpo_contact",
  "operator": "exists"
}
Matches records where dpo_contact is present and non-empty.

Example: Missing Field

{
  "field": "consent_withdrawn",
  "operator": "not_exists"
}
Matches records where consent_withdrawn is missing or empty.

String Matching

Contains

Operator: contains (alias: includes) Case-insensitive substring match:
// From in-memory-backend.ts:208-210
case 'CONTAINS':
    return typeof leftValue === 'string' && typeof rightValue === 'string' &&
        leftValue.toLowerCase().includes(rightValue.toLowerCase());
Example:
{
  "field": "description",
  "operator": "contains",
  "value": "crypto"
}
Matches “Cryptocurrency transaction”, “CRYPTO PURCHASE”, “crypto-related”.

Regex

Operator: MATCH (alias: regex) Regular expression test:
// From in-memory-backend.ts:211-215
case 'MATCH':
    if (typeof leftValue === 'string' && typeof rightValue === 'string') {
        return new RegExp(rightValue).test(leftValue);
    }
    return false;
Example: Email validation
{
  "field": "email",
  "operator": "MATCH",
  "value": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
}

Cross-Field Comparison

You can compare two fields using value_type: "field":
// From in-memory-backend.ts:174-178
if (cond.value_type === 'field' && typeof rightValue === 'string') {
    rightValue = record[rightValue];
    if (rightValue === undefined || rightValue === null) return false;
}

Example: Balance Mismatch

{
  "AND": [
    {
      "field": "newbalanceOrig",
      "operator": "!=",
      "value": "expectedBalance",
      "value_type": "field"
    }
  ]
}
This compares newbalanceOrig to the expectedBalance field in the same record.

Sanity Checks

The engine includes safety guards to prevent false positives:
// From in-memory-backend.ts:169-172
if (leftValue === undefined || leftValue === null) {
    return false;
}
If a field is missing or undefined, the condition does not match (except for exists/not_exists).

Compound Conditions

Operators can be combined with AND/OR logic:
{
  "AND": [
    { "field": "amount", "operator": ">=", "value": 8000 },
    { "field": "amount", "operator": "<", "value": 10000 },
    { "field": "type", "operator": "IN", "value": ["DEBIT", "WIRE"] }
  ]
}
See Architecture for details on condition evaluation.

Type Coercion Summary

CSV InputExpected TypeCoercion
"true"booleantrue
"false"booleanfalse
"123"number123
"10000.50"number10000.5
"approved"string"approved"

Error Handling

Unknown operators are logged and return false:
// From in-memory-backend.ts:217-219
default:
    console.warn(`[ENGINE] Unknown operator: '${cond.operator}' in rule condition for field '${cond.field}'`);
    return false;

Next Steps

Rule Types

Learn when to use WINDOWED vs SINGLE-TX

Architecture

Understand the execution flow