> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kayanos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Expression language syntax

> Write clear, testable KayanOS expressions with an exact guide to values, paths, operators, templates, transforms, and evaluation limits.

## Start with the execution context

An expression returns a value. The feature that evaluates it decides whether that value becomes a calculated field, a visibility decision, a validation result, form text, a serial number, or document output. The same spelling is not automatically valid everywhere: available root variables and context-specific functions differ.

Before writing an expression, identify all four of these facts:

1. The feature that evaluates it: entity default, entity rule, calculated field, form, serial configuration, or document template.
2. The exact field key or context root, rather than a visible label.
3. The required output type: Boolean, Number, text, date, validation result, or list.
4. How an empty value, lookup failure, or error should behave.

Read [expression contexts and availability](/reference/expressions/contexts) before copying a working expression into another feature.

## Values and paths

### Literals

| Value         | Example                             | Use                                                                     |
| ------------- | ----------------------------------- | ----------------------------------------------------------------------- |
| Text          | `"received"` or `'received'`        | Quote literal option values and output text.                            |
| Number        | `1250.5`                            | Keep arithmetic inputs in Number fields where possible.                 |
| Boolean       | `true`, `false`                     | Use for conditions and explicit choices.                                |
| Missing value | `null`, `undefined`                 | Handle deliberately; they are not interchangeable with an empty string. |
| List          | `["normal", "urgent"]`              | Pass a local collection to a helper or membership test.                 |
| Object        | `{ code: "CSR", priority: "high" }` | Use sparingly for local logic; model operational data as fields.        |

### Read a value

The root comes from the context. Entity rules commonly expose the current record as `$`; document templates expose it as `$record`.

```jexl theme={null}
$.requested_amount
$record.request_id
```

Use dot access for ordinary keys and brackets for a numeric index or a key that is not a simple identifier:

```jexl theme={null}
$.inspections[0].result
$.metadata["source-system"]
$record.attachments[0]
```

Do not guess a key from its translated title. A robust expression refers to the stable field key configured in the builder.

### Filter a list

Relative filters use `.` for the item currently being considered:

```jexl theme={null}
$.inspections[.result == "pass"]
$.inspections[.result == "pass"].scheduled_at
```

Treat an empty result as normal. Test it before using a list as the basis for a critical decision:

```jexl theme={null}
isNotEmpty($.inspections[.result == "pass"])
```

## Operators and precedence

Use parentheses whenever arithmetic, comparison, and logical decisions are mixed. They make policy review easier and prevent accidental reliance on precedence.

| Purpose            | Syntax               | Example                                            | Runtime meaning                             |
| ------------------ | -------------------- | -------------------------------------------------- | ------------------------------------------- |
| Unary values       | `!`, `+`, `-`        | `!$.documents_complete`                            | logical not, numeric sign/coercion          |
| Power              | `**`, `^`            | `2 ** 3`                                           | both are exponentiation                     |
| Remainder          | `%`                  | `$.sequence % 2`                                   | evaluated before multiplication/division    |
| Multiply/divide    | `*`, `/`, `//`       | `17 // 5`                                          | `//` is floor division                      |
| Add/subtract       | `+`, `-`             | `$.base_fee + $.inspection_fee`                    | `+` can also concatenate text               |
| Strict comparison  | `==`, `!=`           | `$.status == "approved"`                           | binary equality is strict; types must match |
| Numeric tolerance  | `~=`, `!~=`          | `$.score ~= 7.5`                                   | within / outside `0.01`                     |
| Ordered comparison | `>`, `>=`, `<`, `<=` | `$.requested_days <= 30`                           | compare compatible types                    |
| Membership         | `in`                 | `$.priority in ["high", "urgent"]`                 | supports lists and structured values        |
| Short-circuit AND  | `&&`                 | `$.owner_id && $.due_date`                         | only evaluates the right side if needed     |
| Short-circuit OR   | logical OR           | fallback owner name                                | returns the first usable branch             |
| Ternary choice     | `? :`                | `$.priority == "urgent" ? "same-day" : "standard"` | choose one value                            |

For a fallback, write the logical-OR operator in an expression block rather than placing its two pipe characters inside a Markdown table cell:

```jexl theme={null}
$.owner_name || "Unassigned"
```

The helper `eq(left, right)` intentionally uses loose equality, while binary `==` does not. Prefer binary `==` for stored option values; use `eq` only when deliberate type coercion is part of the policy.

### Textual `and`, `or`, and `xor`

Textual operators exist for validation-oriented expressions, but their validation-message behavior differs between the shared builder runtime and document-template runtime. They are not a portable way to aggregate several human-facing errors. For ordinary Boolean/value logic, prefer `&&` and `||`. For field validation, use the [validation helpers](/reference/expressions/helpers/validations) in the exact validation context and test the returned message.

## Functions and pipe transforms

Most general helpers have two equivalent forms. A function receives all arguments explicitly:

```jexl theme={null}
round($.requested_amount, 2)
```

