Workflow Design¶
Overview¶
NebulaFlow workflows are directed acyclic graphs (DAGs) composed of nodes and edges that execute in a parallel, streaming fashion. The workflow engine uses a Kahn's topological sort algorithm with ordered edges to determine execution order, enabling efficient parallel execution while respecting dependencies.
Workflow Structure¶
Nodes and Edges¶
A workflow consists of: - Nodes: Individual execution units with specific types (LLM, CLI, Loop, etc.) - Edges: Connections between nodes that define data flow and execution dependencies
Each node has:
- id: Unique identifier
- type: Node type (e.g., llm, cli, loop-start)
- data: Configuration and state (title, content, active status, etc.)
- position: Visual coordinates in the webview
- selected: Selection state (UI only)
Edges define:
- id: Unique identifier
- source: Source node ID
- target: Target node ID
- sourceHandle / targetHandle: Optional handle identifiers for multi-port nodes
Execution Context¶
The workflow maintains several runtime contexts: - Node Outputs: Map of node IDs to their execution results - Variable Values: Map of variable names to their current values - Loop States: Track iteration counts and loop variables - Accumulator Values: Track accumulated values across iterations - Conditional Decisions: Store IF/ELSE branch decisions - Disabled Nodes: Nodes that should not execute (pruned branches)
Execution Model¶
Parallel Scheduler¶
The workflow engine uses a parallel scheduler that executes nodes concurrently when dependencies are satisfied. The scheduler implements Kahn's algorithm with the following optimizations:
- In-Degree Tracking: Each node tracks how many dependencies must complete before it can start
- Ready Queue: Nodes with zero in-degree are queued for execution
- Priority Sorting: Ready nodes are sorted by edge order for deterministic execution
- Concurrency Control: Per-node-type caps prevent resource exhaustion (e.g., 8 LLM nodes, 8 CLI nodes)
Execution Flow¶
1. Initialize in-degree for all nodes
2. Populate ready queue with nodes having zero in-degree
3. While ready queue is not empty:
a. Sort ready queue by edge order
b. Start nodes up to concurrency limits
c. Wait for node completion
d. Decrement in-degree of children
e. Add newly ready nodes to queue
4. Handle completion, errors, and pauses
Hybrid Execution for Loops¶
Loops require special handling because they create cycles in the execution graph:
- Pre-Loop Nodes: Nodes that execute before the loop starts
- Loop Body: Nodes inside the loop (between LOOP_START and LOOP_END)
- Post-Loop Nodes: Nodes that execute after the loop completes
The scheduler uses a hybrid approach: - Parallel execution for non-loop segments - Sequential execution within loop blocks - Loop iterations are expanded at execution time
Node Types¶
LLM Node (llm)¶
Executes language model calls with streaming output.
Configuration:
- model: Model ID from available models
- systemPromptTemplate: Optional system prompt
- timeoutSec: Request timeout (default: 300s)
- reasoningEffort: Reasoning effort level (minimal/low/medium/high)
- attachments: Image attachments
- disabledTools: Tools to disable
- dangerouslyAllowAll: Allow all tools (security flag)
Execution: - Streams assistant content (text, thinking, tool use) - Maintains thread ID for conversation history - Supports single-node and workflow execution modes
CLI Node (cli)¶
Executes shell commands with streaming output.
Configuration:
- mode: command or script
- shell: Shell type (bash/sh/zsh/pwsh/cmd)
- safetyLevel: safe or advanced
- streamOutput: Stream stdout/stderr
- stdin: Input configuration (none/parents-all/parent-index/literal)
- env: Environment variable configuration
- flags: Execution flags (exitOnError, pipefail, etc.)
Execution: - Streams output chunks to webview - Captures exit code - Supports approval workflow for unsafe commands
Loop Nodes¶
Loop Start (loop-start)¶
Initiates a loop block.
Configuration:
- iterations: Number of iterations
- loopVariable: Variable name for iteration counter
- overrideIterations: Allow iteration count override
- loopMode: fixed or while-variable-not-empty
- collectionVariable: Variable to iterate over
- maxSafeIterations: Safety limit
Execution: - Sets up loop state - Executes loop body multiple times - Updates loop variable each iteration
Loop End (loop-end)¶
Marks the end of a loop block.
Execution: - Signals loop completion - Allows post-loop nodes to start
Conditional Nodes¶
IF/ELSE Node (if-else)¶
Branches execution based on condition.
Configuration:
- truePathActive: Visual indicator for true branch
- falsePathActive: Visual indicator for false branch
Execution: - Evaluates input (truthy/falsy) - Prunes non-chosen branch - Materializes chosen branch edges
Data Nodes¶
Variable Node (variable)¶
Sets a variable value.
Configuration:
- variableName: Name of the variable
- initialValue: Optional initial value
Execution: - Evaluates template with parent inputs - Stores result in variable map - Output available to downstream nodes
Accumulator Node (accumulator)¶
Appends to a variable across iterations.
Configuration:
- variableName: Name of the accumulator variable
- initialValue: Optional initial value
Execution: - Appends input to existing value - Preserves value across loop iterations
Input Node (text-format)¶
Provides text input to the workflow.
Configuration:
- content: Text content
Execution: - Outputs content directly - Can be used as workflow input or loop override
Utility Nodes¶
Preview Node (preview)¶
Displays text content without execution.
Configuration:
- content: Text to display
Execution: - No actual execution - Used for documentation or notes
Subflow Node (subflow)¶
Executes a reusable workflow.
Configuration:
- subflowId: ID of the subflow to execute
- inputPortCount: Number of input ports
- outputPortCount: Number of output ports
Execution: - Loads subflow definition - Maps inputs/outputs - Executes subflow graph
State Management¶
Workflow State Persistence¶
Workflow state is persisted across save/load operations:
interface WorkflowStateDTO {
nodeResults: Record<string, NodeSavedState>
ifElseDecisions?: Record<string, 'true' | 'false'>
nodeAssistantContent?: Record<string, AssistantContentItem[]>
nodeThreadIDs?: Record<string, string>
}
Resume Support¶
Workflows can be resumed from any point:
interface ResumeDTO {
fromNodeId?: string
seeds?: {
outputs?: Record<string, string>
decisions?: Record<string, 'true' | 'false'>
variables?: Record<string, string>
}
}
Resume Behavior:
- Nodes before fromNodeId are not re-executed
- Seed outputs are pre-loaded into context
- Seed decisions prune branches
- Seed variables initialize variable map
Approval Workflow¶
Nodes can require user approval before execution:
- Node enters
pending_approvalstatus - User reviews command in webview
- User approves or rejects
- Execution continues or aborts
Flow Control¶
Dependency Resolution¶
Nodes execute when all dependencies are satisfied: - All parent nodes have completed - IF/ELSE decisions have been made for conditional edges - Loop iterations are complete
Error Handling¶
Fail-Fast Mode (default): - First error aborts all in-flight nodes - Workflow stops immediately
Continue-Subgraph Mode: - Errors in one branch don't affect other branches - Useful for independent subgraphs
Pause/Resume¶
Workflows can be paused: - Pause signal prevents new node starts - In-flight nodes complete normally - Workflow can be resumed later
Subflows¶
Definition¶
Subflows are reusable workflow components with: - Inputs: Named input ports - Outputs: Named output ports - Graph: Internal nodes and edges
Execution¶
Subflows execute as single nodes in parent workflows: - Inputs are mapped to internal input nodes - Internal execution follows standard rules - Outputs are collected from output nodes
Port Mapping¶
Ports are ordered by index for consistent mapping.
Best Practices¶
Design Principles¶
- Keep Nodes Small: Single responsibility per node
- Use Meaningful Names: Descriptive node titles
- Organize Visually: Group related nodes
- Document with Preview Nodes: Add notes to workflows
Performance¶
- Limit Concurrency: Use per-type caps for resource-intensive nodes
- Batch Operations: Combine related CLI commands
- Cache Results: Use variables to avoid recomputation
Safety¶
- Require Approval: Enable
needsUserApprovalfor dangerous commands - Set Timeouts: Configure timeouts for LLM nodes
- Validate Inputs: Use IF/ELSE nodes to validate data
- Limit Iterations: Set
maxSafeIterationsfor loops
Debugging¶
- Use Preview Nodes: Document expected behavior
- Check Outputs: Inspect node results after execution
- Use Single-Node Execution: Test nodes individually
- Monitor Token Counts: Track LLM usage
Protocol¶
Message Flow¶
Webview → Extension:
- save_workflow: Save current workflow
- load_workflow: Load saved workflow
- execute_workflow: Start execution
- node_approved / node_rejected: Approval responses
- execute_node: Execute single node
Extension → Webview:
- workflow_loaded: Workflow data loaded
- execution_started: Execution began
- node_execution_status: Node status update
- node_assistant_content: LLM streaming content
- execution_completed: Execution finished
Streaming¶
LLM and CLI nodes stream output in chunks:
- node_output_chunk: Individual output chunks
- node_assistant_content: Structured assistant content
Configuration¶
Environment Variables¶
- Provider credentials: Configure the selected provider through pi
/login,auth.json, or its environment variable. OPENROUTER_API_KEY: Alternative LLM providerNEBULAFLOW_DISABLE_HYBRID_PARALLEL: Disable hybrid execution (debug)
Execution Settings¶
- Concurrency: Global limit on parallel nodes
- Per-Type Caps: Limits for LLM (8) and CLI (8) nodes
- Error Policy:
fail-fastorcontinue-subgraph - Timeout: Default LLM timeout (300s)
Examples¶
Simple Linear Workflow¶
Branching Workflow¶
Loop Workflow¶
Subflow Workflow¶
Troubleshooting¶
Common Issues¶
Node Never Starts: - Check in-degree (dependencies) - Verify all parent nodes completed - Check for disabled nodes
Loop Doesn't Iterate:
- Verify iterations is set
- Check loopVariable name
- Ensure LOOP_END exists
LLM Timeout:
- Increase timeoutSec
- Check API key configuration
- Verify model availability
CLI Command Fails:
- Check safetyLevel setting
- Verify shell compatibility
- Review approval workflow
Debug Mode¶
- Single Node Execution: Test nodes individually
- Preview Nodes: Add checkpoints in workflow
- Variable Inspection: Check variable values after execution
- Token Counts: Monitor LLM usage
See Also¶
- LLM Nodes - Detailed LLM node configuration
- CLI Nodes - CLI node options and safety
- Loop Nodes - Loop patterns and best practices
- Variables & State - Variable management