Reference

CEL Expressions

The expression language behind formula fields, validation rules, visibility, sharing and flow conditions — where ObjectOS uses it, a few examples, and the full language on objectstack.ai.

Full specification: Expressions (CEL) on objectstack.ai. This page is the summary: where ObjectOS uses it, and a few examples.

ObjectOS uses CEL (Common Expression Language) wherever a definition needs a small, safe expression: it has no side effects and no I/O, and it is evaluated on the server. An expression sees the record being evaluated as record (and its previous state as previous), and — where there is an acting user — that user as current_user.

Where ObjectOS uses it

WhereWhat the expression decides
A formula fieldThe field's value, derived from the record
A field's requiredWhen, visibleWhen, readonlyWhenWhether the field is required, shown or editable on this record
A validation ruleWhether a write is refused (Validation Rules)
A sharing ruleWhich records a group of users is granted (Record Access)
An action's visible / disabledWhether the button is offered
A flow's start condition and its branchesWhether a flow runs, and which way it goes (Flows)
A field's defaultValueThe value a new record starts with

Examples

Formula field — line-item total:

subtotal: Field.formula({
  label: 'Subtotal',
  expression: F`record.quantity * record.unit_price`,
}),

Validation — close date must be in the future. A script rule's condition describes the invalid record: when it is true, the write is refused.

// One validation rule, an entry of the object's `validations`
{
  type: 'script',
  name: 'close_date_in_future',
  message: 'Close date must be in the future',
  condition: P`record.close_date <= today()`,
}

Visibility — show a field only once the deal is won:

close_reason: Field.textarea({
  label: 'Close reason',
  visibleWhen: P`record.stage == 'closed_won'`,
}),

Flow condition — start a record-change flow only for large amounts:

// The `config` of a `start` node; the rest of the flow is omitted (see Flows).
config: {
  objectName: 'opportunity',
  triggerType: 'record-after-update',
  condition: P`record.amount >= 1000`,
}

Permission checks

Since ObjectStack 17.5, current_user.can(object, verb) asks whether the acting user holds an object permission, answered from that user's effective permissions:

discount: Field.percent({
  label: 'Discount',
  defaultValue: cel`current_user.can('crm_quote', 'edit') ? 10 : 0`,
}),

The server answers it in a select option's visibleWhen (an option the user may not pick is refused invalid_option), in formula fields and in a CEL defaultValue. Where an evaluation carries no permission data — a validation rule is one — can() is refused rather than guessed, and the expression fails.

When an expression is wrong

It does not fail silently. A malformed expression, or one naming a field the object does not have, fails os compile with the location and a did-you-mean hint. At runtime a bad expression throws an attributed error rather than evaluating to null or false, so the failure shows in logs and the audit trail instead of quietly corrupting a formula value or a guard decision.

See also