nebulaflow

Technical Architecture

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.

Codebase Organization: Vertical Slice Architecture (VSA)

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.

Directory Structure

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

Slice Boundaries

Each slice is self-contained and does not import internals from other slices. Communication happens through explicit contracts (interfaces) or events.

Flow Model (REPR)

Requests flow through four logical stages: Entry → Application → Core → Infra.

Example: Executing a Workflow

  1. Entry: VS Code command nebulaFlow.openWorkflow creates a webview panel. The webview sends an execute_workflow message.
  2. Application: ExecuteWorkflow.ts handler validates nodes/edges, sets up execution context, and delegates to the scheduler.
  3. Core: Pure functions evaluate inputs (evalTemplate), combine outputs (combineParentOutputsByConnectionOrder), and manage state (loop states, accumulator values).
  4. Infra: executeCLINode runs shell commands via child_process; executeLLMNode calls Amp SDK; safePost sends messages to the webview.

Code References

Execution Engine

Parallel Scheduler

NebulaFlow 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:

Algorithm:

  1. Build indexes for nodes and edges.
  2. Compute in-degree for each node (number of incoming edges).
  3. Nodes with zero in-degree are scheduled immediately.
  4. When a node completes, decrement in-degree of its children; schedule when zero.
  5. Loop nodes (loop-start, loop-end) manage iteration counts via loopStates.

Code Reference: workflow/WorkflowExecution/Core/engine/parallel-scheduler.ts (lines 1–200)

Node Runners

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).

State Management

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.

Protocol

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.

Message Flow

  1. Webview → Extension: Commands (e.g., execute_workflow, node_approved).
  2. Extension → Webview: Events (e.g., execution_started, node_execution_status).

Example: CLI Node Execution

  1. Webview sends execute_workflow with nodes/edges.
  2. Extension validates, starts parallel scheduler.
  3. Scheduler selects CLI node, calls executeCLINode.
  4. executeCLINode checks needsUserApproval; if true, sends node_execution_status with status: 'pending_approval'.
  5. Webview shows approval prompt; user clicks approve → sends node_approved.
  6. Extension spawns shell process, streams node_output_chunk events.
  7. On completion, sends node_execution_status with status: 'completed'.

Payload Types

Build System

Webview Build (Vite)

The webview is built using Vite with React plugin. Configuration: workflow/Web/vite.config.mts.

Build Process:

  1. npm run build:webview → Vite bundles React app into dist/webviews/.
  2. Output includes workflow.html and static assets.
  3. Extension loads workflow.html into webview panel.

Extension Build (esbuild)

The extension is bundled using esbuild. Configuration: scripts/build-extension.ts.

Build Process:

  1. npm run build:ext → esbuild bundles extension + SDK into dist/extension.js.
  2. SDK sync: sync:sdk script copies Amp SDK from upstream location.
  3. Environment variables: AMP_API_KEY, OPENROUTER_API_KEY are required at runtime.

Full Build

npm run build triggers both webview and extension builds, plus SDK sync.

Development Workflow

Type Checking

npm run check runs TypeScript 5.x type checking. Configuration: tsconfig.json.

Linting & Formatting

Biome is configured for linting and formatting. Commands:

Debugging

  1. Set AMP_API_KEY environment variable.
  2. Launch VS Code extension host (F5).
  3. Open NebulaFlow panel.
  4. Test workflows with LLM/CLI nodes.

Watching

Security

CLI Execution

LLM Integration

File System

Extensibility

Custom Nodes

Users can save custom node configurations. Nodes are stored as JSON definitions and loaded via provide_custom_nodes event.

Subflows

Reusable workflow components defined with input/output ports. Stored in workspace or global storage.

Protocol Extensions

Message types are extensible via union types. New commands/events can be added without breaking existing functionality. Backward compatibility maintained through versioning.

Testing Strategy

Type Checking

Linting

Manual Testing

Future Automated Tests

References