cody-automation
v1.0.0Cody Automation Skill - Specification for creating Automation element details in prooph board. Defines event reaction, dependencies, and automation rules for automated reactions to events.
cody-automation
Define Automation element details for the Cody Engine low-code platform.
Overview
This skill teaches AI agents how to create detailed specifications for Automation elements in Cody Engine, the low-code platform behind prooph board.
Important: This is a Cody Engine-specific skill. It is only useful if you work with the Cody Engine to generate applications from Event Models. If you use prooph board purely for Event Modeling without Cody Engine, this skill does not apply to you.
An Automation in Cody Engine represents an automated reaction to events. The skill covers how to define event reactions, dependencies on external data, and automation rules using the Rule Engine — including command triggers, user lookups, scheduled notifications, and batch processing.
What This Skill Covers
- Event Reaction Declaration — Marks the automation as reacting to events in the chapter flow
- Dependencies — External data requirements (queries, services) using
cody-dependenciesblocks - Automation Rules — Event handling logic using
cody-rulesblocks and the Rule Engine, includingtrigger,lookup,forEach,assign, andlogactions
Why This Skill
- Complete automation specs — Covers event reactions, data dependencies, and rule-based logic
- Notification patterns — Teaches proper use of severity levels, scheduling, and deduplication tags
- Rule Engine knowledge — Guides the agent through trigger, lookup, and forEach patterns
When to Use
| ✅ Use This Skill | ❌ Skip It |
|---|---|
| Modeling automation elements for Cody Engine applications | Using prooph board for Event Modeling only (no Cody Engine) |
| Defining event-triggered automated reactions | General code generation for other frameworks |
| Without knowledge of the Cody Engine Rule Engine |
Usage
Once installed, your AI agent will know how to create structured automation specifications with dependencies and Rule Engine rules for event reactions, notifications, and scheduled tasks.
Examples
Prerequisites
- Familiarity with the Cody Engine low-code platform
- Understanding of event-driven automation patterns
- Knowledge of the Rule Engine and JEXL expressions
Cody Automation Skill - Automation Element Details Specification
This document describes the structure and patterns for creating Automation element details in the Cody/prooph board system.
Overview
Automation elements represent automated reactions to events. They listen for specific events and trigger commands, send notifications, or perform other automated actions.
Automation details contain structured markdown with code blocks that define:
- Event Reaction - Declaration that this automation reacts to events
- Dependencies - External data requirements (queries, services)
- Automation Rules - Business logic for event handling
Related Documentation
- Rule Engine — Details on the rule engine used for automation rules (
cody-rules) includingtrigger,lookup,forEach, andlogactions - JEXL Expressions — Documentation for JEXL expressions used in
cody-rulesandcody-dependenciescode blocks
Structure Template
Simple Automation
```markdown
## Event Reaction
This declares that the automation reacts to events. The specific event is determined by the event this automation element is placed after in the chapter flow.
2. Dependencies
Optional - declares external data requirements
Query Dependency
{
"GetPlannedReminder": {
"type": "query",
"alias": "plannedReminder",
"options": {
"query": {
"leadId": "$> event.leadId"
}
}
}
}
Service Dependency
{
"AuthService": {
"type": "service"
}
}
Multiple Dependencies
{
"AuthService": {
"type": "service"
},
"GetLead": {
"type": "query",
"alias": "lead"
},
"GetPlannedViewingReminder": {
"type": "query",
"alias": "plannedReminder",
"options": {
"query": {
"leadId": "$> event.leadId"
}
}
}
}
Empty Dependencies
{}
3. Automation Rules
Required for all automations - defines event handling logic
Automation rules use the Rule Engine. Key actions for automations include
trigger(execute commands),lookup(find users),forEach(iterate collections),assign(set variables), andlog(debug output).
Rule Structure
[
{
"rule": "always | condition",
"if": "$> boolean_expression",
"if_not": "$> boolean_expression",
"then": {
// Action object
},
"else": {
// Alternative action
},
"stop": true
}
]
Action Types
1. Trigger Command
Triggers a command with mapped data:
[
{
"rule": "condition",
"if": "$> event.leadId",
"then": {
"trigger": {
"command": "HandOutContractToLead",
"mapping": {
"leadId": "$> event.leadId"
}
}
}
}
]
2. Trigger Command with Multiple Notifications
[
{
"rule": "always",
"then": {
"trigger": {
"command": "SendNotification",
"mapping": {
"notificationId": "$> uuid()",
"severity": "$> 'success'",
"tag": "$> 'new-lead-' + event.leadId",
"msg": "$> 'New lead submitted: ' + event.firstName + ' ' + event.lastName",
"to": "$> locationHead.userId",
"plannedFor": "$> eventCreatedAt|isoDateTime()"
}
}
}
},
{
"rule": "always",
"then": {
"trigger": {
"command": "SendNotification",
"mapping": {
"notificationId": "$> uuid()",
"severity": "$> 'warning'",
"tag": "$> 'new-lead-reminder-' + event.leadId",
"msg": "$> 'Attention! New lead not contacted within 24h: ' + event.firstName + ' ' + event.lastName",
"to": "$> locationHead.userId",
"plannedFor": "$> eventCreatedAt|addDays(1)|isoDateTime()"
}
}
}
}
]
3. Log Message
[
{
"rule": "condition",
"if_not": "$> plannedReminder|first()",
"then": {
"log": {
"msg": "$> 'No new lead reminder planned. Aborting ...'"
}
},
"stop": true
}
]
4. Log with Multiple Parts
[
{
"rule": "condition",
"if_not": "$> locationHead",
"then": {
"log": {
"msg": [
"$> 'No KL found for location: '",
"$> event.locationId",
"$> '. Aborting notifications.'"
]
}
},
"stop": true
}
]
5. Assign Variable
[
{
"rule": "always",
"then": {
"assign": {
"variable": "locationHead",
"value": "$> locationHeadMatch|first()"
}
}
}
]
6. Lookup Users
[
{
"rule": "always",
"then": {
"lookup": {
"users": {
"filter": {
"eq": {
"prop": "attributes.location",
"value": "$> event.locationId"
}
},
"variable": "locationHeadMatch"
}
}
}
}
]
7. For Each Loop
[
{
"rule": "always",
"then": {
"forEach": {
"variable": "plannedReminders",
"then": {
"trigger": {
"command": "DiscardNotification",
"mapping": {
"notificationId": "$> item|get('notificationId')"
}
}
}
}
}
}
]
8. Execute Nested Rules
[
{
"rule": "condition",
"if_not": "$> event.viewingAppointment",
"then": {
"execute": {
"rules": [
{
"rule": "condition",
"if_not": "$> plannedReminder|first()",
"then": {
"log": {
"msg": "$> 'No viewing appointment planned. Aborting ...'"
}
},
"else": {
"trigger": {
"command": "DiscardNotification",
"mapping": {
"notificationId": "$> plannedReminder|first()|get('notificationId')"
}
}
}
}
]
}
},
"stop": true
}
]
Complete Examples
Example 1: Simple Command Trigger
```markdown
## Event Reaction
## Dependencies
```cody-dependencies
{}
```
## Automation
```cody-rules
[
{
"rule": "always",
"then": {
"trigger": {
"command": "SendNotification",
"mapping": {
"notificationId": "$> uuid()",
"severity": "$> 'warning'",
"tag": "$> 'fill-datasheet-reminder-{{event.contractId}}'",
"msg": "$> 'A datasheet was handed out to {{event.parents[0].firstName}} {{event.parents[0].lastName}} at {{eventCreatedAt|localDate()}}, but we did not receive an answer yet. Please contact the parents and ask if everything is ok'",
"to": "$> meta.user.userId",
"plannedFor": "$> eventCreatedAt|addDays(7)|isoDate() + 'T07:00:00.000Z'"
}
}
}
}
]
Notification Patterns
Immediate Notification
[
{
"rule": "always",
"then": {
"trigger": {
"command": "SendNotification",
"mapping": {
"notificationId": "$> uuid()",
"severity": "$> 'success'",
"tag": "$> 'action-completed'",
"msg": "$> 'Action completed successfully'",
"to": "$> meta.user.userId",
"plannedFor": "$> eventCreatedAt|isoDateTime()"
}
}
}
}
]
Scheduled Reminder (Future)
[
{
"rule": "always",
"then": {
"trigger": {
"command": "SendNotification",
"mapping": {
"notificationId": "$> uuid()",
"severity": "$> 'warning'",
"tag": "$> 'reminder-task'",
"msg": "$> 'Reminder: Task needs attention'",
"to": "$> userId",
"plannedFor": "$> eventCreatedAt|addDays(1)|isoDateTime()"
}
}
}
}
]
Scheduled at Specific Time
[
{
"rule": "always",
"then": {
"trigger": {
"command": "SendNotification",
"mapping": {
"notificationId": "$> uuid()",
"severity": "$> 'info'",
"tag": "$> 'morning-reminder'",
"msg": "$> 'Morning reminder message'",
"to": "$> userId",
"plannedFor": "$> eventCreatedAt|addDays(1)|isoDate() + 'T07:00:00.000Z'"
}
}
}
}
]
Severity Levels
| Severity | Use Case |
|---|---|
success |
Positive confirmation (item created, action completed) |
info |
Informational messages (appointment scheduled) |
warning |
Reminders requiring attention (follow-up needed) |
error |
Critical issues (failed operations) |
Expression Syntax
Expressions use the JEXL expression language. The
$>prefix marks a JEXL expression in Cody code blocks.
Available Variables
| Variable | Description |
|---|---|
$> event |
The triggering event data |
$> meta.user |
Current user |
$> eventCreatedAt |
Event timestamp |
$> item |
Current item in forEach loop |
$> order |
Dependency alias (query result) |
$> customer |
Dependency alias (query result) |
$> plannedReminder |
Dependency alias (query result) |
Common Expressions
Access Event Data:
$> event.itemId
$> event.title
$> event.groupId
$> event.taskId
$> event.dueDate
$> event.assignee.firstName
Date/Time Operations:
$> eventCreatedAt|isoDateTime()
$> eventCreatedAt|isoDate()
$> eventCreatedAt|localDate()
$> eventCreatedAt|localDateTime()
$> eventCreatedAt|addDays(1)|isoDateTime()
$> eventCreatedAt|addDays(7)|isoDate() + 'T07:00:00.000Z'
$> event.dueDate|subDays(1)|isoDate() + 'T07:00:00.000Z'
$> event.dueDate|isoDate()
Query Result Access:
$> plannedReminder|first()
$> plannedReminder|first()|get('notificationId')
$> plannedReminder|first()|get('plannedFor')|isoDate()
$> order.customerId
$> customer.email
$> customer.groupId
String Concatenation:
$> 'New item: ' + event.title + ' by ' + event.assignee.lastName
$> 'task-reminder-' + event.taskId
$> 'completion-reminder-{{event.orderId}}'
User Lookup:
$> responsibleUserMatch|first()
$> responsibleUser.userId
$> meta.user.userId
String Interpolation in Messages:
$> 'Appointment planned for {{event.dueDate|localDateTime()}} with: {{event.assignee.firstName}} {{event.assignee.lastName}}'
$> 'A task was assigned to {{event.assignee.firstName}} {{event.assignee.lastName}} at {{eventCreatedAt|localDate()}}...'
Checklist for Creating New Automations
- Identify the triggering event
- Determine if dependencies are needed (queries, services)
- Define query dependencies with appropriate filters
- Add validation rules (check if data exists)
- Add early exit with
stop: truefor abort conditions - Log meaningful messages for debugging
- Use
lookupfor finding users by attributes - Schedule notifications with appropriate
plannedFortimestamps - Use unique tags for notification deduplication
- Consider forEach loops for multiple items
- Handle edge cases (no user found, no data available)
Automation Categories
1. Status Change Automations
Triggered when an aggregate changes state:
Change Order Status to shippedChange Order Status to delivered
2. Notification Automations
Send immediate or scheduled notifications:
Notify team about new itemNotify manager about status change
3. Reminder Scheduling
Schedule future reminders:
Schedule Task Completion ReminderSchedule Review ReminderSchedule appointment reminder after callSchedule reminder if deadline is set
4. Reminder Discard/Cleanup
Cancel planned reminders when no longer needed:
Discard task completion reminderDiscard new item reminder if item processedDiscard new item reminder if next step is scheduledDiscard review reminder
5. Email Sending
Trigger email notifications:
Send email(multiple instances for different events)
Common Patterns
Pattern 1: Check Before Trigger
[
{
"rule": "condition",
"if_not": "$> dependency|first()",
"then": {
"log": {
"msg": "$> 'No data found. Aborting ...'"
}
},
"stop": true
},
{
"rule": "always",
"then": {
"trigger": {
"command": "CommandName",
"mapping": {
"id": "$> dependency|first()|get('id')"
}
}
}
}
]
Pattern 2: User Lookup with Validation
[
{
"rule": "always",
"then": {
"lookup": {
"users": {
"filter": {
"eq": {
"prop": "attributes.location",
"value": "$> event.locationId"
}
},
"variable": "userMatch"
}
}
}
},
{
"rule": "always",
"then": {
"assign": {
"variable": "targetUser",
"value": "$> userMatch|first()"
}
}
},
{
"rule": "condition",
"if_not": "$> targetUser",
"then": {
"log": {
"msg": "$> 'No user found. Aborting ...'"
}
},
"stop": true
},
{
"rule": "always",
"then": {
"trigger": {
"command": "SendNotification",
"mapping": {
"to": "$> targetUser.userId"
}
}
}
}
]
Pattern 3: Duplicate Prevention
[
{
"rule": "condition",
"if": "$> existingReminder|first()",
"then": {
"execute": {
"rules": [
{
"rule": "always",
"then": {
"assign": {
"variable": "existingDate",
"value": "$> existingReminder|first()|get('plannedFor')|isoDate()"
}
}
},
{
"rule": "condition",
"if": "$> existingDate == targetDate",
"then": {
"log": {
"msg": "$> 'Reminder already scheduled. Aborting ...'"
}
},
"stop": true
}
]
}
}
}
]
Pattern 4: For Each Cleanup
[
{
"rule": "condition",
"if_not": "$> items|first()",
"then": {
"log": {
"msg": "$> 'No items to process. Aborting ...'"
}
},
"stop": true
},
{
"rule": "always",
"then": {
"forEach": {
"variable": "items",
"then": {
"trigger": {
"command": "CleanupCommand",
"mapping": {
"id": "$> item|get('id')"
}
}
}
}
}
}
]
Pattern 5: Conditional Notification Scheduling
[
{
"rule": "always",
"then": {
"trigger": {
"command": "SendNotification",
"mapping": {
"notificationId": "$> uuid()",
"severity": "$> 'success'",
"tag": "$> 'immediate-notification'",
"msg": "$> 'Immediate message'",
"to": "$> userId",
"plannedFor": "$> eventCreatedAt|isoDateTime()"
}
}
}
},
{
"rule": "always",
"then": {
"trigger": {
"command": "SendNotification",
"mapping": {
"notificationId": "$> uuid()",
"severity": "$> 'warning'",
"tag": "$> 'follow-up-reminder'",
"msg": "$> 'Follow-up message'",
"to": "$> userId",
"plannedFor": "$> eventCreatedAt|addDays(1)|isoDateTime()"
}
}
}
}
]
Best Practices
- Always validate dependencies exist before using them
- Use
stop: trueafter abort conditions to prevent further execution - Log meaningful messages for debugging and monitoring
- Use unique tags for notifications to enable deduplication
- Schedule reminders at appropriate times (e.g.,
T07:00:00.000Zfor morning) - Handle missing users gracefully with log messages
- Use
forEachfor batch operations on multiple items - Check for existing reminders before scheduling duplicates
- Use severity levels appropriately (success, info, warning, error)
- Document automation purpose in the description field