Skip to content

CEL Functions Reference

Complete reference for all functions available in Mycel transforms and conditions.

Context Variables

Variable Description
input Incoming data (request body, message payload, query result)
output Already-computed output fields in the current transform
ctx Request context: headers, path params, user info
enriched Data fetched from enrich blocks
step Results from named step blocks
result Flow result (in aspect conditions)
error Error message string (in aspect conditions)
_flow Flow name (in aspects)
_operation Operation name (in aspects)
_target Target name (in aspects)
_timestamp Unix timestamp (in aspects)

Mycel Built-in Functions

Identity and Time

Function Signature Returns Description
uuid() () → string UUID v4 string Generate a random UUID
now() () → string RFC3339 string Current UTC time
now_unix() () → int Unix timestamp Current time as Unix seconds
uuid()        // "550e8400-e29b-41d4-a716-446655440000"
now()         // "2025-12-29T15:04:05Z"
now_unix()    // 1735488245

String Functions

Function Signature Description
lower(s) (string) → string Convert to lowercase
upper(s) (string) → string Convert to uppercase
trim(s) (string) → string Remove leading/trailing whitespace
replace(s, old, new) (string, string, string) → string Replace all occurrences of old with new
split(s, sep) (string, string) → list(string) Split string by separator
join(list, sep) (list(string), string) → string Join list items with separator
substring(s, start, end) (string, int, int) → string Extract substring (byte indices)
len(s) (string) → int String length in bytes
hash_sha256(s) (string) → string SHA-256 hash (hex encoded)
format_date(date, fmt) (string, string) → string Reformat ISO date string
lower("HELLO")                          // "hello"
upper("hello")                          // "HELLO"
trim("  hello  ")                       // "hello"
replace("hello", "l", "L")             // "heLLo"
split("a,b,c", ",")                     // ["a", "b", "c"]
join(["a", "b", "c"], "-")              // "a-b-c"
substring("hello", 1, 4)               // "ell"
len("hello")                           // 5
hash_sha256("password")                // hex string

// format_date tokens: YYYY MM DD HH mm ss
format_date("2025-01-15T10:30:00Z", "YYYY-MM-DD")  // "2025-01-15"
format_date(now(), "DD/MM/YYYY HH:mm")              // "15/01/2025 10:30"

Default and Null Handling

Function Signature Description
default(value, fallback) (any, any) → any Return fallback if value is null or empty string
coalesce(value, fallback) (any, any) → any Alias for default
default(input.nickname, input.name)   // Use name if nickname is null/empty
coalesce(input.phone, "N/A")          // "N/A" if phone is null/empty

Map Functions

Function Signature Description
merge(m1, m2) (map, map) → map Merge two maps; m2 values override m1
merge(m1, m2, m3) (map, map, map) → map Merge three maps
merge(m1, m2, m3, m4) (map, map, map, map) → map Merge four maps
omit(m, k1) (map, string) → map Return map without key k1
omit(m, k1, k2) (map, string, string) → map Return map without keys k1 and k2
omit(m, k1, k2, k3) (map, string, string, string) → map Return map without up to 3 keys
pick(m, k1) (map, string) → map Return map with only key k1
pick(m, k1, k2) (map, string, string) → map Return map with only keys k1 and k2
pick(m, k1, k2, k3) (map, string, string, string) → map Return map with only up to 3 keys
merge(step.order, {"customer": step.customer})
omit(input, "password")
omit(input, "password", "secret_token")
pick(input, "id", "email")

Array Functions

Function Signature Description
first(list) (list) → any First element, or null if empty
last(list) (list) → any Last element, or null if empty
flatten(list) (list(list)) → list Flatten one level of nesting
unique(list) (list) → list Remove duplicate values
reverse(list) (list) → list Reverse list order
pluck(list, key) (list(map), string) → list Extract a field from each map in a list
sort_by(list, key) (list(map), string) → list Sort list of maps by field (ascending)
sum(list) (list(number)) → number Sum numeric values
avg(list) (list) → double Average of numeric values
min_val(list) (list) → any Minimum value
max_val(list) (list) → any Maximum value
first(input.items)                         // first item or null
last(input.items)                          // last item or null
flatten([[1, 2], [3, 4]])                  // [1, 2, 3, 4]
unique([1, 2, 2, 3])                       // [1, 2, 3]
reverse([1, 2, 3])                         // [3, 2, 1]
pluck(input.orders, "total")               // [100, 200, 150]
sort_by(input.products, "price")           // sorted by price asc
sum(pluck(input.items, "price"))           // sum of prices
avg(pluck(input.scores, "value"))          // average score
min_val(pluck(input.bids, "amount"))       // minimum bid
max_val(pluck(input.bids, "amount"))       // maximum bid

GraphQL Field Selection

Function Signature Description
has_field(input, path) (map, string) → bool True if field path was requested in the GraphQL query
field_requested(input, path) (map, string) → bool Alias for has_field
requested_fields(input) (map) → list(string) All requested field paths
requested_top_fields(input) (map) → list(string) Top-level requested fields only
has_field(input, "orders")              // true if "orders" was queried
has_field(input, "orders.items")        // true if nested field was requested
requested_fields(input)                 // ["id", "name", "orders", "orders.total"]
requested_top_fields(input)             // ["id", "name", "orders"]

CEL Standard Extensions

ext.Strings — Extended String Operations

