Automations
Overview
The Automations module provides a visual workflow automation engine with a node-based editor. Users create automations composed of trigger nodes, condition nodes, and action nodes connected by edges. Automations can be triggered by platform events (e.g., a new follower triggers a chat message) or manually. The module includes an execution engine that walks the node graph, evaluates conditions, executes actions via a dispatcher, and supports template variables. Execution history tracks completed steps for debugging.
Architecture
Backend
- GraphQL (
apps/api/src/graphql/automations.rs) -- Full CRUD for automations, nodes, and edges. Manual execution mutation that builds and runs the execution graph. - Database (
apps/api/src/db/automations.rs) -- PostgreSQL operations for automations, automation_nodes, and automation_edges tables. Supports bulk replace for nodes and edges. - Execution Engine (
crates/lo-automation/src/) --ActionExecutorwalks the execution graph from a trigger node, evaluates conditions, and dispatches actions.TemplateContextprovides variable interpolation.NodeTypeenum defines available node types (triggers, conditions, actions). - Dispatcher (
apps/api/src/dispatch/) --RedisActionDispatchersends action payloads via Redis pub/sub for real-time execution.
Frontend
- Node-based visual editor with a drag-and-drop canvas for creating and arranging nodes.
- Edge connections define the execution flow between nodes.
- Manual execution button triggers the automation from the UI.
API
GraphQL Queries
| Query | Permission | Description |
|---|---|---|
automations | automations:read | List all automations for the account |
automation(id: UUID) | automations:read | Get a single automation with all its nodes and edges |
GraphQL Mutations
| Mutation | Permission | Description |
|---|---|---|
createAutomation(input: CreateAutomationInput) | automations:create | Create a new automation with name and description |
updateAutomation(input: UpdateAutomationInput) | automations:edit | Update automation name, description, or enabled state |
deleteAutomation(id: UUID) | automations:delete | Delete an automation and all its nodes/edges |
saveAutomationNodes(automationId: UUID, nodes: [AutomationNodeInput]) | automations:edit | Bulk replace all nodes for an automation |
saveAutomationEdges(automationId: UUID, edges: [AutomationEdgeInput]) | automations:edit | Bulk replace all edges for an automation |
executeAutomation(id: UUID) | automations:execute | Manually execute an automation. Finds the manual_trigger node (or first trigger), builds the execution graph, and runs it. |
Input Types
AutomationNodeInput:
| Field | Type | Description |
|---|---|---|
id | UUID | Node ID (client-generated) |
nodeType | String | Node type (trigger, condition, action) |
positionX | f64 | X position in the editor canvas |
positionY | f64 | Y position in the editor canvas |
config | JSON | Node-specific configuration (default: {}) |
AutomationEdgeInput:
| Field | Type | Description |
|---|---|---|
id | UUID | Edge ID (client-generated) |
sourceNodeId | UUID | Source node ID |
targetNodeId | UUID | Target node ID |
sourceHandle | String | Source handle name (default: "output") |
targetHandle | String | Target handle name (default: "input") |
REST Endpoints
Mirror the GraphQL surface. All paths live under /v1/automations.
| Method | Path | Permission | Description |
|---|---|---|---|
GET | /v1/automations | automations:read | List automations |
POST | /v1/automations | automations:create | Create an automation |
GET | /v1/automations/{id} | automations:read | Get an automation (with nodes and edges) |
PATCH | /v1/automations/{id} | automations:edit | Update name/description/enabled |
DELETE | /v1/automations/{id} | automations:delete | Delete automation + nodes + edges |
PUT | /v1/automations/{id}/nodes | automations:edit | Bulk replace node list |
PUT | /v1/automations/{id}/edges | automations:edit | Bulk replace edge list |
POST | /v1/automations/{id}/execute | automations:execute | Run the automation manually |
Request bodies are snake_case copies of the GraphQL CreateAutomationInput / UpdateAutomationInput / AutomationNodeInput / AutomationEdgeInput.
Permissions
| Permission | Description |
|---|---|
automations:read | View automations and their configuration |
automations:create | Create new automations |
automations:edit | Edit automation metadata, nodes, edges |
automations:delete | Delete automations |
automations:execute | Manually trigger and start/stop automations |
automations:history | View automation execution history and debug logs |
Database
| Table | Database | Description |
|---|---|---|
automations | PostgreSQL | id, account_id, name, description, enabled, created_at, updated_at |
automation_nodes | PostgreSQL | id, automation_id (FK), node_type, position_x, position_y, config (JSONB), created_at |
automation_edges | PostgreSQL | id, automation_id (FK), source_node_id, target_node_id, source_handle, target_handle, created_at |
Data Flow
- User creates an automation and adds nodes (triggers, conditions, actions) via the visual editor.
- Nodes are connected with edges that define execution flow.
- Nodes and edges are saved via bulk-replace mutations (
saveAutomationNodes,saveAutomationEdges). - When a platform event matches a trigger node, or the user clicks "Execute":
- The execution graph is built from nodes and edges.
- The executor starts at the trigger node and walks the graph.
- Conditions are evaluated; actions are dispatched via
RedisActionDispatcher. - Each step is recorded for the execution result.
ExecutionResultGqlreturns whether the execution completed and how many steps ran.
Key Files
| Path | Description |
|---|---|
apps/api/src/graphql/automations.rs | GraphQL queries and mutations |
apps/api/src/db/automations.rs | Database CRUD for automations, nodes, edges |
crates/lo-automation/src/ | Execution engine, template context, node types |
apps/api/src/dispatch/ | RedisActionDispatcher for action execution |
apps/api/src/workers/automation.rs | build_execution_graph helper |
Extension Nodes
Third-party developers can create custom automation nodes via the Extension Platform. Extension nodes appear in the Automation Builder toolbar under the "Extensions" section when installed.
Node types
| Type | Description |
|---|---|
| Trigger | Starts an automation from an external event (webhook or polling) |
| Action | Performs work during automation execution |
| Logic | Branches the flow based on a condition |
Extension nodes execute in V8 isolates inside the Automation Worker service. Each node has a 2-5 second timeout depending on type.
Installation
Extension automation nodes are installed from the Extension Store like any other extension. Once installed, they appear in the Automation Builder toolbar for all automations in the account. Uninstalling removes the node from the toolbar and disables any automations that use it (with a warning notification).
Feature flag
Extension automation nodes require the feature:automation_node_extensions feature flag. This flag gates:
- Installation of
automation_nodeextensions in the store - The "Extensions" section in the Automation Builder toolbar
Webhook triggers
Extension trigger nodes can receive external webhooks. When an automation with a webhook trigger is enabled:
- A webhook URL and secret are generated
- The user configures the external service with this URL and the
X-Webhook-Secretheader - Incoming webhooks are validated and forwarded to the Automation Worker
- If the handler returns
fired: true, the automation runs
Key files
| Path | Description |
|---|---|
apps/automation-worker/ | Automation Worker HTTP service (V8 handler executor) |
crates/lo-automation-worker/ | Automation Worker library crate |
crates/lo-automation/src/executor.rs | Automation Engine with extension node dispatch |