cody-automation

v1.0.0
Download Skill

Cody Automation Skill - Specification for creating Automation element details in prooph board. Defines event reaction, dependencies, and automation rules for automated reactions to events.

Author prooph software GmbH
License MIT
Category cody
Element Types automation

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-dependencies blocks
  • Automation Rules — Event handling logic using cody-rules blocks and the Rule Engine, including trigger, lookup, forEach, assign, and log actions

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

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:

  1. Event Reaction - Declaration that this automation reacts to events
  2. Dependencies - External data requirements (queries, services)
  3. Automation Rules - Business logic for event handling

Related Documentation

  • Rule Engine — Details on the rule engine used for automation rules (cody-rules) including trigger, lookup, forEach, and log actions
  • JEXL Expressions — Documentation for JEXL expressions used in cody-rules and cody-dependencies code 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), and log (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: true for abort conditions
  • Log meaningful messages for debugging
  • Use lookup for finding users by attributes
  • Schedule notifications with appropriate plannedFor timestamps
  • 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 shipped
  • Change Order Status to delivered

2. Notification Automations

Send immediate or scheduled notifications:

  • Notify team about new item
  • Notify manager about status change

3. Reminder Scheduling

Schedule future reminders:

  • Schedule Task Completion Reminder
  • Schedule Review Reminder
  • Schedule appointment reminder after call
  • Schedule reminder if deadline is set

4. Reminder Discard/Cleanup

Cancel planned reminders when no longer needed:

  • Discard task completion reminder
  • Discard new item reminder if item processed
  • Discard new item reminder if next step is scheduled
  • Discard 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

  1. Always validate dependencies exist before using them
  2. Use stop: true after abort conditions to prevent further execution
  3. Log meaningful messages for debugging and monitoring
  4. Use unique tags for notifications to enable deduplication
  5. Schedule reminders at appropriate times (e.g., T07:00:00.000Z for morning)
  6. Handle missing users gracefully with log messages
  7. Use forEach for batch operations on multiple items
  8. Check for existing reminders before scheduling duplicates
  9. Use severity levels appropriately (success, info, warning, error)
  10. Document automation purpose in the description field