Skip to main content

OXL Expressions

What is OXL?

OXL (Owlie Expression Language) is a lightweight formula language. It lets you reference data from a context object and transform it using operators and functions — similar to a spreadsheet formula.

Syntax at a glance

Referencing context values

Every expression runs against a context object. Use dot notation or bracket notation to access values.

Given this context:

{
"identity": {
"firstName": "Jane",
"lastName": "Doe",
"email": "jane@acme.com"
}
}
ExpressionResult
identity.email"jane@acme.com"
identity["firstName"]"Jane"
identity.firstName + " " + identity.lastName"Jane Doe"

Arithmetic

ExpressionResult
10 + 515
10 - 55
3 * 412
10 / 33.333…
10 // 33 (floor division)
10 % 31 (remainder)
2 ^ 8256 (exponentiation)

Comparison and logic

Given this context:

{
"age": 25,
"role": "admin",
"active": true
}
ExpressionResult
age >= 18true
role == "admin"true
role == "admin" && activetrue
!activefalse

The in operator

Checks membership in arrays and substrings in strings.

Given this context:

{
"roles": ["viewer", "admin"],
"email": "jane@acme.com"
}
ExpressionResult
"admin" in rolestrue
"@acme" in emailtrue

Conditional (ternary) expressions

condition ? valueIfTrue : valueIfFalse

Given this context:

{
"active": true,
"nickname": null,
"firstName": "Jane"
}
ExpressionResult
active ? "enabled" : "disabled""enabled"
nickname ?: firstName"Jane" (shorthand — returns first truthy value)

Arrays

Given this context:

{
"roles": ["viewer", "editor", "admin"],
"groups": [
{ "name": "eng", "active": true },
{ "name": "sales", "active": false }
]
}
ExpressionResult
roles[0]"viewer"
first(roles)"viewer"
length(roles)3
groups[.active == true][{"name": "eng", "active": true}]

Array filtering uses relative identifiers — the . prefix means "this element":

groups[.active == true]

This filters the groups array, keeping only elements where .active is true.

String functions

Given this context:

{
"identity": {
"firstName": "Jane",
"lastName": "Doe",
"email": "jane@acme.com"
}
}
ExpressionResult
upper(identity.lastName)"DOE"
lower(identity.firstName)"jane"
split(identity.email, "@")["jane", "acme.com"]
contains(identity.email, "@acme.com")true
replace(identity.email, "acme.com", "newco.com")"jane@newco.com"

Null-safe patterns

Given this context:

{
"nickname": null,
"firstName": "Jane",
"tags": []
}
ExpressionResult
coalesce(nickname, firstName)"Jane"
isEmpty(tags)true

Object introspection

Given this context:

{
"attrs": {
"dept": "Engineering",
"level": "senior"
}
}
ExpressionResult
keys(attrs)["dept", "level"]
values(attrs)["Engineering", "senior"]
length(attrs)2

Generating passwords

Use genPassword() in provisioning expressions to create secure random passwords.

ExpressionResult (example)
genPassword()"aK3!mR7@pL2#nQ5&" (16 chars)
genPassword(24)"xP4!kM8@rL2#nQ5&wT9*yB7=" (24 chars)

Every generated password includes at least one lowercase letter, one uppercase letter, one digit, and one special character.


Putting it together

Build a display name from identity fields:

identity.firstName + " " + upper(substring(identity.lastName, 0, 1)) + "."

Result: "Jane D."


Assign a license tier based on role membership:

"admin" in roles ? "enterprise" : (length(roles) > 1 ? "pro" : "basic")

Result: "enterprise" (when roles include "admin")


Extract a domain from an email address:

last(split(config.email, "@"))

Result: "acme.com"


Check if a user belongs to any active engineering group:

length(groups[.active == true && startsWith(.name, "eng")]) > 0

Result: true

Troubleshooting

  • Expression too long — Expressions are limited to 2,000 characters.
  • Timeout errors — Expressions must evaluate within 500ms. Avoid filtering extremely large arrays.
  • Variable not found — Double-check that the variable name matches the context. Names are case-sensitive.

Next steps

  • OXL Reference — Complete list of operators, functions, types, and limits