Skip to main content

Understanding node system

The Scope node system enables third-party extensions to provide custom pipelines. This document describes the architectural design and data flows that enable node discovery, installation, and lifecycle management.

Architecture Layers

Desktop App (Electron) → Frontend (React) → Backend (FastAPI) → Nodes
Each layer has distinct responsibilities, communicating through well-defined interfaces.

Key Technologies

  • pluggy: Python hook system for pipeline registration and discovery
  • uv: Fast Python package manager for dependency resolution and installation
  • Electron IPC: Communication bridge between desktop app and frontend

System Architecture

┌─────────────────────────────────────────────────────────────────┐
│                        Desktop App (Electron)                    │
│  ┌─────────────┐    ┌──────────────┐    ┌───────────────────┐  │
│  │ Deep Links  │───▶│  IPC Bridge  │◀──▶│ Python Process    │  │
│  │ File Browse │    │              │    │ Manager           │  │
│  └─────────────┘    └──────────────┘    └───────────────────┘  │
└─────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────┐
│                         Frontend (React)                         │
│  ┌─────────────┐    ┌──────────────┐    ┌───────────────────┐  │
│  │ Settings UI │───▶│  API Client  │───▶│ State Management  │  │
│  └─────────────┘    └──────────────┘    └───────────────────┘  │
└─────────────────────────────────────────────────────────────────┘
                              │ HTTP

┌─────────────────────────────────────────────────────────────────┐
│                      Backend (FastAPI)                           │
│  ┌─────────────┐    ┌──────────────┐    ┌───────────────────┐  │
│  │  REST API   │───▶│ Node Manager │───▶│ Pipeline Registry │  │
│  └─────────────┘    └──────────────┘    └───────────────────┘  │
│                              │                                   │
│                     ┌────────┴────────┐                         │
│                     ▼                 ▼                         │
│              ┌────────────┐    ┌────────────┐                   │
│              │ Dependency │    │   Venv     │                   │
│              │ Validator  │    │ Snapshot   │                   │
│              └────────────┘    └────────────┘                   │
└─────────────────────────────────────────────────────────────────┘

Node Discovery

Nodes integrate with Scope through Python’s entry point mechanism:
  1. Nodes declare entry points in their pyproject.toml under [project.entry-points."scope"]
  2. The backend uses pluggy hooks to discover installed nodes at startup
  3. Each node implements a register_pipelines hook to register its pipeline implementations
  4. The Pipeline Registry maintains a mapping of pipeline IDs to their implementations

Node Sources

SourceDescription
PyPIStandard Python packages
GitDirect repository installation
LocalFile system paths (editable mode for development)

Installation Flow

User                Frontend              Backend              Desktop App
 │                    │                     │                      │
 │ Click Install      │                     │                      │
 │───────────────────▶│                     │                      │
 │                    │ POST /nodes       │                      │
 │                    │────────────────────▶│                      │
 │                    │                     │ Validate deps        │
 │                    │                     │────────┐             │
 │                    │                     │◀───────┘             │
 │                    │                     │ Capture venv         │
 │                    │                     │────────┐             │
 │                    │                     │◀───────┘             │
 │                    │                     │ Install via uv       │
 │                    │                     │────────┐             │
 │                    │                     │◀───────┘             │
 │                    │     200 OK          │                      │
 │                    │◀────────────────────│                      │
 │                    │ Request restart     │                      │
 │                    │─────────────────────────────────────────────▶
 │                    │                     │                      │ Respawn
 │                    │                     │                      │────────┐
 │                    │                     │                      │◀───────┘
 │                    │ Poll health         │                      │
 │                    │────────────────────▶│                      │
 │                    │ Refresh pipelines   │                      │
 │                    │────────────────────▶│                      │
Installation steps:
  1. User initiates install (UI or deep link)
  2. Frontend sends install request to backend API
  3. Backend validates dependencies won’t conflict with existing environment
  4. Backend captures current venv state (for rollback)
  5. Backend resolves and installs dependencies via uv
  6. Backend updates node registry
  7. Frontend triggers server restart
  8. Server restarts with new node loaded
  9. Frontend polls until server is healthy
  10. Frontend refreshes pipeline list
Rollback: If installation fails at any step, the venv is restored to its captured state.

Node Update Flow

The update flow has two phases: detection (happens automatically when nodes are listed) and execution (triggered by the user). The execution phase reuses the installation flow with an upgrade: true flag.

Update Detection

Frontend                        Backend
 │                                │
 │ GET /nodes                     │
 │───────────────────────────────▶│
 │                                │ For each node:
 │                                │ _check_node_update()
 │                                │────────┐
 │                                │        │ Compare installed
 │                                │        │ vs latest version
 │                                │◀───────┘
 │  Node list                     │
 │  (with update_available flags) │
 │◀───────────────────────────────│
Step by step:
  1. Frontend fetches the node list via GET /nodes
  2. Backend iterates over installed nodes and calls _check_node_update() for each
  3. For PyPI nodes, the installed version is compared against the latest version on PyPI
  4. For Git nodes, the installed commit hash is compared against the latest commit on the remote
  5. Local nodes are skipped (use Reload instead)
  6. Each node in the response includes an update_available flag
  7. Frontend displays an update badge on nodes where the flag is true

Update Execution

