Sevro

CEL Expressions

Reference for the CEL expression language used in conditions, actions, validation, and filters.

Sevro uses CEL (Common Expression Language) for all logic: method conditions, actions, computed fields, validation rules, authorization policies, and record filters.

CEL is a simple, fast, and safe expression language designed for embedded use. It's not Turing-complete — no loops, no recursion — which makes it predictable and debuggable.

Context variables

Different contexts provide different variables:

Method conditions

VariableDescription
recordThe current record's fields
paramsThe method's input parameters
record.status == "draft"
record.amount > 0
params.discount <= record.amount

Method actions

VariableDescription
recordThe current record's fields (before mutation)
paramsThe method's input parameters
"paid"                    // set status to "paid"
params.customer_name      // copy parameter to field
now()                     // set timestamp to current time
record.amount * 0.9       // compute discounted price

Computed fields

VariableDescription
recordThe current record's fields
record.price * record.quantity    // compute total
record.first_name + " " + record.last_name  // compute full name

Validation rules

VariableDescription
recordThe current record's fields
record.age >= 0
record.email.contains("@")
record.start_date < record.end_date

Record filters (ListRecords)

VariableDescription
recordThe record being filtered
record.status == "active"
record.age > 18
record.name.contains("Alice")

Authorization policies

VariableDescription
identityThe authenticated identity (identity.subject, identity.roles)
actionThe action being performed
resourceThe target resource
recordThe record (if applicable)
identity.role == "admin"
record.creator_id == identity.subject
identity.role == "manager" || action != "approve"

Workflow expressions

VariableDescription
$.input.<field>Workflow input
$nodes.<id>.output.<field>Output from a previous node
$nodes.<id>.errorError from a failed node
$nodes.check_inventory.output.available == true
$.input.order_id
$nodes.validate_order.output.total + $nodes.create_shipment.output.shipping_cost

Built-in functions

FunctionReturnsDescription
now()stringCurrent timestamp in RFC 3339 format
uuid()stringGenerate a random UUID
len(x)intLength of a string, list, or map
upper(s)stringConvert string to uppercase
lower(s)stringConvert string to lowercase
contains(s, sub)boolCheck if string contains substring
startsWith(s, prefix)boolCheck if string starts with prefix
endsWith(s, suffix)boolCheck if string ends with suffix
format(fmt, args...)stringFormat string with arguments

Type system

CEL supports the following types:

TypeExamples
booltrue, false
int42, -7
double3.14, 1e5
string"hello", 'world'
nullnull
list[1, 2, 3]
map{"key": "value"}

Type checking

CEL is statically typed — type errors are caught at compile time. If a field is a string, comparing it to a number is a compile error.

Operators

OperatorDescription
==, !=Equality
<, >, <=, >=Comparison
&&Logical AND
||Logical OR
!Logical NOT
+Addition / string concatenation
-, *, /, %Arithmetic
inList/map membership

Examples

Conditions

// Only allow marking as paid if status is draft
record.status == "draft"

// Only allow cancel if not already paid
record.status != "paid"

// Only allow order if amount is positive and customer is active
record.amount > 0 && record.customer_active == true

Actions

// Set a field to a constant
"paid"

// Copy a parameter
params.customer_name

// Set timestamp
now()

// Compute a value
record.price * record.quantity

// Conditional value
record.status == "draft" ? "submitted" : record.status

Validation

// Age must be non-negative
record.age >= 0

// Email must contain @
record.email.contains("@")

// End date must be after start date
record.start_date < record.end_date

// Discount can't exceed 50%
record.discount <= 0.5

Filters

// Active users
record.is_active == true

// Created in the last 30 days
record.created_at > "2024-01-15T00:00:00Z"

// Name starts with "A"
record.name.startsWith("A")

// Status is one of several values
record.status in ["draft", "pending", "review"]

Custom functions

Sevro supports registering custom Go functions callable from CEL. This allows extending the expression language with domain-specific logic. Custom functions are registered at the platform level via plugins (WASM modules).

See the plugin documentation for details on registering custom functions.

On this page