A transform receives the value to the left of `|` as its first argument:

```jexl theme={null}
$.requested_amount | round(2)
```

Use the version that reads best. Validation functions, form lookup/filter helpers, and the document-template lookup helper are function calls only. Form-only and serial-only helpers are not general calculated-field APIs; their availability is stated on each reference page.

Browse the complete reference by task:

* [Math helpers](/reference/expressions/helpers/math), [string helpers](/reference/expressions/helpers/string), [date and time helpers](/reference/expressions/helpers/date), and [array helpers](/reference/expressions/helpers/array)
* [Comparison and conditional helpers](/reference/expressions/helpers/operators) and [common conversion helpers](/reference/expressions/helpers/common)
* [Validation helpers](/reference/expressions/helpers/validations) and [legacy aliases](/reference/expressions/helpers/aliases)
* [Form helpers and lookup filters](/reference/expressions/helpers/forms), [serial helpers](/reference/expressions/helpers/serial), and [document-template lookup](/reference/expressions/helpers/document-templates)
* [Project helpers](/reference/expressions/helpers/project) and [planning helpers](/reference/expressions/helpers/planning)

## Templates, lists, and objects

Backtick templates combine fixed text and evaluated values. Put the evaluated expression inside `{{` and `}}`:

```jexl theme={null}
`Request {{ $.request_id }} is assigned to {{ $.owner_name || "the service team" }}`
```

An interpolation that resolves to `null` or `undefined` becomes an empty string. That avoids displaying the word `undefined`, but it can hide missing data. Add an explicit fallback for any public-facing sentence.

You can create a small list or object for local logic:

```jexl theme={null}
$.priority in ["high", "urgent"]
{ request_id: $.request_id, status: $.status }
```

Spread syntax can combine an already structured value with a new item:

```jexl theme={null}
[...$.selected_categories, "other"]
```

Keep these structures local to the expression. If staff must search, approve, report on, or audit a value, store it in a normal field instead.

## Validation expressions are not ordinary conditions

Validation helpers return `true` when valid and a localized error result when invalid. In a field-validation context, helpers such as `v.required()` can receive the current field value automatically through `$value`.

```jexl theme={null}
v.required() and v.minLength(3)
v.greaterThan($.requested_amount, 0)
```

Entity validation and form validation do not consume every return value in exactly the same way. A form, for example, treats `true`, `null`, `undefined`, and an empty string as valid; an expression error can be handled differently from an entity validation error. See [validation helpers](/reference/expressions/helpers/validations) and [expression contexts](/reference/expressions/contexts) before publishing a rule.

## Determinism, dates, and safe use

Avoid `random`, `shuffle`, `sample`, and `sampleSize` in serial formats, persisted calculated fields, or auditable decisions. Avoid relying on the live clock without a refresh policy: `now()`, `isToday`, `isTomorrow`, `isYesterday`, and `getAge` can change without a record edit.

Date helpers do not all use one timezone model. Some calendar helpers use local date setters while `dateAdd`, comparison units, component extraction, and `dateFormat` use UTC-oriented behavior. Use an ISO-like source value, state the intended timezone in the field description, and test values around midnight and daylight-saving boundaries when applicable.

`dateFormat` uses `YYYY`, `MM`, `DD`, `HH`, `mm`, `ss`, and `SSS`. This is different from the smaller `serialDate` vocabulary (`yyyy`, `yy`, `MM`, `dd`).

## Test and troubleshoot

| Symptom                      | First check                                                        | Safe response                                                                    |
| ---------------------------- | ------------------------------------------------------------------ | -------------------------------------------------------------------------------- |
| Blank result                 | Is this root available in this feature?                            | Compare the expression with the context table and test a record with known data. |
| Condition always false       | Are stored option values and types exact?                          | Use strict `==` with the stored value, not a translated label.                   |
| `NaN` or unexpected text     | Is a Number field actually carrying text/null?                     | Check the source and explicitly convert or reject invalid input.                 |
| Date moves by one day        | Is a local/UTC boundary involved?                                  | Test an ISO value near midnight in the target timezone.                          |
| Green editor, failed runtime | Is a context-only helper being used elsewhere?                     | Treat editor status as syntax feedback; test in the real feature.                |
| Lookup returns nothing       | Is this a form or template lookup with an approved query and mode? | Check scope, context, filter keys, timeout behavior, and data-exposure policy.   |

KayanOS Automations does not provide this expression runtime as a general trigger/action configuration language. Use this reference only where a KayanOS builder field explicitly supports expressions.

## Related guides

* [Expressions in the builder](/build/expressions-in-builder)
* [Calculated fields](/build/calculated-fields)
* [Forms, fields, and repeatables](/build/form-fields-and-repeatables)
* [Serial IDs](/build/serial-ids)
* [Document templates](/build/document-templates)

![KayanOS expression syntax in a builder field](https://kayanos.app/docs-images/en/reference/expressions-language-syntax.png)
