# Hydra Browser Architecture This document explains the Hydra Browser architecture for a developer who knows Python but is new to frontend and Electron. It focuses on how the app is structured, how data flows, and how the main features work. ## 1. What This App Is Hydra is a **desktop app** (Electron) that renders **web pages inside a canvas of linked windows**. Each window is a React Flow node. Links can open new windows and form a graph of browsing paths. Key ideas: - **Electron** runs a desktop window using Chromium. - The **renderer** is a React app (frontend UI). - A **local proxy server** fetches web pages and injects scripts to intercept clicks. - **Zustand store** holds all app state (nodes, edges, UI state). ## 2. High-Level Architecture ```mermaid flowchart LR subgraph Electron App Main[Main Process src/main/index.js] Renderer[Renderer Process React UI] end Renderer -->|HTTP| Proxy[Local Proxy Server src/server/proxy.js] Renderer <-->|IPC| Main Proxy -->|Fetch| Internet[Websites] ``` ### Roles - **Main Process**: bootstraps Electron and starts the proxy server. - **Renderer**: React UI + state. Renders the canvas and windows. - **Proxy Server**: fetches web content, injects scripts, returns HTML to iframes. ## 3. Key Modules ### 3.1 Main Process (Electron) **File:** `src/main/index.js` Responsibilities: - Create the Electron window. - Start the local proxy server (port 3001). - Provide IPC handlers for file-based session save/load. ### 3.2 Proxy Server **File:** `src/server/proxy.js` Responsibilities: - Fetch remote pages (via Axios). - Inject a script into HTML to: - intercept clicks - intercept form submissions - intercept programmatic navigations - send `postMessage` events back to the renderer - provide page text for summaries/chat ### 3.3 Renderer **Root:** `src/renderer` Key pieces: - `components/ReactFlowCanvas.tsx`: canvas and node types - `components/BrowserWindowNode.tsx`: web window node - `components/NoteWindowNode.tsx`: notes - `components/SummaryWindowNode.tsx`: AI summary output - `components/ChatWindowNode.tsx`: AI chat window - `store/hydraStore.ts`: Zustand store (all app state) ## 4. Data Flow: Opening a Page ```mermaid sequenceDiagram participant UI as BrowserWindowNode participant Store as Hydra Store participant Proxy as Proxy Server participant Web as Website UI->>Store: addBrowserWindow(url) Store->>UI: node created (BrowserWindowNode) UI->>Proxy: GET /fetch?url=... Proxy->>Web: fetch page Web->>Proxy: HTML response Proxy->>Proxy: inject link interception script Proxy->>UI: HTML (blob URL) UI->>UI: iframe loads blob ``` ## 5. How Link Expansion Works When the injected script sees a link click or navigation, it sends: ```js window.parent.postMessage({ type: 'HYDRA_LINK_CLICK', url: 'https://example.com', openInNewWindow: true|false }, '*') ``` The renderer listens for these messages and either: - opens a new node and connects it with an edge, or - navigates within the same node ```mermaid flowchart TD Click[User clicks link] --> Script[Injected script] Script -->|postMessage| Renderer Renderer -->|openInNewWindow| StoreAdd[addBrowserWindow] Renderer -->|same window| StoreNav[navigateBrowserWindow] ``` ## 6. State Management (Zustand) **File:** `src/renderer/store/hydraStore.ts` The store keeps: - **nodes**: all windows on the canvas - **edges**: relationships between windows - **theme**: dark/light - **AI settings**: provider, API key, model - **session info**: file path + name ### Example: Creating a Browser Window Node ```ts addBrowserWindow(url, parentId?) ``` - Creates a new React Flow node - Optionally creates an edge from the parent - Re-layouts the graph so windows align ## 7. Layout Engine **File:** `src/renderer/store/hydraStore.ts` A custom layout function positions nodes: - Root nodes are stacked vertically - Children appear to the right of their parent - Subtrees never overlap ```mermaid graph LR A[Root 1] --> B[Child 1] A --> C[Child 2] D[Root 2] --> E[Child] ``` ## 8. Node Types | Type | Purpose | File | |------|---------|------| | browserWindow | Render a web page | `BrowserWindowNode.tsx` | | noteWindow | Editable note | `NoteWindowNode.tsx` | | summaryWindow | AI summary output | `SummaryWindowNode.tsx` | | chatWindow | AI chat UI | `ChatWindowNode.tsx` | ## 9. AI Features ### 9.1 Summaries - Renderer requests page text via `postMessage`. - Sends request to `/summarize` on the proxy. - Proxy calls OpenAI/Anthropic API. - Summary text displayed in a Summary node. ```mermaid sequenceDiagram participant UI as BrowserWindowNode participant Proxy as Proxy Server participant LLM as AI Provider UI->>Proxy: POST /summarize {text, url} Proxy->>LLM: summarize LLM->>Proxy: summary Proxy->>UI: summary ``` ### 9.2 Chat - Chat node sends messages to `/chat` on proxy. - Proxy adds context text and calls LLM API. ## 10. Session Files (File-Based) Sessions are saved to disk using file dialogs. No in-app storage. - **Save**: user chooses a `.hydra` file. - **Load**: user selects a `.hydra` file. Flow: ```mermaid flowchart LR UI -->|IPC| Main Main -->|showSaveDialog/openDialog| OS OS --> Main Main -->|read/write file| FileSystem ``` ## 11. Important Constraints - Some sites block iframes (`X-Frame-Options`, `CSP frame-ancestors`). - JavaScript-driven navigation can bypass the proxy if not intercepted. - Removing `allow-same-origin` increases safety but prevents direct DOM access. ## 12. Mental Model (Python Developer Friendly) Think of it as: - **Electron Main** = Python `if __name__ == '__main__':` boot process - **Renderer** = GUI app logic (like a web app) - **Proxy Server** = a local Flask server that fetches and rewrites HTML - **Zustand Store** = a global state dictionary - **React Flow** = a canvas + graph UI library ## 13. Where to Start Reading Recommended order: 1. `src/main/index.js` – app bootstrap 2. `src/server/proxy.js` – page fetching and injection 3. `src/renderer/store/hydraStore.ts` – core data model 4. `src/renderer/components/ReactFlowCanvas.tsx` – node registration 5. `src/renderer/components/BrowserWindowNode.tsx` – core window node --- If you want a deeper walkthrough of any module, ask and I’ll expand that section.