-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture Overview
How the codebase is laid out and how the major subsystems fit together. Useful before you start hacking on ClusterSpace.
Standard Electron 3-process model:
┌──────────────────────────────────────────────────────────────────┐
│ Main process (Node.js) │
│ - src/main/index.ts — entry, IPC handlers │
│ - src/main/pty-manager.ts — node-pty pool │
│ - src/main/workspace-store.ts — electron-store backed │
│ - src/main/ai-manager.ts — LLM streaming, tool exec │
│ - src/main/goal-runner.ts — autonomous loop │
│ - src/main/browser-pane-registry.ts— WebContents inventory │
│ - src/main/ai-tools/... — tool registry + impls │
└─────────────────┬────────────────────────────────────────────────┘
│ IPC (contextBridge)
┌─────────────────┴────────────────────────────────────────────────┐
│ Preload (sandboxed Node bridge) │
│ - src/preload/index.ts — typed window.electronAPI │
└─────────────────┬────────────────────────────────────────────────┘
│ window.electronAPI.*
┌─────────────────┴────────────────────────────────────────────────┐
│ Renderer (Chromium + React) │
│ - src/renderer/App.tsx — root │
│ - src/renderer/context/* — global state via React │
│ - src/renderer/components/* — UI surface │
│ - src/renderer/hooks/* — useTerminal, shortcuts │
└──────────────────────────────────────────────────────────────────┘
| File | Responsibility |
|---|---|
index.ts |
App lifecycle, IPC handler registration, store instantiation |
pty-manager.ts |
Spawn / kill / read / write PTYs; per-pane scrollback buffer; background/foreground for workspace switches |
workspace-store.ts |
Workspaces, panes, grid config, settings, window bounds — all via electron-store |
credentials-store.ts |
SSH server passwords (safeStorage) |
browser-pane-registry.ts |
Map<paneId, WebContents> for routing browser tool calls |
browser-store.ts |
Browser tabs, bookmarks, history, downloads, find-in-page state |
browser-credentials-store.ts |
Saved logins (safeStorage) |
browser-recipes.ts |
Stored recipes + recipe runner |
browser-action-log.ts |
500-entry ring buffer of browser tool calls |
browser-approval.ts |
Regex-based legacy approval gate for risky browser actions |
cdp-helpers.ts |
Chrome DevTools Protocol helpers for trusted input events |
ai-store.ts |
AI providers (API keys via safeStorage), active provider |
ai-memory-store.ts |
Conversation history, per (provider, workspace, pane) keying |
ai-manager.ts |
Stream messages, build tool context, dispatch tools, build vision helpers |
agent-store.ts |
Per-pane agent state |
orchestration-store.ts |
Multi-pane orchestration goals + event log |
goal-policy.ts |
Risk-level evaluator + per-tool permissions table |
goal-store.ts |
Persistent goal checkpoints + step log (50-goal cap) |
goal-runner.ts |
The autonomous loop, transient tools, critic, verification |
config-loader.ts |
Loads personas/skills/tasks from resources/defaults/ and <userData>/clusterspace-data/config/
|
legacy-rename.ts |
One-time migration from fleet-term-data/ → clusterspace-data/ |
ai-tools/*.ts |
Tool implementations grouped by category, registered into toolRegistry
|
ai-tools/plugin-loader.ts |
Hot-reload user plugin tools from <userData>/.../config/tools/*.js
|
| File | Responsibility |
|---|---|
App.tsx |
Root component; mounts contexts and dashboards |
context/WorkspaceContext.tsx |
Active workspace + workspaces array + grid/pane mutations |
context/AIContext.tsx |
Conversation state, streaming, tool auto-loop (chat panel) |
context/AgentContext.tsx |
Agent states map, active orchestration goal, event log |
hooks/useTerminal.ts |
xterm.js lifecycle wired to PTY IPC |
hooks/useKeyboardShortcuts.ts |
Global hotkey dispatcher |
components/PaneGrid.tsx |
Grid layout + drag-resize + drag-swap |
components/TerminalPane.tsx (+ TerminalTabContent.tsx) |
Terminal pane (per-pane tabs) |
components/BrowserPane.tsx |
Browser pane (webview wrapper, chrome controls, tabs) |
components/AIChatPanel.tsx |
Floating AI chat panel |
components/GoalDashboard.tsx (+ GoalCreateDialog.tsx) |
Goal runner UI |
components/FleetDashboard.tsx |
Multi-pane orchestration dashboard |
components/PaneLabel.tsx / PaneLabelWithAgent.tsx
|
Per-pane label with agent status |
components/CommandPalette.tsx |
Ctrl+P searchable actions |
components/StatusBar.tsx |
Bottom bar with workspace, broadcast, Fleet, Goals, settings, memory chips |
src/shared/types.ts — single file with every cross-process type:
-
GridConfig,PaneConfig,WorkspaceConfig,WindowState,AppSettings -
AIProviderConfig,AISettings,AIMessage,AIToolCall,AIToolResult,AIToolDefinition,PagedTextResult -
PaneAgentState,AgentTask,AgentStatus,OrchestrationGoal,OrchestrationEvent -
GoalStatus,GoalRisk,SuccessCriterion,GoalPolicy,GoalStep,GoalCheckpoint,GoalRunnerEvent -
BrowserContentResult,BrowserActionResult,Bookmark,HistoryEntry,DownloadInfo,BrowserCredential[Meta] -
IPC_CHANNELS(all string constants) -
DEFAULT_AI_SYSTEM_PROMPT,DEFAULT_AI_SETTINGS,DEFAULT_TERMINAL_THEME,DEFAULT_TEMPLATES
If you change a cross-process shape, change it here once and everything that imports it stays in sync.
All renderer↔main communication goes through window.electronAPI, exposed by src/preload/index.ts via Electron's contextBridge. Channel names are constants in IPC_CHANNELS to keep typos out.
Full reference: IPC-Channels-Reference.
All persistent state uses electron-store — JSON files under <userData>/clusterspace-data/. See Data-Storage-and-Migration for the full file inventory.
Personas, skills, task templates, and plugin tools live under <userData>/clusterspace-data/config/ (user-authored) with fallback to bundled resources/defaults/ (read-only).
1. User asks AI: "list panes in workspace 1"
2. Renderer → AI_CHAT_STREAM IPC → AIManager.streamMessage
3. AIManager POSTs OpenAI-compat request → streams SSE chunks back
4. Assistant message arrives with toolCalls: [{name: 'list_panes', arguments: {}}]
5. Renderer dispatches AI_EXECUTE_TOOL for each toolCall
6. AIManager.executeTool:
a. Build ToolContext (window, ptyManager, stores, vision helpers)
b. If active goal: evaluate(name, getPermissions(name, args), policy)
- If denied: return error to model
- If needsApproval: prompt user via BROWSER_APPROVAL_REQUEST
c. Fall back to legacy approval gate (regex-based) if no policy
d. toolRegistry.dispatch(name, args, ctx)
e. Log to action log (for browser_*)
f. Truncate result if > 3000 chars
7. Tool result → AI message with role: 'tool', tool_call_id
8. Renderer re-streams with the appended messages
9. Loop until model emits no more tool_calls or 20 turns (chat panel auto-loop guard)
1. User starts goal → GoalRunner.start(input)
2. Runner creates GoalCheckpoint in goal-store
3. Runner sets policy on AIManager (gates tool dispatch)
4. Runner builds the goal prompt (instruction + criterion + contract)
5. Runner enters runLoop:
- streamMessage → assistant
- for each tool_call: dispatch (with policy enforced) + log step
- if pendingClaim: verifySuccessCriterion → completed | continue
- if pendingAbort: aborted
- every N steps: runCritic → maybe inject STUCK/MISLED or pendingClaim
- check wall-clock cap
6. Loop ends → endGoal updates status, clears policy, emits ended event
See Goal-Runner-Internals for the deep dive.
npm install # deps + native rebuild via electron-builder postinstall
npm run dev # Vite for renderer + Electron with auto-restart on main/preload changes
npm run build # tsc --noEmit + Vite production build
npm run dist # electron-builder packaged installer for current platform
npm run rebuild # force native rebuild (if node-pty fails)Vite serves the renderer at localhost:5173 in dev. The main process restarts on changes to src/main/** and src/preload/**; the renderer hot-reloads on changes to src/renderer/** and src/shared/**.
- IPC-Channels-Reference — every IPC channel + preload bridge
- Tool-Registry — how tools are registered and dispatched
- Plugin-Authoring — adding tools without recompiling
- Data-Storage-and-Migration — full electron-store file inventory
- Contributing — dev workflow + PR conventions
ClusterSpace · Issues · Releases · MIT License · Edit any page via the Edit button (top right of the wiki).
- Workspaces-and-Layout
- Terminal-Panes
- Per-Pane-Tabs
- SSH-and-tmux
- Browser-Panes
- Saved-Logins
- Command-Palette
- Broadcast-Mode
- Settings-and-Configuration
- AI-Overview
- AI-Providers
- AI-Chat-Panel
- AI-Tools-Reference
- Personas
- Skills
- Task-Templates
- Agent-Orchestration
- Fleet-Dashboard
- Goal-Runner-Overview
- Starting-a-Goal
- Success-Criteria
- Goal-Policy-and-Risk-Levels
- Critic-and-Replan
- Vision-Verification
- Goal-Dashboard