Expression Language

Expressions are strings. Non-string primitives (42, true, [], {}) are treated as literals.

Scopes

ScopeAvailable inDescription
event.<field>actions, projections (derive), listenersEvent payload field
event.tsallEvent timestamp (epoch ms) — reserved
event.entity_idallRouting entity ID — reserved
event.typeallEvent type string — reserved
entity.<field>actions (core/side_effects), preflightCurrent entity state (dot notation)
input.<field>actions (entity_id_expr), queriesAction input or query parameter
intent.<field>actionsAlias for input.<field>
state.idactionsCurrent entity ID
resources.<type>["<id>"].<field>allStatic resource lookup
it.<field>find, filter, remove, for_eachIterator variable
item.<field>emit_each, for_eachIterator variable
<var>.<field>after find … as: var or clone … as: varBound variable
project.<field>actionsPlatform-level shared state
global.<field>actionsGlobal read-only state

event.<field> in rules vs projections

In rules: event.amount reads from the intent payload directly. In projection derive:: event.amount and event.payload.amount are both accepted (the latter is a backwards-compat alias).

Never use event.payload.amount in rules — it always returns null.

Operators

==  !=  >  <  >=  <=  &&  ||
+   -   *   /
!expr              (logical not: !contains(entity.tags, "x"))
cond ? a : b       (ternary)
val ?: default     (null-coalesce)
entity['path']     (bracket access)
array[0]           (index access)

Built-in functions

FunctionDescription
size(array)Array length
sum(array)Sum of numeric values
contains(array, value)Check if array contains value
map(array, expr)Transform array
filter(array, expr)Filter array (keep matching)
max(a, b)Maximum of two values
min(a, b)Minimum of two values
floor(value)Floor of a number
concat(a, b, …)Concatenate strings
join(array, sep)Join array to string
format_date(ts)Format epoch ms timestamp
is_prev_day(d1, d2)Check if two timestamps are on different days
shard(expr, N)Map expression to shard ID 0..N-1
lookup(stream, id_expr).<field>Cross-entity lookup (projections only)
LOOKUP_FIELD('stream', id, '/path')Cross-stream field read (rule expressions / preflight)

FORBIDDEN expressions

The following are rejected at compile time with VERR_NON_DETERMINISTIC_EXPRESSION or VERR_SPEL_FORBIDDEN_FUNCTION:

now()       random()    uuid()      Math.random
shuffle()   nanoTime()  System.*    Runtime.*
Process.*   Thread.*    Runnable.*  getClass
forName     eval        exec
http.*      redis.*     db.*        kafka.*
s3.*        stripe.*    env.*       secret.*

All IDs must be deterministic. Build them with concat:

value: "concat('notif_', event.user_id, '_', event.show_id)"