User       Frontend              Backend              Desktop App
 │           │                     │                      │
 │ Click     │                     │                      │
 │ Update    │                     │                      │
 │──────────▶│                     │                      │
 │           │ POST /nodes         │                      │
 │           │ {upgrade: true}     │                      │
 │           │────────────────────▶│                      │
 │           │                     │ Capture venv         │
 │           │                     │────────┐             │
 │           │                     │◀───────┘             │
 │           │                     │ Compile with         │
 │           │                     │ --upgrade-package    │
 │           │                     │────────┐             │
 │           │                     │◀───────┘             │
 │           │                     │ Sync deps            │
 │           │                     │────────┐             │
 │           │                     │◀───────┘             │
 │           │     200 OK          │                      │
 │           │◀────────────────────│                      │
 │           │ Request restart     │                      │
 │           │─────────────────────────────────────────────▶
 │           │                     │                      │ Respawn
 │           │                     │                      │────────┐
 │           │                     │                      │◀───────┘
 │           │ Poll health         │                      │
 │           │────────────────────▶│                      │
 │           │ Refresh pipelines   │                      │
 │           │────────────────────▶│                      │
Step by step:
  1. User clicks the Update button on a node
  2. Frontend sends POST /nodes with the node spec and upgrade: true
  3. Backend captures the current venv state (for rollback)
  4. Backend runs uv pip compile with --upgrade-package targeting only the node package
  5. Backend syncs the environment with the newly resolved dependencies
  6. Backend updates the node registry
  7. Frontend triggers server restart
  8. Server restarts with the updated node loaded
  9. Frontend polls until server is healthy
  10. Frontend refreshes pipeline list
Rollback: If the update fails at any step, the venv is restored to its pre-update state, just like a failed installation.

Source-Specific Update Behavior

SourceDetection MethodNotes
PyPICompares installed version against latest version on PyPIStandard version comparison
GitCompares installed commit hash against latest remote commitDetects new commits on the default branch
LocalSkippedLocal nodes use Reload instead

Uninstallation Flow

  1. User initiates uninstall
  2. Backend unloads any active pipelines from the node
  3. Backend removes node from registry
  4. Backend uninstalls package via uv
  5. Frontend triggers server restart
  6. Frontend refreshes pipeline list

Manual Reload Flow

For local/editable nodes, developers can trigger a reload to pick up code changes:
  1. Developer modifies code
  2. Developer clicks Reload button
  3. Frontend requests server restart
  4. Server restarts with fresh Python module imports
  5. Code changes take effect
In standalone mode (without the desktop app), the reload flow is the same except the server performs a self-restart instead of being respawned by the desktop app (see Standalone Mode below).

External sources can facilitate node installation via protocol URLs:
daydream-scope://install-node?package=<spec>
SourceRaw SpecEncoded URL
PyPImy-nodedaydream-scope://install-node?package=my-node
Gitgit+https://github.com/user/repo.gitdaydream-scope://install-node?package=git%2Bhttps%3A%2F%2Fgithub.com%2Fuser%2Frepo.git
Flow:
  1. External source opens the deep link URL
  2. Desktop app receives URL via OS protocol handler
  3. If app is starting: stores pending deep link for later processing
  4. Once frontend is loaded: sends action via IPC to renderer
  5. Frontend opens settings with Nodes tab and pre-filled package spec
  6. User confirms installation

Component Responsibilities

Backend Components

ComponentResponsibility
Node ManagerSingleton that manages node lifecycle (install, uninstall, update, reload)
Dependency ValidatorPre-validates that new packages won’t break existing environment
Venv SnapshotCaptures and restores environment state for safe rollback
Pipeline RegistryMaps pipeline IDs to their implementations and source nodes
REST APIExposes node operations to frontend

Frontend Components

ComponentResponsibility
Settings DialogUser interface for node management
API ClientHTTP calls to backend node endpoints
Restart CoordinatorHandles server restart and health polling
Pipeline ContextRefreshes available pipelines after changes

Desktop App Components

ComponentResponsibility
Python Process ManagerSpawns/respawns backend server, handles restart signals
Deep Link HandlerReceives and parses protocol URLs
IPC BridgeCommunicates between main process and renderer
File BrowserNative dialog for selecting local node directories
The File Browser is a desktop convenience feature. In standalone mode, users can type local paths directly into the node installation input field.

Server Restart Protocol

Managed Mode (Desktop App)

When running in the desktop app, server restarts are handled automatically:
  • Backend exits with code 42 (signals intentional restart)
  • Desktop app waits for port release
  • Desktop app respawns server process
  • Frontend polls health endpoint until ready

Standalone Mode

When running the server directly (uv run daydream-scope):
  • Unix/macOS: Uses os.execv() to replace the current process in-place
  • Windows: Spawns a new subprocess and exits the old one

Data Storage

Node state is persisted in the user’s data directory:
DataLocationPurpose
Node list~/.daydream-scope/nodes/nodes.txtInstalled package specs
Resolved deps~/.daydream-scope/nodes/resolved.txtLock file for reproducibility; baseline for update detection
Venv backup~/.daydream-scope/nodes/freeze.txtRollback state

Error Handling

The node system uses defensive error handling at each stage:
Error TypeDetectionRecovery
Dependency conflictsDry-run compilation before installInstallation blocked with clear error message
Installation failuresException during uv installVenv rolled back to pre-install state
Runtime errorsPipeline execution failurePipeline unloaded without affecting others
Network errorsHealth check timeoutsFrontend retries with exponential backoff
This multi-layer approach ensures that node operations cannot corrupt the base Scope installation.

See Also

Using Nodes

Install and manage nodes

Developing Nodes

Create your own custom pipelines

Pipeline Architecture

Technical details of the pipeline system

Tutorial: Build a VFX Node

Step-by-step tutorial building a complete node from scratch