Skip to main content

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. A manual run reports its outcome inline as ExecutionResultGql (automationId, completed, steps); runs are not persisted to an execution-history table.

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.
  • REST (apps/api/src/routes/automations.rs) -- parity endpoints under /v1/automations.
  • 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/) -- ActionExecutor walks the execution graph from a trigger node, evaluates conditions, and dispatches actions. TemplateContext provides variable interpolation. NodeType enum defines available node types (triggers, actions, logic).
  • Dispatcher (apps/api/src/dispatch.rs) -- RedisActionDispatcher sends 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

Every automation query and mutation additionally requires the feature:automation feature flag on the account. When the flag is off the operation fails on both protocols before any permission check runs.

QueryPermissionDescription
automationsfeature:automation + automations:readList all automations for the account
automation(id: UUID!)feature:automation + automations:readGet a single automation with all its nodes and edges
automationWebhookUrl(installId: UUID!, automationId: UUID!)feature:automationWebhook URL + secret for an extension trigger node (see Webhook triggers)

GraphQL Mutations

MutationPermissionDescription
createAutomation(input: CreateAutomationInput!)automations:createCreate a new automation with name and description. Returns AutomationGql!.
updateAutomation(input: UpdateAutomationInput!)automations:editUpdate automation name, description, or enabled state. Returns AutomationGql!.
deleteAutomation(id: UUID!)automations:deleteDelete an automation and all its nodes/edges. Returns AutomationDeleteResult!.
saveAutomationNodes(automationId: UUID!, nodes: [AutomationNodeInput!]!)automations:editBulk replace all nodes for an automation. Returns [AutomationNodeGql!]!.
saveAutomationEdges(automationId: UUID!, edges: [AutomationEdgeInput!]!)automations:editBulk replace all edges for an automation. Returns [AutomationEdgeGql!]!.
executeAutomation(id: UUID!)automations:executeManually execute an automation. Finds the manual_trigger node (or first trigger), builds the execution graph, and runs it. Returns ExecutionResultGql!.

Built-in node types

nodeType on a saved node is one of the NodeType variants in crates/lo-automation/src/types.rs:

GroupNode types
Triggercommand_trigger, keyword_trigger, event_trigger, timer_trigger, manual_trigger, webhook_trigger, extension_trigger
Actionchat_message, discord_post, obs_control, streamer_bot, spotify_control, overlay_alert, webhook_call, moderation, set_variable, get_variable, extension_action
Logiccondition, delay, random, loop, extension_logic

The three extension_* variants are the dispatch points for extension nodes.

Input Types

AutomationNodeInput:

FieldTypeDescription
idUUIDNode ID (client-generated)
nodeTypeStringNode type (trigger, condition, action)
positionXf64X position in the editor canvas
positionYf64Y position in the editor canvas
configJSONNode-specific configuration (default: {})

AutomationEdgeInput:

FieldTypeDescription
idUUIDEdge ID (client-generated)
sourceNodeIdUUIDSource node ID
targetNodeIdUUIDTarget node ID
sourceHandleStringSource handle name (default: "output")
targetHandleStringTarget handle name (default: "input")

REST Endpoints

Mirror the GraphQL surface. All paths live under /v1/automations.

MethodPathPermissionDescription
GET/v1/automationsautomations:readList automations
POST/v1/automationsautomations:createCreate an automation
GET/v1/automations/{id}automations:readGet an automation (with nodes and edges)
PATCH/v1/automations/{id}automations:editUpdate name/description/enabled
DELETE/v1/automations/{id}automations:deleteDelete automation + nodes + edges
PUT/v1/automations/{id}/nodesautomations:editBulk replace node list
PUT/v1/automations/{id}/edgesautomations:editBulk replace edge list
POST/v1/automations/{id}/executeautomations:executeRun the automation manually

Request bodies are snake_case copies of the GraphQL CreateAutomationInput / UpdateAutomationInput / AutomationNodeInput / AutomationEdgeInput.

WebSocket

ChannelGateFeature flag
automations:{account_id}automations:read on the account in the channel keyfeature:automation

An account without feature:automation is rejected at subscribe time, so the stream cannot be reached by crafting the channel name. The gate lives in channel_gate_for / channel_feature_for (crates/lo-websocket/src/gate.rs).

Permissions

PermissionDescription
automations:readView automations and their configuration
automations:createCreate new automations
automations:editEdit automation metadata, nodes, edges
automations:deleteDelete automations
automations:executeManually trigger and start/stop automations

There is no automations:history permission: no execution-history surface exists — executeAutomation returns its results inline and they are not persisted. The former automations:history account permission was removed in ZAF-1094 (it gated nothing).

Database

TableDatabaseDescription
automationsPostgreSQLid, account_id, name, description, enabled, created_at, updated_at
automation_nodesPostgreSQLid, automation_id (FK), node_type, position_x, position_y, config (JSONB), created_at
automation_edgesPostgreSQLid, automation_id (FK), source_node_id, target_node_id, source_handle, target_handle, created_at

Data Flow

  1. User creates an automation and adds nodes (triggers, conditions, actions) via the visual editor.
  2. Nodes are connected with edges that define execution flow.
  3. Nodes and edges are saved via bulk-replace mutations (saveAutomationNodes, saveAutomationEdges).
  4. 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.
  5. ExecutionResultGql returns whether the execution completed and how many steps ran.

Key Files

PathDescription
apps/api/src/graphql/automations.rsGraphQL queries and mutations
apps/api/src/db/automations.rsDatabase CRUD for automations, nodes, edges
crates/lo-automation/src/Execution engine, template context, node types (types.rs)
apps/api/src/routes/automations.rsREST endpoints
apps/api/src/dispatch.rsRedisActionDispatcher for action execution
apps/api/src/workers/automation.rsbuild_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

TypeDescription
TriggerStarts an automation from an external event (webhook or polling)
ActionPerforms work during automation execution
LogicBranches 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_node extensions 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:

  1. A webhook URL and secret are generated
  2. The user configures the external service with this URL and the X-Webhook-Secret header
  3. Incoming webhooks are validated and forwarded to the Automation Worker
  4. If the handler returns fired: true, the automation runs

Key files

PathDescription
apps/automation-worker/Automation Worker HTTP service (V8 handler executor)
crates/lo-automation-worker/Automation Worker library crate
crates/lo-automation/src/executor.rsAutomation Engine with extension node dispatch