This document provides a deep technical overview of NebulaFlow’s architecture, focusing on implementation details, code organization, and internal mechanisms. For a high-level overview, see Architecture.
NebulaFlow follows a Vertical Slice Architecture where code is organized by features (slices) rather than technical layers. This maximizes context locality and keeps all code required to understand a feature within the fewest possible files and folders.
src/
extension.ts # VS Code extension entry point
workflow/
Application/ # Orchestration and message handling
register.ts # Extension activation and webview setup
messaging/ # Protocol converters and message handling
workflow-session.ts # Workflow session management
Core/ # Pure business logic (no side effects)
models.ts # Node types and data structures
Contracts/ # Shared protocol contracts
Protocol.ts # Message types for extension-webview communication
DataAccess/ # I/O operations (file system, storage)
fs.ts # File system operations for workflows/subflows
Execution/ # Node execution logic
Application/handlers/ # Workflow execution handler
Core/engine/ # Parallel scheduler
Core/execution/ # Input evaluation, output combination
Application/node-runners/ # Individual node executors
LLMIntegration/ # LLM provider integrations (Amp, OpenRouter)
Shared/ # Generic primitives (Host, Infrastructure)
Host/ # VS Code host adapter
Infrastructure/ # Messaging, workspace management
Web/ # Webview UI (React + React Flow)
components/ # React components
nodes/ # Node UI components
services/ # Protocol communication
WorkflowApp.tsx # Main webview application
Each slice is self-contained and does not import internals from other slices. Communication happens through explicit contracts (interfaces) or events.
Requests flow through four logical stages: Entry → Application → Core → Infra.
nebulaFlow.openWorkflow creates a webview panel. The webview sends an execute_workflow message.ExecuteWorkflow.ts handler validates nodes/edges, sets up execution context, and delegates to the scheduler.evalTemplate), combine outputs (combineParentOutputsByConnectionOrder), and manage state (loop states, accumulator values).executeCLINode runs shell commands via child_process; executeLLMNode calls Amp SDK; safePost sends messages to the webview.src/extension.ts → workflow/Application/register.tsworkflow/WorkflowExecution/Application/handlers/ExecuteWorkflow.tsworkflow/WorkflowExecution/Core/execution/inputs.ts, workflow/WorkflowExecution/Core/execution/combine.tsworkflow/WorkflowExecution/Application/node-runners/run-cli.ts, workflow/WorkflowExecution/Application/node-runners/run-llm.tsNebulaFlow uses a parallel scheduler that executes nodes when their dependencies are satisfied. The scheduler is implemented in workflow/WorkflowExecution/Core/engine/parallel-scheduler.ts.
Key Concepts:
WorkflowNodes objects.Algorithm:
loop-start, loop-end) manage iteration counts via loopStates.Code Reference: workflow/WorkflowExecution/Core/engine/parallel-scheduler.ts (lines 1–200)
Each node type has a dedicated runner that handles execution, error handling, and streaming.
| Node Type | Runner File | Key Responsibilities |
|---|---|---|
| CLI | run-cli.ts |
Spawn shell process, stream stdout/stderr, handle approval |
| LLM | run-llm.ts |
Call Amp/OpenRouter SDK, stream assistant content, manage chat history |
| If/Else | run-if-else.ts |
Evaluate condition, route execution path |
| Loop Start/End | run-loop-start.ts, run-loop-end.ts |
Manage iteration count, loop variable |
| Input/Text | run-input.ts |
Provide static text input |
| Accumulator | run-accumulator.ts |
Concatenate inputs into variable |
| Variable | run-variable.ts |
Set variable value from template |
| Preview | run-preview.ts |
Display data in execution panel |
| Subflow | run-subflow.ts |
Execute saved workflow as subgraph |
Approval System: CLI nodes require explicit user approval before execution. The node enters pending_approval state; the webview displays a prompt; user approves (node_approved) or rejects (node_rejected).
Execution state is stored in IndexedExecutionContext:
interface IndexedExecutionContext {
nodeOutputs: Map<string, string | string[]>
nodeIndex: Map<string, WorkflowNodes>
edgeIndex: IndexedEdges
loopStates: Map<string, { currentIteration: number; maxIterations: number; variable: string }>
accumulatorValues?: Map<string, string>
cliMetadata?: Map<string, { exitCode: string }>
variableValues?: Map<string, string>
ifelseSkipPaths?: Map<string, Set<string>>
}
Pause/Resume: Workflows can be paused and resumed from any node. The ResumeDTO contains seeds for variables, decisions, and outputs.
The extension and webview communicate using a custom workflow message protocol defined in workflow/Core/Contracts/Protocol.ts. All messages extend BaseWorkflowMessage with a type field.
execute_workflow, node_approved).execution_started, node_execution_status).execute_workflow with nodes/edges.executeCLINode.executeCLINode checks needsUserApproval; if true, sends node_execution_status with status: 'pending_approval'.node_approved.node_output_chunk events.node_execution_status with status: 'completed'.WorkflowPayloadDTO: Contains nodes, edges, state, resume metadata.NodeExecutionPayload: Node status, result, error information.AssistantContentItem: Structured LLM content (text, thinking, tool use).SubflowDefinitionDTO: Reusable workflow definition.The webview is built using Vite with React plugin. Configuration: workflow/Web/vite.config.mts.
Build Process:
npm run build:webview → Vite bundles React app into dist/webviews/.workflow.html and static assets.workflow.html into webview panel.The extension is bundled using esbuild. Configuration: scripts/build-extension.ts.
Build Process:
npm run build:ext → esbuild bundles extension + SDK into dist/extension.js.sync:sdk script copies Amp SDK from upstream location.AMP_API_KEY, OPENROUTER_API_KEY are required at runtime.npm run build triggers both webview and extension builds, plus SDK sync.
npm run check runs TypeScript 5.x type checking. Configuration: tsconfig.json.
Biome is configured for linting and formatting. Commands:
npm run lint – lint onlynpm run format – format codenpm run biome – auto-fix lint issuesAMP_API_KEY environment variable.npm run watch:webview – watch webview changes (Vite HMR).Safety Levels: Configurable safety levels (safe |
advanced). |
Users can save custom node configurations. Nodes are stored as JSON definitions and loaded via provide_custom_nodes event.
Reusable workflow components defined with input/output ports. Stored in workspace or global storage.
Message types are extensible via union types. New commands/events can be added without breaking existing functionality. Backward compatibility maintained through versioning.
npm run check ensures TypeScript correctness.npm run lint enforces code style and catches potential errors.