Renderer Process
React app structure, contexts, components, and hooks
The renderer is a React 19 single-page application built with Vite and Tailwind. It communicates with the main process exclusively via window.cosmoDesktop (the preload bridge). Source lives in packages/desktop/src/renderer/src/.
Entry Point (main.tsx)
Before React mounts, main.tsx reads localStorage for cosmo-theme and cosmo-preset and applies them to document.documentElement. This prevents a flash of unstyled content on load.
PostHog is initialised here with the app's analytics key.
If VITE_CLERK_PUBLISHABLE_KEY is set, the app renders AuthProvider → App. Otherwise it renders DevApp (development bypass mode).
Contexts
AuthContext (context/AuthContext.tsx)
Manages authentication state for the entire app.
| Value | Type | Description |
|---|---|---|
isLoaded | boolean | Auth state has been fetched from main |
isSignedIn | boolean | User is authenticated |
token | string? | Cosmo JWT |
user | AuthUser? | { id, email, name, avatarUrl } |
org | AuthOrg? | { id, name, slug } |
role | string? | OWNER / ADMIN / MEMBER |
plan | string? | Active billing plan |
onboardingCompleted | boolean | Whether onboarding is done |
login() | fn | Calls window.cosmoDesktop.auth.login() |
logout() | fn | Calls window.cosmoDesktop.auth.logout() |
getToken() | () => string | Returns the current token |
On mount it calls window.cosmoDesktop.auth.get() and subscribes to auth:changed events (fired after deep-link login).
Hook: useDesktopAuth()
ChatContext (context/ChatContext.tsx)
The most complex context — manages sessions, streaming, and model selection.
Session state:
| Value | Type | Description |
|---|---|---|
sessions | SessionInfo[] | All chat sessions |
activeSessionId | string? | Currently open session |
messages | DisplayMessage[] | Messages for active session |
isStreaming | boolean | A response is in flight |
streamingText | string | Accumulated text so far |
streamSegments | StreamSegment[] | Typed segments (thinking, text, tool, advisory) |
contextUsage | { usedTokens, maxTokens, percentage } | Token meter |
activeModel | ModelInfo? | Selected model |
availableModels | ModelInfo[] | All available models |
onboardingSessionId | string? | Special onboarding session |
Methods:
| Method | Description |
|---|---|
createSession(opts?) | Create and switch to a new session |
switchSession(id) | Load a different session |
deleteSession(id) | Delete and switch to another |
sendMessage(content) | Send and stream response |
stopGeneration() | Abort the active stream |
switchModel(modelId) | Change active model |
Stream segments are built incrementally as chat:event IPC events arrive:
| Segment type | Description |
|---|---|
thinking | Extended thinking content (shown collapsed) |
text | Plain assistant text (Markdown rendered) |
tool_call | Tool invocation display |
tool_result | Tool execution result |
tool_confirm | Awaiting user approval |
advisory:next_actions | Suggested next steps |
advisory:heads_up | Warning or notice card |
advisory:connector_required | Prompt to add a connector |
When the final text contains [ONBOARDING_COMPLETE], the context strips the sentinel and calls onboarding.handleComplete(sessionId).
Hook: useChatContext()
AppModeContext (context/AppModeContext.tsx)
Provides { isClerkMode, orgId, userId } throughout the app. Set once at startup from AuthContext.
Hook: useAppMode()
ThemeContext (context/ThemeContext.tsx)
Manages visual theme:
| Value | Description |
|---|---|
theme | 'light' / 'dark' |
preset | 'chalk' / 'paper' / 'dusk' / 'ledger' / 'atelier' / 'mono' |
setTheme(t) | Update and persist theme |
setPreset(p) | Update and persist preset |
Applies classes to document.documentElement and syncs values to PostHog person properties.
Hook: useTheme()
Pages
HomePage (pages/HomePage.tsx)
The main authenticated layout. Three panes:
┌──────────────────────────────────────────────────────┐
│ Titlebar (hamburger + window controls) │
├──────────┬──────────────────────┬───────────────────┤
│ │ │ │
│ Sidebar │ ChatPanel │ HubPanel │
│ (52–256px│ │ (resizable) │
│ toggle) │ │ │
└──────────┴──────────────────────┴───────────────────┘- Sidebar collapses to icon-only mode (52 px) on toggle.
- The
ResizeHandlebetween Chat and Hub lets users drag to adjust the Hub width (default 60% of remaining space, min 280 px). - Switching to
'customize'view hidesChatPaneland showsCustomizePage. - Listens for
cosmo:open-integrationscustom DOM event to jump directly to the Integrations tab.
LoginPage (pages/LoginPage.tsx)
Shown when isSignedIn is false. Shows the Cosmo logo and a Sign in with browser button that calls window.cosmoDesktop.auth.login().
In dev mode (DevApp), shows a mock form for local testing.
Key Components
ChatPanel (components/chat/ChatPanel.tsx)
- Renders
DisplayMessagelist with Markdown support. - Shows thinking blocks (collapsible), tool calls, tool confirmation dialogs, and advisory cards.
- Auto-scrolls to the latest message.
- Textarea with auto-resize (max 160 px height), Shift+Enter for newline, Enter to send.
- Context meter at the bottom shows token usage percentage.
- Model selector (hidden when
VITE_HIDE_MODEL_SELECTORis set). - Stop button during streaming.
- Filters
systemrole messages from display.
Sidebar (components/sidebar/Sidebar.tsx)
- New session button at the top.
- Session search input.
- Sessions grouped by time: Today / Yesterday / Older.
- Delete button on session hover.
- Customize toggle button.
- User menu (bottom): profile, usage modal, manage org (opens web), reset onboarding (dev only), sign out.
- Trial reminder card + Upgrade button if on free or trial plan.
- Update card when a new version is available.
HubPanel (components/hub/HubPanel.tsx)
The right-side panel with multiple views:
| View | Description |
|---|---|
| Dashboard | Stat cards (Open Tasks, Due Today, Completed, Workspaces), focus task list, status breakdown chart |
| Tasks | Full task list with filters (All / Mine / Unassigned), show/hide completed |
| Team Hub | Workspaces list, team tasks, member roster |
| Artifact viewer | Embedded <iframe> rendering the HTML artifact |
| Connectors | Browse and add integrations grouped by category |
Auto-navigates to Artifact view when artifacts:created is received.
CustomizePage (components/customize/CustomizePage.tsx)
Two tabs:
- Integrations — Add/remove MCP connectors, see connection status.
- Appearance — Theme (dark/light) + preset picker (chalk, paper, dusk, ledger, atelier, mono).
Hooks
useOnboardingChat (hooks/useOnboardingChat.ts)
Controls the onboarding session lifecycle.
| Value / Method | Description |
|---|---|
needsOnboarding | true if user is incomplete, or admin and org is incomplete |
initOnboarding(api) | Creates onboarding session, sends [SYSTEM: BEGIN_ONBOARDING] trigger |
handleComplete(sessionId) | Extracts memory, marks user/org complete, seeds org data |
skipOnboarding() | Mark complete without memory extraction |
The onboarding session ID is persisted to localStorage so the same session is resumed on restart.
useOnboardingStatus (hooks/useOnboardingStatus.ts)
Loads UserProfile and OrgOnboarding from the main process.
| Hook | Returns |
|---|---|
useUserOnboarding(userId) | { isLoading, isComplete, profile, refetch } |
useOrgOnboarding(orgId) | { isLoading, isComplete, data, refetch } |
Onboarding Prompt (lib/onboardingPrompt.ts)
Builds the AI system prompt used in the onboarding session. The prompt:
- Greets the user by name.
- Steps through: welcome → user background → org info (admin only) → pain points → preferences → wrap-up.
- Uses a different flow for org creators vs. invited members.
- Terminates with
[ONBOARDING_COMPLETE]sentinel when complete. - Allows the user to skip at any point.