Function Signature Description
s.charAt(i) (string, int) → string Character at index
s.indexOf(sub) (string, string) → int First index of substring (-1 if not found)
s.lastIndexOf(sub) (string, string) → int Last index of substring
s.upperAscii() (string) → string ASCII uppercase
s.lowerAscii() (string) → string ASCII lowercase
s.replace(old, new) (string, string, string) → string Replace first occurrence
s.replace(old, new, n) (string, string, string, int) → string Replace up to n occurrences
s.split(sep) (string, string) → list Split string
s.substring(start, end) (string, int, int) → string Extract substring
s.trim() (string) → string Trim whitespace
s.reverse() (string) → string Reverse string
list.join(sep) (list, string) → string Join list with separator
"hello".charAt(1)                    // "e"
"hello world".indexOf("o")           // 4
"hello world".lastIndexOf("o")       // 7
"hello".upperAscii()                 // "HELLO"
"hello".replace("l", "L")            // "heLLo"
"a,b,c".split(",")                   // ["a", "b", "c"]
"hello".substring(1, 4)              // "ell"
"  hello  ".trim()                   // "hello"
"hello".reverse()                    // "olleh"
["a", "b", "c"].join("-")            // "a-b-c"

ext.Encoders — Base64

Function Signature Description
base64.encode(bytes) (bytes) → string Base64 encode
base64.decode(s) (string) → bytes Base64 decode
base64.encode(b"hello")              // "aGVsbG8="
base64.decode("aGVsbG8=")            // b"hello"

ext.Math — Mathematical Functions

Function Signature Description
math.abs(n) (number) → number Absolute value
math.ceil(n) (double) → double Ceiling
math.floor(n) (double) → double Floor
math.round(n) (double) → double Round to nearest
math.sign(n) (number) → number Sign (-1, 0, 1)
math.greatest(...) (number, ...) → number Maximum of arguments
math.least(...) (number, ...) → number Minimum of arguments
math.isNaN(n) (double) → bool Is NaN?
math.isInf(n) (double) → bool Is infinite?
math.abs(-5)                         // 5
math.ceil(4.2)                       // 5.0
math.floor(4.8)                      // 4.0
math.round(4.5)                      // 5.0
math.sign(-10)                       // -1
math.greatest(1, 5, 3)               // 5
math.least(1, 5, 3)                  // 1

ext.Lists — Extended List Operations

Function Signature Description
list.slice(from, to) (list, int, int) → list Slice from index to index
list.flatten() (list(list)) → list Flatten one level
lists.range(n) (int) → list(int) Generate [0, 1, ..., n-1]
[1, 2, 3, 4, 5].slice(1, 4)          // [2, 3, 4]
[[1, 2], [3, 4]].flatten()           // [1, 2, 3, 4]
lists.range(5)                        // [0, 1, 2, 3, 4]

ext.Sets — Set Operations

Function Signature Description
sets.contains(a, b) (list, list) → bool True if a contains all elements of b
sets.equivalent(a, b) (list, list) → bool True if a and b have same elements
sets.intersects(a, b) (list, list) → bool True if a and b share any element
sets.contains([1, 2, 3], [2, 3])     // true
sets.equivalent([1, 2], [2, 1])      // true
sets.intersects([1, 2], [2, 3])      // true

CEL Built-ins

Type Conversions

int("42")                            // 42
double(42)                           // 42.0
string(42)                           // "42"
bool(1)                              // true
bytes("hello")                       // b"hello"

String Methods (CEL built-ins)

"hello".startsWith("he")             // true
"hello".endsWith("lo")               // true
"hello".contains("ell")              // true
"ABC123".matches("[A-Z]{3}[0-9]+")   // true (regex)
"hello".size()                       // 5

List Built-ins

[1, 2, 3].size()                     // 3
[1, 2, 3][0]                         // 1
"admin" in input.roles               // membership check

// Comprehension macros
input.items.exists(x, x.price > 100)   // any item over $100?
input.items.all(x, x.available)        // all items available?
input.items.filter(x, x.price > 50)    // items over $50
input.items.map(x, x.price * 1.1)      // apply 10% markup

Operators

// Arithmetic
input.price * input.quantity
input.total + input.tax
input.balance - input.withdrawal
input.count / 2
input.value % 10

// Comparison
input.age >= 18
input.status == "active"
input.score != 0
input.amount > 100
input.priority < 5

// Logical
input.active && input.verified
input.admin || input.moderator
!input.deleted

// Conditional (ternary)
input.age >= 18 ? "adult" : "minor"

// Null coalescing
input.nickname ?? input.name
input.body.payload.jobId ?? ''
input.list ?? []

?? is preprocessed by Mycel before reaching CEL. When the left-hand side is a simple dotted path (e.g. input.body.payload.jobId), the rewrite uses CEL's has() macro to check every parent segment, so a missing intermediate field falls back cleanly instead of raising "no such key". For other left-hand sides (function calls, parenthesized expressions) the rewrite is coalesce(lhs, rhs), which catches present-but-null and present-but-empty-string values but evaluates lhs eagerly.

Chaining is right-associative: a ?? b ?? c behaves like a ?? (b ?? c).

When mixing ?? with the ternary ?: at the same depth, parenthesize for clarity: (a ?? b) ? c : d. The rewriter does not resolve precedence against ?: automatically.

Common Patterns

Email normalization

lower(trim(input.email))

Slug generation

lower(replace(trim(input.name), " ", "-"))

Conditional field with fallback

default(input.display_name, input.first_name + " " + input.last_name)

Extract domain from email

split(input.email, "@")[1]

Compute order total

sum(pluck(input.items, "price"))

Flatten and deduplicate tags

unique(flatten([input.tags, input.extra_tags]))

Conditional status based on multiple fields

input.paid && input.shipped ? "completed" : input.paid ? "processing" : "pending"