Skip to main content

Architecture Overview

Ganimede is built as a real-time collaborative 2D computational notebook with a clear separation between backend and frontend concerns. The system uses Yjs CRDTs for real-time synchronization and collaboration.

High-Level Architecture

┌─────────────────────────────────────────────────────────────┐
│                        Frontend (Svelte)                    │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
│  │  Canvas  │  │ Notebook │  │   Cell   │  │  Tissue  │   │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘   │
│          │              │              │              │     │
│          └──────────────┴──────────────┴──────────────┘     │
│                            │                                │
│                 ┌──────────▼──────────┐                     │
│                 │   Yjs WebSocket     │                     │
│                 │   Provider (Y-WS)   │                     │
│                 └──────────┬──────────┘                     │
└─────────────────────────────┼──────────────────────────────┘
                              │ WebSocket
                              │ (ws://localhost:1234)
┌─────────────────────────────▼──────────────────────────────┐
│                     Backend (Python)                        │
│  ┌─────────────────────────────────────────────────────┐   │
│  │          Ypy WebSocket Server (Port 1234)           │   │
│  │                   (YDoc sync)                       │   │
│  └────────────────────┬────────────────────────────────┘   │
│                       │                                     │
│  ┌────────────────────▼────────────────────────────────┐   │
│  │          Starlette App (Port 8000)                  │   │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐          │   │
│  │  │  Routes  │  │  WebSocket│  │  Config  │          │   │
│  │  └──────────┘  └──────────┘  └──────────┘          │   │
│  └────────────────────┬────────────────────────────────┘   │
│                       │                                     │
│  ┌────────────────────▼────────────────────────────────┐   │
│  │                  Managers                            │   │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐          │   │
│  │  │ Notebook │  │  Kernel  │  │   Comms  │          │   │
│  │  └──────────┘  └──────────┘  └──────────┘          │   │
│  └────────────────────┬────────────────────────────────┘   │
│                       │                                     │
│  ┌────────────────────▼────────────────────────────────┐   │
│  │         Jupyter Kernel Client                       │   │
│  │           (jupyter_client)                          │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

Technology Stack

Ganimede is built on top of several key technologies:
ComponentTechnologyPurpose
Backend FrameworkStarletteASGI web framework for Python
Kernel Integrationjupyter_clientExecute code in Jupyter kernels
Frontend FrameworkSvelteReactive UI components
CRDT SyncYjsConflict-free replicated data types
Code EditorMonaco EditorVS Code’s editor component

Component Responsibilities

Backend Components

  • Starlette Application: HTTP server and routing (port 8000)
  • Ypy WebSocket Server: Yjs synchronization server (port 1234)
  • Notebook Manager: Loads .ipynb files, manages cell graph structures (np_graph, pc_graph)
  • Kernel Manager: Spawns and communicates with Jupyter kernels
  • Comms Manager: WebSocket communication for control messages
  • YDoc: Shared CRDT document containing all notebook state

Frontend Components

  • Canvas: 2D workspace with pan and zoom
  • Notebook: Renders cells and manages graph visualization
  • Cell: Individual code or markdown cells with drag-and-drop
  • Tissue: Grouping container for heading cells and their children
  • Monaco Editor: Code editing with syntax highlighting
  • Stores: Svelte stores for socket, mouse, zoom, and notebook state

Request/Response Flow

1. Application Startup

# main.py startup sequence
1. Start Ypy WebSocket Server (port 1234)
2. Create YDoc (shared document)
3. Connect WebSocket Provider to YDoc
4. Initialize managers:
   - ConfigHandler
   - Kernel (with YDoc)
   - Notebook (with YDoc, kernel)
   - Comms
5. Start Starlette app (port 8000)

2. Frontend Initialization

// Frontend startup sequence
1. Load config from /config endpoint
2. Open WebSocket to ws://localhost:8000/ (Comms)
3. Create Yjs WebSocket Provider to ws://localhost:1234
4. Subscribe to YDoc changes
5. Render CanvasNotebookCells

3. Code Execution Flow

User clicks Run


Cell component


WebSocket (Comms) ──────► Notebook.queue_cell()


                          Add to run_queue


                          Kernel.execute(code)


                    Jupyter Kernel Client


                    Receive outputs (IOPub)


                    Update YDoc cell.outputs


                    Yjs sync to frontend


                    Cell component renders output

4. Real-time Collaboration Flow

User A edits cell source


Yjs YText.insert()


WebSocket Provider ──────► Ypy WebSocket Server


                          Broadcast to all clients


                    User B's WebSocket Provider


                    YDoc applies change


                    Monaco Editor updates

Data Flow

All notebook state flows through the YDoc:
  1. Frontend → YDoc: User edits trigger Yjs updates
  2. YDoc → YDoc: Ypy WebSocket Server synchronizes all clients
  3. Backend → YDoc: Kernel outputs update YDoc maps/arrays
  4. YDoc → Frontend: Yjs observers trigger Svelte reactivity

Communication Channels

Ganimede uses two separate WebSocket connections:
  1. Yjs WebSocket (port 1234): For CRDT synchronization of notebook state
  2. Comms WebSocket (port 8000): For control messages (run cell, restart kernel, etc.)
This separation allows Yjs to handle all state synchronization while Comms handles imperative operations that don’t belong in the shared state.

Next Steps

Build docs developers (and LLMs) love