Desktop App Overview
Architecture and structure of the Cosmo Electron desktop application
The Cosmo desktop app is an Electron + React application that provides the full Cosmo workspace experience as a native desktop client on macOS and Windows. It is located at packages/desktop.
Technology Stack
| Layer | Technology |
|---|---|
| Shell | Electron |
| Renderer | React 19 + Vite |
| Styling | Tailwind CSS + Shadcn |
| Auth | Clerk (cloud) with dev-mode bypass |
| Analytics | PostHog |
| Build | electron-vite |
Multi-Process Architecture
Electron splits work across two processes:
Main Process (src/main/)
The Node.js process that owns the OS window, IPC bus, file system, and all network calls. It initialises six managers on startup:
| Manager | File | Responsibility |
|---|---|---|
ChatManager | chat-manager.ts | LLM sessions, streaming, tool execution |
ConnectorManager | connector-manager.ts | OAuth flows, MCP connector instances |
ArtifactManager | artifact-manager.ts | Local HTML artifact persistence |
OnboardingManager | onboarding-manager.ts | User profile + org data storage |
SyncManager | sync-manager.ts | Cloud pull/push + SSE change feed |
UpdateManager | update-manager.ts | Auto-update polling and installation |
Preload (src/preload/index.ts)
A context-bridge script that exposes a typed CosmoDesktopAPI to the renderer. Nothing from Node.js bleeds into the renderer directly — all communication goes through this bridge.
Renderer Process (src/renderer/src/)
A React single-page app that runs in a sandboxed Chromium context. It reads and writes state only through the preload bridge.
Application Layout
packages/desktop/
├── src/
│ ├── main/
│ │ ├── index.ts ← Entry: window, IPC handlers, auth
│ │ ├── chat-manager.ts ← Chat sessions & LLM engine
│ │ ├── artifact-manager.ts ← Local artifact storage
│ │ ├── connector-manager.ts ← MCP OAuth + instance management
│ │ ├── sync-manager.ts ← Cloud sync (pull/push/SSE)
│ │ ├── sync-client.ts ← HTTP wrapper for server API
│ │ ├── onboarding-manager.ts ← Profile + memory file storage
│ │ ├── update-manager.ts ← Auto-update lifecycle
│ │ ├── error-tracker.ts ← PostHog uncaught exception capture
│ │ └── oauth-callback-server.ts ← Local HTTP for OAuth redirects
│ ├── preload/
│ │ └── index.ts ← IPC context bridge
│ └── renderer/src/
│ ├── main.tsx ← React entry, theme bootstrap
│ ├── App.tsx ← Auth gate → home or login
│ ├── DevApp.tsx ← Dev-mode bypass (no Clerk)
│ ├── pages/
│ │ ├── HomePage.tsx ← Three-pane layout
│ │ └── LoginPage.tsx ← Sign-in UI
│ ├── context/
│ │ ├── AuthContext.tsx ← Auth state + token
│ │ ├── ChatContext.tsx ← Sessions, streaming, model
│ │ ├── AppModeContext.tsx ← orgId + userId
│ │ └── ThemeContext.tsx ← Dark/light + preset
│ ├── components/
│ │ ├── chat/ ← ChatPanel, ModelSelector, ContextMeter
│ │ ├── sidebar/ ← Session list, user menu
│ │ ├── hub/ ← HubPanel: tasks, workspaces, artifacts
│ │ └── customize/ ← Integrations + Appearance settings
│ └── hooks/
│ ├── useOnboardingChat.ts
│ └── useOnboardingStatus.ts
├── electron.vite.config.ts
└── package.jsonStartup Sequence
- Electron launches;
main/index.tscreates aBrowserWindow. - A local HTTP server starts on a random port to serve the renderer (required for Clerk cookies —
file://cannot hold cookies). - Stored auth (
userData/auth.json) is loaded and validated. If the token is expired but within the 7-day grace window, it is refreshed automatically. ChatManager,ConnectorManager,ArtifactManager,OnboardingManager,SyncManager, andUpdateManagerare initialised.SyncManager.pull()pulls the latest user profile, org onboarding data, and memory files from the cloud.- The renderer loads and React mounts. The
AuthContextfetches stored auth via the IPC bridge. - If signed in,
HomePagerenders the three-pane layout (Sidebar | Chat | Hub).
Auth Flow (Production)
- User clicks Sign in with browser on
LoginPage. - Main process opens
https://getcosmo.app/auth/desktopin the system browser. - User authenticates via Clerk on the web.
- The web app deep-links back to the desktop:
cosmo://auth?token=... - Main process handles the
cosmo://protocol, extracts the token, stores it touserData/auth.json, and emitsauth:changedto the renderer.
Dev Mode
When VITE_CLERK_PUBLISHABLE_KEY is absent, the app renders DevApp instead of App. Dev mode uses fixed orgId='dev-org' and userId='dev-user' — no Clerk dependency required for local development.