CEL Expressions
Quick reference for writing conditions in workflows, event rules, and data validation.
CEL Expressions
Write dynamic conditions for Gravity Rail workflows using CEL (Common Expression Language). Use it to control access to tasks, route conversations, and trigger automations.
Quick Start
CEL expressions evaluate to true or false. Here are common patterns:
cel
Operators
| Type | Operators | Example |
|---|---|---|
| Comparison | == != < > <= >= | member.data.score >= 80 |
| Logic | && (AND) || (OR) ! (NOT) | "vip" in member.labels && is_business_hours |
| Containment | in | "premium" in member.labels |
| Math | + - * / | member.data.quantity * 10 |
Available Variables
member
Information about the current member.
Available in: All contexts where a member is associated (event rules, ability conditions, router tasks).
| Field | Type | Description |
|---|---|---|
member.name | string | Member's name |
member.email | string | Member's email |
member.phone | string | Member's phone number |
member.labels | list | Labels assigned to member (e.g., ["vip", "verified"]) |
member.label_uuids | list | UUIDs of labels assigned to member |
member.data.{type}.{field} | varies | Data from Data Types (singular and collection) |
member.collections.{type}.count | number | Total records for a collection Data Type |
member.collections.{type}.latest.data.{field} | varies | Latest record from collection Data Types (by creation time) |
member.collections.{type}.latest.created_at | string | Timestamp of latest record |
member.collections.{type}.latest.external_id | string | External ID of latest record |
member.collections.{type}.recent | list | Last 10 records (supports exists, filter, map, size) |
Examples:
cel
chat
Information about the current conversation.
Available in: Message event rules, router tasks, ability conditions.
| Field | Type | Description |
|---|---|---|
chat.id | number | Chat ID |
chat.uuid | string | Chat UUID |
chat.channel | string | Channel (see values below) |
chat.chat_type | string | "assignment", "manager", "developer", "supervisor" |
chat.paused | bool | Whether the chat is paused |
chat.needs_response | bool | Whether the chat needs a response |
chat.is_test | bool | Whether this is a test chat |
chat.title | string | Chat title (if set) |
Channel values: "phone-sms", "phone-voice", "email", "web-chat", "web-voice", "cli", "frame", "discord", "slack", "direct-message"
Examples:
cel
task
Information about the current task.
Available in: Ability conditions, router task edges.
| Field | Type | Description |
|---|---|---|
task.id | number | Task ID |
task.uuid | string | Task UUID |
task.name | string | Task name |
assignment
Information about the current assignment (a member's progress through a workflow).
Available in: Ability conditions, event rules on assignment events.
| Field | Type | Description |
|---|---|---|
assignment.id | number | Assignment ID |
assignment.uuid | string | Assignment UUID |
record
Information about the data record that triggered the event.
Available in: Data record event rules only (
data_record:created,data_record:updated,data_record:deleted).
| Field | Type | Description |
|---|---|---|
record.id | number | Record ID |
record.external_id | string | External ID (if set) |
record.data.{field} | varies | Field values from the record |
record.created_at | string | ISO 8601 creation timestamp |
record.updated_at | string | ISO 8601 last-update timestamp |
Examples:
cel
changes
Field-level change tracking for record updates.
Available in:
data_record:updatedevent rules only.
| Field | Type | Description |
|---|---|---|
changes.{field}.old | varies | Previous value of the field |
changes.{field}.new | varies | New value of the field |
Examples:
cel
datetime
Current time in your workspace's timezone.
Available in: All contexts.
| Field | Type | Description |
|---|---|---|
datetime.hour | number | Hour (0-23) |
datetime.minute | number | Minute (0-59) |
datetime.second | number | Second (0-59) |
datetime.day_of_week | number | Day (0=Monday, 6=Sunday) |
datetime.day_of_month | number | Day of month (1-31) |
datetime.month | number | Month (1-12) |
datetime.year | number | Year |
datetime.timestamp | string | ISO 8601 timestamp |
current_date | string | Date as "YYYY-MM-DD" |
current_time | string | Time as "HH:MM" |
is_business_hours | bool | Within workspace business hours |
Examples:
cel
tool_invocations
List of tools the AI called this turn. Each entry has name (string) and args (map of argument values).
Available in: Edge conditions on task transitions only. Evaluated after each agent turn.
| Field | Type | Description |
|---|---|---|
tool_invocations | list | List of tool calls made this turn |
tool_invocations[].name | string | Tool function name (e.g., "update_patient_info_record") |
tool_invocations[].args | map | Arguments passed to the tool |
Examples:
cel
Note: Tool names for Data Access abilities follow the pattern update_{data_type_slug}_record, create_{data_type_slug}_record, etc. Use has(t.args.field) to check field presence before comparing values.
message
The content of the current message.
Available in: Router tasks and message event rules only.
cel
Built-in Functions & Macros
Standard CEL functions available in all contexts:
| Function | Description | Example |
|---|---|---|
has(field) | Check if a field exists and is set | has(member.phone) |
size(value) | Length of a string, list, or map | size(member.labels) > 0 |
exists(x, cond) | True if any list element matches | member.labels.exists(l, l == "vip") |
all(x, cond) | True if all list elements match | member.labels.all(l, l != "blocked") |
filter(x, cond) | Return matching list elements | member.labels.filter(l, l != "test") |
map(x, expr) | Transform each list element | member.labels.map(l, l + "_tag") |
startsWith(prefix) | String starts with prefix | member.phone.startsWith("+1") |
endsWith(suffix) | String ends with suffix | member.email.endsWith("@example.com") |
int(value) | Convert to integer | int("42") == 42 |
string(value) | Convert to string | string(member.id) |
type(value) | Return the type of a value | type(member.name) == string |
Examples:
cel
Custom Functions
| Function | Description | Example |
|---|---|---|
contains(text, substring) | Case-insensitive substring check | contains(member.email, "@gmail.com") |
notcontains(text, substring) | Inverse of contains | notcontains(message, "cancel") |
matches(text, pattern) | Regex pattern match | matches(message, "^[0-9]{5}$") |
containsEntryInFile(text, fileUuid) | Check against uploaded file entries | containsEntryInFile(message, "blocklist-uuid") |
Common Patterns
VIP Handling
cel
Business Hours
cel
Form Completion Check
cel
Channel-Specific Logic
cel
Combined Conditions
cel
Content Filtering
cel
Record Status Change
cel
Tool Invocation Routing (Edge Conditions)
cel
Data Type Validation
CEL expressions can be used within Data Types to control field behavior and validate input.
Conditional Field Options
Use visibleWhen on enum options to show or hide choices based on other field values. The expression evaluates in the form editing context, where field names are available directly.
Example: Show California-specific options only when the state is California.
cel
This would be set on enum options that should only appear for California residents. When the user selects "CA" in the state field, these options become visible.
Field Validation
Use validateCel on fields to add custom validation rules. The expression should return:
trueif the value is valid- An error message string if the value is invalid
Access field values using record.data.<field>.
Example: Require age to be 18 or older.
cel
Example: Require email for non-SMS contacts.
cel
Example: Validate date is in the future.
cel
Tips
-
Use labels for permissions — Labels like
"vip","verified","admin"are the cleanest way to control access. -
Handle missing data — Use
has(field)to check if a field exists before accessing it. For example,has(member.phone) && member.phone != ""safely checks for a phone number. If a field doesn't exist and you access it directly, the expression evaluates tofalserather than erroring. -
Test your expressions — The CEL editor validates syntax in real-time. Invalid expressions show a red error indicator and cannot be saved.
-
Keep it readable — Break complex logic into multiple rules when possible.
-
All available functions appear in the editor — Click the "Functions" dropdown in the CEL editor toolbar to see all built-in and custom functions with signatures and examples.
Related
- Actions — Use CEL conditions to control when automations fire
- Abilities — Add CEL conditions to control when abilities activate
- Qualifications — Use CEL in formula criteria for evaluation
Related Resources
Workflows
Build AI-powered conversation flows with tasks, abilities, and agents.
Actions
Automate your workspace with event-triggered actions, notifications, and webhooks.
Scheduled Events
Run automated actions on schedules - daily reports, reminders, and recurring tasks.
All Guides
Browse all available guides