Conditions
A condition is a boolean check the system evaluates against the live reservation, guest, property, teammate, or message-thread state. Conditions appear in two places:
- Trigger conditions — should this template fire at all for this reservation?
- Auto-resolve conditions — should this scheduled task actually run when its time comes?
Shape
{
"property": "reservation.nukiAccessCode",
"operator": "is_not_null",
"value": null,
"notifyOnNotMet": true
}
property— the entity.field to read (uses the same namespacing as placeholders).operator— one ofequals,notEquals,in,notIn,is_null,is_not_null,greaterThan,lessThan,contains,startsWith.value— comparison value (literal or another placeholder reference).notifyOnNotMet— only meaningful for auto-resolve conditions; when true, the operator gets a WhatsApp ping at fire time if the condition fails.
Multiple conditions are AND-combined.
Common conditions
Pre-fire (Send Check-in)
reservation.nukiAccessCode is_not_null
"Don't send the check-in message until the PIN has been generated."
Pre-fire (Pre-checkout reminder)
messageThread.hasUnansweredGuestMessage equals false
"Don't send the pre-checkout reminder if the guest has an open question — answer them first."
Pre-fire (Thank-you message)
reservation.guestMood notIn ['angry', 'disputed']
"Only send a warm thank-you if the guest isn't visibly upset."
Pre-fire (Generate access code)
reservation.status notIn ['cancelled', 'no_show']
"Don't provision a PIN for a cancelled reservation."
Sequenced auto-resolve
task.dependencies.allDone equals true
"Wait until all dependent tasks complete first."
When a condition is met / not met
At evaluation time:
- The runtime walks the property path the same way placeholders do.
- Compares against
valueusingoperator. - Returns true / false.
If false:
- Trigger conditions → the template doesn't fire for this reservation; no task is created.
- Auto-resolve conditions → the task stays in
scheduledstatus; ifnotifyOnNotMet: true, the operator is notified.
In both cases, the failure is logged to app_errors with enough context to debug.
Adding a new property to the catalogue
Developer task: add the field to platformCapabilities.ts. The editor's condition picker reads from that file at startup. Operators don't need to do anything — once the developer ships the change, the new property appears in the condition picker on next reload.
A note on data quality
A condition that reads from data the system never populates is just a permanently-false gate. Common examples:
reservation.guestMood— only populated after the LLM mood-analyser has run on at least one inbound guest message. New reservations with no inbound messages haveguestMood = NULL.reservation.guestCommunicationType— same as guestMood.reservation.earlyCheckinTime— only set if the guest or operator explicitly requested early check-in; otherwise NULL.
Use is_not_null / is_null operators when you're not sure the field is always populated, and consider a fallback chain in placeholders.
Related issues
- #214 — condition status surfaced on task cards.
- #260 —
reservation.nukiAccessCode is_not_nullcondition reads from canonical guest row (JOIN disambiguation). - #180 — silent-skip →
failed; conditions are now the authoritative truth.