How Workflow Edges Connect Nodes in the Modly Graph
In Modly, workflow edges connect nodes via the WFEdge interface which stores source and target node IDs, creating a directed graph that the execution engine traverses using helpers like resolveDataSource and reachesSceneOutput.
The lightningpixel/modly repository implements a node-based workflow system where edges define the execution flow between operations. Understanding how these edges link nodes is essential for both authoring workflows programmatically and debugging execution paths.
The WFEdge Interface Structure
The contract for workflow edges is defined in src/shared/types/electron.d.ts. Each edge acts as a directed connection between two nodes, with optional port specifiers for multi-input or multi-output nodes.
export interface WFEdge {
id: string // unique edge identifier
source: string // id of the node where the edge starts
target: string // id of the node where the edge ends
sourceHandle?: string | null // optional port on the source node (e.g. "output")
targetHandle?: string | null // optional port on the target node (e.g. "input-0")
}
This interface appears at lines 23–29 of the type definitions file. The source and target fields reference the id properties of WFNode objects, while the optional handle fields enable precise port-to-port connections required by React Flow rendering.
Creating and Storing Workflow Edges
When workflows are constructed or migrated from legacy formats, Modly generates the edge list in src/shared/stores/workflowsStore.ts. The store chains nodes sequentially by mapping each node to its successor:
const edges: WFEdge[] = allNodes.slice(0, -1).map((n, i) => ({
id: `e-${n.id}-${allNodes[i + 1].id}`,
source: n.id,
target: allNodes[i + 1].id,
}))
This logic appears at lines 152–156. The resulting array populates the workflow's edges collection, which is persisted alongside the nodes array.
Edge Sanitization and Validation
The sanitizeEdges function (lines 101–123 in the same file) enforces graph integrity through three specific safeguards:
- Dangling endpoint removal – Edges referencing non-existent source or target nodes are filtered out immediately
- Handle patching – For extension nodes, missing
sourceHandleortargetHandlevalues are populated with defaults ('output'and'input-0'respectively) to ensure React Flow can resolve ports - Type-based constraints – The system consults
NODE_TYPES_WITHOUT_TARGETandNODE_TYPES_WITHOUT_SOURCEsets to prevent creating edges that would connect to nodes lacking the required handles (for example, preventing anoutputNodefrom acting as a source)
Traversing the Graph at Runtime
During execution, the engine interprets edges as directed pathways through the workflow. The helpers in src/areas/workflows/nodeBehaviors.ts navigate these connections without modifying the graph structure.
Resolving Data Sources
The resolveDataSource function (lines 43–57) walks backward from a given node, following source references through any passthrough nodes until it locates the actual upstream data producer. This traversal relies solely on matching source IDs to node IDs in the workflow collection.
Finding Upstream Dependencies
nearestUpstreamWaits (lines 65–80) identifies the closest Wait nodes that feed into the current node. It uses the edge list to trace incoming connections recursively, gathering all branch-starter nodes that must complete before execution can proceed.
Checking Output Reachability
To determine if a node contributes to final scene output, reachesSceneOutput (lines 90–108) performs a forward traversal following target references. It respects edge direction and branch boundaries to verify whether any path from the starting node eventually terminates at a scene-output node.
Summary
- Modly stores workflow edges as
WFEdgeobjects containingsourceandtargetnode IDs, with optional handle identifiers for precise port mapping - Edge creation occurs in
workflowsStore.ts, where nodes are chained sequentially or sanitized to remove dangling references and patch missing handles - Runtime traversal uses directional edge walking via
resolveDataSource,nearestUpstreamWaits, andreachesSceneOutputto determine execution order and data dependencies - Validation constants like
NODE_TYPES_WITHOUT_TARGETprevent invalid connections during graph construction
Frequently Asked Questions
What happens if an edge references a deleted node?
The sanitizeEdges function in src/shared/stores/workflowsStore.ts automatically removes any edge whose source or target ID does not exist in the current nodes array. This prevents runtime errors during graph traversal by ensuring the edge list always references valid endpoints.
Can a node have multiple input or output edges?
Yes. The WFEdge interface supports multiple connections through the sourceHandle and targetHandle fields. A single node can be the target of multiple edges (multiple inputs) or the source of multiple edges (branching outputs), provided the node type supports the corresponding handles and passes validation against NODE_TYPES_WITHOUT_SOURCE or NODE_TYPES_WITHOUT_TARGET.
How does Modly handle edges for extension nodes that lack defined ports?
The sanitizeEdges function detects when sourceHandle or targetHandle are null on extension nodes and patches them with default values ('output' for sources, 'input-0' for targets). This ensures compatibility with React Flow's rendering engine while maintaining the directed graph structure required for execution.
What is the difference between sourceHandle and targetHandle?
sourceHandle identifies the specific output port on the source node (such as "output"), while targetHandle identifies the input port on the target node (such as "input-0"). These optional fields allow precise connections when nodes expose multiple ports, enabling complex data routing beyond simple one-to-one node linking.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →