Execution Flows
Where execution starts, and the main code paths.
This document traces several "from click to side-effect" stories so the architecture from 01-architecture.md becomes concrete.
1. Entry Points
| Component | Entry file |
|---|---|
| Electron main | apps/desktop/src/main/index.ts |
| Electron preload | apps/desktop/src/preload/index.ts |
| Electron renderer | apps/desktop/src/renderer/index.tsx |
| PTY daemon | packages/pty-daemon/src/main.ts |
| Host-service (in-proc) | packages/host-service/src/app.ts (createApp) |
| Host-service (standalone) | packages/host-service/src/serve.ts |
| Cloud API | Next.js — apps/api/src/app/ |
| Web app | Next.js — apps/web/src/app/ |
| Relay tunnel | apps/relay/src/index.ts |
| Electric proxy | apps/electric-proxy/src/index.ts (Cloudflare Worker) |
| Public SDK | packages/sdk/src/index.ts |
| CLI | packages/cli/src/ |
2. App Boot — bun run dev to a Live UI
bun run dev (root package.json)
└─ turbo run dev dev:caddy --filter=@superset/api --filter=@superset/web --filter=@superset/desktop --filter=electric-proxy --filter=//
├─ caddy run --config Caddyfile ← TLS reverse proxy for *.localhost
├─ apps/api: next dev ← cloud API
├─ apps/web: next dev ← dashboard
├─ apps/electric-proxy: wrangler dev ← Electric SQL proxy
└─ apps/desktop: electron-vite dev --watch
└─ apps/desktop/src/main/index.ts:
1. app.whenReady()
2. initTray() ← macOS menubar
3. getHostServiceCoordinator().init()
├─ scan ~/.superset/host/{org}/manifest.json
├─ health-check each
└─ for the active org: start() if not adopted
4. createWindow() ← BrowserWindow + preload
5. set up tRPC IPC handler
6. set up deep-link handler (superset://app)
└─ Renderer (BrowserWindow loads index.html):
1. apps/desktop/src/renderer/index.tsx
2. Set up TanStack Router with file-based routes
3. Set up tRPC clients (electronTrpc + localHostService)
4. Render <RouterProvider /> → routes/__root.tsx
5. routes/_authenticated/layout.tsx wires:
• CollectionsProvider (cloud sync)
• WorkspaceInitEffects (subscribes to creation progress)
• Notification subscriptions
• TanStack Query
The predev script (apps/desktop/package.json) runs clean-launch-services.ts and patch-dev-protocol.ts to keep macOS's Launch Services from binding the wrong app to superset://.
3. Workspace Creation: The Whole Story
This is the central flow of the product. It exercises essentially every component.
sequenceDiagram
autonumber
participant U as User
participant R as Renderer (React)
participant M as Electron main
participant H as Host-service
participant G as Git
participant D as Local SQLite
participant C as Cloud (Postgres)
U->>R: Click "New workspace"
R->>R: Open NewWorkspaceModal<br/>(stores/new-workspace-modal.ts)
U->>R: Type prompt + pick base branch
R->>M: electronTrpc.workspaces.create.mutate(intent=fork, …)
M->>H: tRPC: workspaceCreation.create
H->>G: git worktree add -b new origin/base
G-->>H: ok (path + branch)
H->>D: insert into worktrees + workspaces
H->>C: write v2_workspaces row (Drizzle → Postgres)
H-->>M: { workspaceId, status: "creating" }
M-->>R: workspaceId
R->>R: Navigate to /pending/{workspaceId}
H->>H: Run setup script (.superset/setup.sh)
H->>H: emit progress events
R->>H: subscribe(workspaceCreation.getProgress)
H-->>R: status: "initializing" → "ready"
R->>R: Navigate to /v2-workspace/{workspaceId}
R->>H: terminal.createOrAttach (paneId, …)
H->>H: pty-daemon: spawn shell with SUPERSET_* env
H-->>R: WS URL for I/O3.1 Modal logic — apps/desktop/src/renderer/stores/new-workspace-modal.ts
The modal stashes draft state in a Zustand store so navigation away (e.g., to log into GitHub) does not lose what the user typed. It also tracks a "pending workspace" id so a refresh can resume on /pending/{id}.
3.2 Three intents converge — apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts
// pseudo
switch (intent.kind) {
case "fork": return host.workspaceCreation.create({ baseBranch, branchName });
case "checkout": return host.workspaceCreation.checkout({ branch, baseBranchSource });
case "adopt": return host.workspaceCreation.adopt({ worktreePath });
}baseBranchSource ("local" | "remote" | "auto") is propagated end-to-end so the host doesn't re-resolve a stale upstream mid-flight.
3.3 Branch picker — searchBranches
A single procedure handles substring search, filter (local/remote), and cursor pagination. Each BranchRow carries lastCommitDate, isLocal, isRemote, recency (reflog ordinal), hasWorkspace (cloud-synced state), and worktreePath. The UI uses IntersectionObserver for infinite scroll with hover-reveal actions.
3.4 Pending page — routes/_authenticated/_dashboard/pending
Polls workspaceCreation.getProgress until status === "ready", then navigates to the workspace. Survives full app reloads because the workspace id is in the URL and the host-service is the source of truth.
4. Terminal Launch (V2)
sequenceDiagram
autonumber
participant R as Renderer
participant M as Electron main
participant H as Host-service
participant P as PTY daemon
participant A as Agent CLI
R->>M: electronTrpc.terminal.createOrAttach({ paneId, workspaceId })
M->>M: getWorkspaceTerminalContext(workspaceId)<br/>(branch, path, root, env)
M->>H: terminal.launchSession(WS upgrade)
H->>P: spawn-or-attach session
P->>A: posix_spawn shell with PATH=~/.superset/bin:$PATH<br/>SUPERSET_PANE_ID, _PORT, _WORKSPACE_ID, _HOME_DIR
A-->>P: stdout via PTY
P-->>H: NDJSON over Unix socket
H-->>R: WS frames (stdout, exit, resize ack)Key files:
apps/desktop/src/lib/trpc/routers/terminal/terminal.ts:49+— main routerpackages/host-service/src/terminal/terminal.ts— host-service routespackages/pty-daemon/src/Server/— PTY ownership + SessionStore snapshots
The "snapshot" capability in packages/pty-daemon/src/SessionStore/ lets the daemon hand a session over to a fresh daemon if it must restart — a defensive measure for daemon upgrades.
5. Agent Launch — From Prompt To Running CLI
User submits prompt (or task) in renderer
│
▼
launchAgentSession(request, ctx) ← apps/desktop/src/renderer/lib/agent-session-orchestrator/
│
├─ buildIdempotencyKey(request) ← prevents double-launches
│
├─ kind == "chat" → launchChatAdapter ← packages/chat (Mastracode runtime)
└─ kind == "terminal" → launchTerminalAdapter
│
├─ buildLaunchContext(sources) ← collect prompts/issues/PRs/attachments
│ = ContextSection[] (system | user)
├─ buildLaunchSpec(ctx, agentConfig) ← apply Mustache template per agent
│ = { systemContent, userContent, attachments[] }
├─ writeAttachmentFiles(workspace/.superset, attachments)
├─ resolve preset (claude/codex/cursor/…) ← packages/host-service/src/trpc/router/settings/agent-presets.ts
│ = { command, args, promptTransport: "argv" | "stdin", promptArgs }
├─ buildPromptCommandString(...) ← packages/shared/src/agent-prompt-launch.ts
│ = quoting-safe shell command with random-id heredoc delimiter
├─ spawn into the workspace's terminal pane
└─ status transitions queued → launching → running
5.1 Why buildPromptCommandString matters
packages/shared/src/agent-prompt-launch.ts:26-68 derives a delimiter that doesn't appear in the prompt and emits one of:
# stdin transport
claude --permission-mode acceptEdits <<'D7M0KQ'
… large prompt with backticks, $vars, even quotes …
D7M0KQ
# argv transport
gemini --approval-mode=auto_edit "$(cat <<'D7M0KQ'
… same content …
D7M0KQ
)"This is a small, focused piece of code worth reading — it's the safe way to move an arbitrary text blob from a TypeScript program into a child process's argv when you don't control the agent binary's flag set.
5.2 Launch context composition
plans/done/v2-workspace-context-composition.md documents the structured-context model:
LaunchSource[] ContextSection[] LaunchSpec
(user-prompt, github-issue, → (id, kind, scope, → { system, user,
github-pr, internal-task, label, content[], attachments[] }
attachment, agent-instructions) cacheControl)
Critical decisions:
- Scope (
system/user):agent-instructionsdefaults tosystem(cacheable across calls); everything else isuser. - Bytes, not base64 through IPC. Encode at the AI SDK provider boundary only.
- Per-agent template: Claude gets XML-tagged sections; Codex/Cursor get markdown. Configured per-agent (
contextPromptTemplate.system,.user). - File parts kept separate in
attachments[](with collision-safe deduped names), not embedded as base64 in the prompt.
This is what enables prompt caching and safe multi-agent fanout.
6. Cloud Tool Call → Device Execution
This is the path the public SDK takes for ops that must happen on a specific machine — e.g., "create a worktree in my laptop's superset repo from a CI pipeline."
sequenceDiagram
autonumber
participant SDK as SDK / CLI / MCP client
participant API as apps/api
participant DB as Postgres
participant EL as Electric proxy
participant DT as Desktop (Electron + host)
participant LDB as Desktop SQLite
SDK->>API: POST /api/trpc/agent.createWorktree
API->>DB: INSERT INTO agent_commands (target_device_id, tool, params, status='pending')
DB->>EL: replication
EL->>DT: row update via Electric subscription
DT->>LDB: read pending command
DT->>DT: execute (host-service.workspaceCreation.create)
DT->>API: tRPC: agent.updateCommand({ id, status: 'completed', result })
API->>DB: UPDATE agent_commands
API-->>SDK: poll/return resultThis pattern uses Electric SQL as a queue, leveraging row-sync rather than building a custom WebSocket protocol. Result writes go back through the regular API (no need for bidirectional sync). The relay tunnel (apps/relay) supplements this for ops that need direct tunnelled WS rather than a queue (large terminal streams, etc.).
The MCP tool catalogue lives in apps/api/MCP_TOOLS.md — 15 procedures, half cloud-immediate (tasks, members), half device-routed (workspaces, automations).
7. Chat Path
There are two chat paths today:
7.1 Local chat — host-service runs Mastracode
Renderer ──tRPC subscribe──▶ Host-service.chat.subscribe(sessionId)
│
├─ getSupersetMcpTools(headers, apiUrl) ← MCP client to /api/agent/mcp
├─ small-model resolver (Haiku / 4o-mini) ← env / OAuth / API key
└─ createMastraCode({ cwd, extraTools, observerModelId, reflectorModelId })
└─ MastracodeHarness
├─ sendMessage(payload)
├─ respondToToolApproval(decision)
├─ respondToPlanApproval(response)
├─ listMessages()
└─ getDisplayState()
7.2 Cloud chat — durable streams
Web client ──HTTP POST──▶ /api/chat/{sessionId}
│
└─ appendToStream(sessionId, event) → Durable Streams
└─ Web client GET /api/chat/{sessionId}/stream (SSE, resumable via offset/cursor)
Headers stream-next-offset, stream-cursor, stream-up-to-date, stream-closed make the SSE stream resumable across reconnects and tab-closes.
The greenfield event-sourced replacement for both is documented in plans/v2-chat-greenfield-architecture.md — single event log per session, monotonic seq, client reducer (applyEvent(state, event)), gap detection, replay. P5a (Postgres + LISTEN/NOTIFY + advisory locks) vs P5b (Cloudflare Durable Objects with hibernation) is an open decision.
8. Auth Flows
Web user signs up
Browser → /sign-in → Better Auth (apps/api /api/auth/[...all])
├─ social OAuth (GitHub/Google) → user row
├─ allowedDomains check → auto-enroll into matching org
└─ session cookie (cross-subdomain, 30d)
Desktop pairs to web account
Web user clicks "Connect desktop"
→ API generates short-lived API key (sk_live_…) in DB
→ key shown in UI; user pastes into desktop OR opens superset:// deep-link
→ Desktop posts to /api/auth/desktop/connect with key
→ API exchanges for session JWT (long-lived for desktop)
→ Desktop stores in macOS keychain (via Electron main, never host-service)
MCP / SDK call from CI
SDK sets X-API-Key: sk_live_xxx (encodes userId, orgId, defaultDeviceId)
→ /api/agent/[transport]/route.ts validates
→ context = { userId, orgId, defaultDeviceId }
→ router executes tool
9. State Transitions To Know
| Entity | States | Source |
|---|---|---|
| Workspace creation | creating → initializing → ready (or failed) | host-service runtime/; renderer stores/workspace-init.ts |
| Agent command | pending → executing → completed / failed | packages/db/src/schema/schema.ts (agent_commands.status) |
| Chat turn | (queued) → started → toolUseRequested → approval → toolUseExecuted → finished / aborted | Mastracode harness (@mastra/core) |
| Automation run | pending → completed / failed | packages/db/src/schema/schema.ts (automation_runs.status) |
| Host | online ↔ offline (heartbeat) | v2_hosts heartbeat updates |
| Integration | connected → disconnected (with disconnectedAt, disconnectReason) |
integration_connections (Linear refresh-token work in flight) |