Cloud & Data
The web app, the API, the schema, auth, and the sync layer.
If 01-architecture.md is the desktop's anatomy, this doc is the cloud's. Two databases (cloud Postgres + per-host SQLite), a real-time row-sync layer (Electric SQL), a tunnel (Relay), a streaming layer (Durable Streams), and a broad tRPC + MCP API surface.
1. The Apps
| App | Path | Hosted on | Role |
|---|---|---|---|
| Marketing | apps/marketing/ |
Vercel | superset.sh — landing, comparisons, blog |
| Web | apps/web/ |
Vercel | app.superset.sh — auth, dashboard, agent UI, tasks, integrations |
| API | apps/api/ |
Vercel | api.superset.sh — Better Auth, tRPC, MCP transport, webhooks |
| Admin | apps/admin/ |
Vercel | Internal admin |
| Docs | apps/docs/ |
Vercel | docs.superset.sh |
| Electric proxy | apps/electric-proxy/ |
Cloudflare Worker | Subscriber for cloud Postgres → desktop, scoped per org |
| Relay | apps/relay/ |
Fly.io | WebSocket tunnel from cloud → device for SDK-routed ops |
| Streams (small) | apps/streams/ |
— | Durable streams adapter helpers |
| Mobile | apps/mobile/ |
Expo | React Native client (read-only-ish dashboard) |
| Desktop | apps/desktop/ |
electron-builder | The product |
2. Web App — apps/web/
A Next.js 16 app (file: apps/web/src/app/). It's a thin client over apps/api's tRPC — there are no server-side tRPC routers in apps/web. Auth, agents, tasks, billing, integrations all live here as routes.
Key route groups:
apps/web/src/app/
├── (auth)/sign-in ← Better Auth
├── (auth)/sign-up
├── (agents)/agents ← list of agent sessions
├── (agents)/agents/workspace/[workspaceId] ← per-workspace chat
├── (dashboard-legacy)/integrations ← GitHub/Slack/Linear setup
├── (dashboard-legacy)/settings/billing ← Stripe portal
├── tasks/[slug]
├── accept-invitation/[invitationId]
├── cli/auth/code ← device code flow for CLI
├── auth/desktop/success ← redirect target post-pair
└── oauth/consent ← Better Auth consent screen
apps/web/src/trpc/client.ts:7 — tRPC client points to ${API_URL}/api/trpc with httpBatchLink, superjson, and credentials. Same shape as the desktop's electronTrpc — that consistency is the point.
3. API App — apps/api/
The cloud's tRPC server, plus webhooks, plus MCP transports, plus Better Auth.
3.1 tRPC handler
apps/api/src/app/api/trpc/[trpc]/route.ts mounts appRouter from @superset/trpc. Context is built in apps/api/src/trpc/context.ts:
ctx = { session, activeOrganizationId, auth, headers }3.2 Routers (in packages/trpc/src/router/)
| Router | Purpose | Key procedures |
|---|---|---|
admin |
Admin-only ops | (org, billing) |
agent |
Device command status updates | updateCommand |
analytics |
PostHog event tracking | trackEvent |
apiKey |
API key lifecycle for MCP | create, revoke |
automation |
Cron-like recurring agent runs | create, list, run, setPrompt, dispatchToHost |
billing |
Stripe | getPlans, updateSeats |
chat |
Chat session CRUD | createSession, getModels |
device |
(legacy v1) | — |
host |
v2 host registration | register, list, updateOnlineStatus |
integration |
Linear/GitHub/Slack OAuth + sync | connect, sync, disconnect |
organization |
Orgs, invites, members | create, invite, list |
project |
(legacy v1) | — |
task |
Task CRUD with external sync | create, update, list, get, delete |
user |
Profile/preferences | getMe, updatePreferences |
v2Host |
v2 host registration | register, updateStatus |
v2Project |
v2 project model | create, list |
v2Workspace |
Worktree CRUD | create, list, getCurrent |
workspace |
(legacy v1) | — |
Aggregated in packages/trpc/src/root.ts.
3.3 Webhooks
/api/integrations/slack/* ← OAuth, events, mentions, home view
/api/integrations/slack/jobs/process-mention ← async Slack mention → agent invocation
/api/integrations/github/install ← App install redirect
/api/integrations/github/webhook ← PR/issue webhooks
/api/integrations/github/callback ← OAuth callback
/api/github/sync ← manual sync
The Slack mention → agent invocation path is interesting: a Slack mention hits the API, gets queued, a job processor selects a target host, writes an agent_commands row, Electric pushes it to the host, the host launches an agent in a worktree, results stream back via Durable Streams.
3.4 MCP transports
/api/agent/[transport] supports SSE / WebSocket / stdio. Auth is via API key (X-API-Key: sk_live_… encoding userId, orgId, defaultDeviceId). apps/api/MCP_TOOLS.md is the public spec for the 15 cloud-immediate + device-routed procedures.
3.5 Chat HTTP
POST /api/chat/{sessionId} ← create message
GET /api/chat/{sessionId}/stream ← SSE proxy (offset/cursor/live)
The SSE proxy returns 204 if up-to-date and forwards Authorization: Bearer ${DURABLE_STREAMS_SECRET} to the upstream Durable Streams service. See 03-llm-integration.md for the streaming details.
3.6 Automations
/api/automations/dispatch/[id] ← dispatch automation run to relay/host
/api/automations/evaluate ← evaluate rules (e.g., for Slack triggers)
4. Auth — Better Auth, not Clerk
packages/auth/src/server.ts — the canonical config. The presence of NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY in turbo.jsonc:globalEnv is legacy — the active provider is Better Auth v2.
4.1 Plugins enabled
apiKey(MCP API keys)expo(mobile)organization(orgs + members + invitations)bearer,jwtstripe(billing)
4.2 Social providers
- GitHub OAuth
- Google OAuth
- GitHub App (for repo access in integrations)
4.3 Trusted origins
- web/api/marketing/admin/desktop URLs
- Vercel preview origins
superset://app(the deep-link scheme for desktop pairing)
4.4 User creation hook
packages/auth/src/server.ts:102-150 auto-enrolls new users into matching orgs based on email domain (allowedDomains on org). Falls back to creating a personal org if no match.
4.5 Auth flows
| Flow | Where |
|---|---|
| Web: email magic link / OAuth | /sign-in → /api/auth/[...all] |
| Desktop pairing | Web issues short-lived API key → desktop posts to /api/auth/desktop/connect → JWT |
| MCP via SDK | X-API-Key (validated by API key plugin) |
| OAuth consent for Superset-as-OIDC-provider | /oauth/consent |
The session stores activeOrganizationId so a user with multi-org membership has org-scoped queries automatically.
5. Cloud Database — Postgres on Neon
Schema in packages/db/src/schema/. Core entities:
5.1 Auth (in auth.* schema)
users,sessions,accounts,organizations,members,invitations
5.2 Tasks
tasks— primary entity (schema.ts:94). Hasexternal_provider,external_id,external_url,external_key,last_synced_at,sync_errorfor two-way sync with Linear/GitHub.task_statuses— org-scoped columns (backlog/unstarted/started/completed/canceled)- Unique constraint on
(org, slug); partial unique on(org, external_provider, external_id)
5.3 Devices/hosts (v1 + v2)
- v1:
device_presence(schema.ts:262) - v2:
v2_hosts(schema.ts:429),v2_clients(per-org-user-machine),v2_users_hosts(member-host access map)
5.4 Workspaces
- v1:
projects,workspaces - v2:
v2_projects,v2_workspaces(schema.ts:565)
5.5 The command queue
agent_commands(schema.ts:299) —target_device_id,tool,params,status(pending/executing/completed/failed),resultJSON. This is the Electric-synced table.
5.6 Chat & automation
chat_sessions(schema.ts:661)automations(schema.ts:709) —rrule,target_host_id,v2_project_id,agent_configJSON,enabled,mcp_scopeautomation_runs— execution historyautomation_prompt_versions— prompt history (lets you roll back an LLM-edited automation)
5.7 Integrations
integration_connections(schema.ts:174) — provider, accessToken, refreshToken (in-flight Linear work), externalOrgId,disconnectedAt,disconnectReasonusersSlackUsers— Slack user linking
5.8 Billing
subscriptions— Stripe (org-based, plan, status, seats, trial dates)
5.9 In-flight (per plans/20260501-linear-team-entity.md)
teams— org × external (Linear) teamteam_keys— history of team key changes (withretired_atfor redirect support)team_sequences— atomic per-team counter (so identifiers areSUPER-103, not a hybrid)
6. Local Database — SQLite per host
Schema in packages/local-db/src/schema/. Roughly mirrors the cloud's "what does this machine see":
projects(schema.ts:26) —main_repo_path,default_branch,worktreeBaseDir,neonProjectId(per-project Neon for migrations)worktrees(schema.ts:68) — disk path, branch, baseBranch,git_statusJSON,github_statusJSON,createdBySupersetboolean (so adoption knows which orphans are claim-able)workspaces(schema.ts:103) — UI tabs: project_id, worktree_id, type (worktree/branch/main), branch, name, tabOrder,port_baseworkspace_sections— groupingagent_presets,agent_custom_definitionsautomation_setupsdeveloper_experience— terminal link behavior, file open modes, git preset
The host-service has its own SQLite too (per ~/.superset/host/{org}/host.db) for its own per-org state — workspace details, host registration, chat history.
7. Sync Layer
Three sync mechanisms, each scoped to a different problem:
7.1 Electric SQL — row-sync from cloud Postgres → desktop SQLite
apps/electric-proxy/src/index.ts:
- Cloudflare Worker
- Validates JWT
- Filters tables (
agent_commands,device_presence, others) byorganizationId - Caches at the CF edge (
cf: { cacheEverything: true }) - Used to pipe
agent_commandsrows from cloud to desktop
7.2 Relay tunnel — cloud → device for active calls
apps/relay/src/index.ts:20:
- Hono on Fly.io
- WebSocket
/tunnel - Devices register with JWT, relay holds the open WS
- SDK call lands at API → API decides target → API forwards via relay → device responds → relay returns
7.3 Durable Streams — append-only event log per chat session
@durable-streams/client:
- Each chat session has a stream at
/sessions/{sessionId} - Producers append events
- Consumers read with offset/cursor
- Resumable across reconnects via
stream-next-offset
The cloud chat path layers Durable Streams under SSE; the desktop chat path skips this and runs Mastracode locally (no cloud DB writes).
8. Public SDK — packages/sdk/
Exists so external code (CI, third-party tools, customers) can do what the dashboard does.
import Superset from "@superset_sh/sdk";
const client = new Superset({
apiKey: process.env.SUPERSET_API_KEY, // sk_live_…
organizationId: process.env.SUPERSET_ORGANIZATION_ID,
baseURL: "https://api.superset.sh", // optional
relayURL: "https://relay.superset.sh",
timeout: 60_000,
maxRetries: 2,
});Surface (1:1 with MCP):
tasks.create/list/retrieve/update/deleteworkspaces.list(relay-routed)projects.listhosts.listautomations.list/automations.run(id)(relay-routed)
Errors: APIError, RateLimitError, NotFoundError with parsed bodies.
The split between api-direct (immediate) and relay-routed (device-required) is explicit in the SDK so users can reason about which calls need an online host.
9. Data Flow Diagram
flowchart LR
subgraph Web["Web Browser"]
WebClient["dashboard / mobile / marketing"]
end
subgraph CloudVercel["Cloud — Vercel"]
WebApp["apps/web<br/>Next.js 16"]
APIApp["apps/api<br/>Next.js 16<br/>+ Better Auth<br/>+ tRPC<br/>+ MCP transports"]
end
subgraph CF["Cloudflare"]
ElectricProxy["apps/electric-proxy<br/>row-sync"]
end
subgraph Fly["Fly.io"]
RelayApp["apps/relay<br/>WebSocket tunnel"]
end
subgraph DS["Durable Streams (managed)"]
DurableSt["per-session event log<br/>(chat)"]
end
subgraph Neon["Neon Postgres"]
DBcloud[("@superset/db schema<br/>tasks · auth · workspaces<br/>agent_commands · automations")]
end
subgraph DesktopHost["Desktop / remote host"]
Electron["Electron main"]
HostSvc["host-service"]
SQLite[("local SQLite<br/>(local-db + host-db)")]
end
subgraph SDKBox["SDK / CLI / external MCP client"]
SDK["@superset_sh/sdk"]
end
WebClient -->|HTTPS| WebApp
WebApp -->|tRPC| APIApp
APIApp <-->|Drizzle| DBcloud
DBcloud -.replication.-> ElectricProxy
ElectricProxy -->|row sync| HostSvc
HostSvc <--> SQLite
Electron -->|tRPC IPC| HostSvc
SDK -->|HTTPS| APIApp
APIApp -->|relay| RelayApp
RelayApp <-->|WebSocket| HostSvc
APIApp -->|append| DurableSt
DurableSt -->|SSE GET| WebClient
HostSvc -->|host registration · chat| APIApp10. Operational Sketch
| Concern | Shape today |
|---|---|
| Migration safety | Drizzle: schema diffs + drizzle-kit generate — a Neon dev branch is created per migration, never the prod DB. |
| Multi-tenant isolation | organizationId everywhere; Better Auth activeOrganizationId; Electric proxy filters by org. |
| Backups | Neon point-in-time recovery (out-of-tree). |
| Observability | Sentry + PostHog. PostHog person profiles tagged with billing status (commit 48c0d1dc8). |
| Secrets | secrets table per org × project, encrypted; not loaded into Superset's main process. |
| CI | Turbo task graph + bun run lint:fix + Sherif (per ci-check skill). |
| Release | Desktop via electron-builder, canary path scripted (scripts/release-canary.sh). |
11. Most-Important Cloud-Side Files (15)
apps/api/MCP_TOOLS.md— full MCP spec for cloud toolspackages/db/src/schema/schema.ts:94— tasks (external sync model)packages/db/src/schema/schema.ts:299— agent_commands (the queue)packages/db/src/schema/schema.ts:661— chat_sessionspackages/db/src/schema/schema.ts:709— automations (rrule + agent config)packages/trpc/src/root.ts:24— appRouter aggregationpackages/auth/src/server.ts:51— Better Auth configapps/api/src/app/api/trpc/[trpc]/route.ts— tRPC HTTP handlerapps/api/src/trpc/context.ts— auth/org-scoped contextapps/web/src/trpc/client.ts:7— tRPC clientapps/relay/src/index.ts:20— relay tunnel WSapps/electric-proxy/src/index.ts:35— Electric proxy + filteringpackages/chat/src/server/trpc/service.ts— chat runtimepackages/local-db/src/schema/schema.ts:68— local worktree mirrorpackages/sdk/README.md— public SDK contract