CodeDocs Vault

Multica Repository Analysis: Architecture

High-Level Architecture

+------------------------------------------------------------------+
|                        FRONTEND MONOREPO                          |
|                                                                   |
|  +-------------------+  +-------------------+  +---------------+  |
|  |   apps/web/       |  |  apps/desktop/    |  |  apps/docs/   |  |
|  |   (Next.js 16)    |  |  (Electron 39)    |  |  (Next.js)    |  |
|  +--------+----------+  +--------+----------+  +---------------+  |
|           |                      |                                |
|  +--------v----------+  +-------v-----------+                     |
|  |  platform/        |  |  platform/        |  Platform bridges   |
|  |  (Next.js APIs)   |  |  (Electron APIs)  |  (routing, storage)|
|  +--------+----------+  +--------+----------+                     |
|           |                      |                                |
|  +--------v----------------------v----------+                     |
|  |          packages/views/                 |  Shared pages &     |
|  |   (zero next/*, zero react-router-dom)   |  components         |
|  +--------+-----------------+---------------+                     |
|           |                 |                                     |
|  +--------v--------+ +-----v---------+                            |
|  | packages/core/  | | packages/ui/  |                            |
|  | (headless logic)| | (atoms, no biz)|                           |
|  | API, stores,    | | shadcn/ui     |                            |
|  | queries, WS     | | design tokens |                            |
|  +-----------------+ +---------------+                            |
+------------------------------------------------------------------+
           |
           | HTTP/REST + WebSocket
           |
+----------v---------------------------------------------------+
|                        GO BACKEND                             |
|                                                               |
|  cmd/server/main.go                                           |
|  +----------------------------------------------------------+ |
|  |  Middleware Chain:                                        | |
|  |  RequestID -> ClientMetadata -> Logger -> Recoverer      | |
|  |  -> CSP -> CORS -> Auth -> WorkspaceMember               | |
|  +----------------------------------------------------------+ |
|                                                               |
|  +---------------+  +----------------+  +-----------------+   |
|  | handler/      |  |  service/      |  |  realtime/      |   |
|  | (HTTP/WS API) |  |  (biz logic)   |  |  (Hub + Redis)  |   |
|  +-------+-------+  +-------+--------+  +--------+--------+   |
|          |                   |                    |             |
|  +-------v-------------------v--------------------v--------+   |
|  |                    events/Bus                           |   |
|  |   (in-process synchronous pub/sub)                      |   |
|  +---------------------------------------------------------+   |
|          |                                                     |
|  +-------v-----------+                                         |
|  | pkg/db/generated/ |  sqlc-generated type-safe queries       |
|  +-------+-----------+                                         |
|          |                                                     |
+----------v-----------------------------------------------------+
           |
     +-----v------+     +-------------------+
     | PostgreSQL  |     |   Redis           |
     | (pgvector)  |     |   (optional,      |
     |             |     |    multi-node)     |
     +-------------+     +-------------------+

+------------------------------------------------------------------+
|                          DAEMON                                   |
|  cmd/multica/ (CLI + daemon mode)                                 |
|                                                                   |
|  +------------------+  +-----------------+  +-----------------+   |
|  | daemon/daemon.go |  | daemon/execenv/ |  | pkg/agent/      |   |
|  | (task polling,   |  | (work dirs,     |  | (unified agent  |   |
|  |  heartbeat,      |  |  config inject, |  |  interface for  |   |
|  |  GC)             |  |  skills)        |  |  10 providers)  |   |
|  +------------------+  +-----------------+  +-----------------+   |
|                                                                   |
|  Communicates with server via HTTP (daemon token auth)            |
+------------------------------------------------------------------+

Core Components

1. Go Server (server/cmd/server/)

Entry point: main.go:21-142

Initialization sequence:

  1. Logger init, env validation (JWT_SECRET, RESEND_API_KEY warnings)
  2. PostgreSQL connection pool
  3. Event bus creation (events.New())
  4. Realtime hub creation (realtime.NewHub())
  5. Optional Redis relay for multi-node (realtime.NewRedisRelay)
  6. Event listener registration (subscribers, activity, notifications, autopilots)
  7. Router creation with full middleware chain
  8. Background workers: runtime sweeper, autopilot scheduler, DB stats logger
  9. HTTP server start with graceful shutdown (SIGINT/SIGTERM, 10s timeout)

2. Router (server/cmd/server/router.go:57-425)

Route groups with escalating auth requirements:

Route Group Auth Level Examples
/health* None Liveness/readiness probes
/auth/* None Login, code verification, OAuth
/ws JWT/PAT in first message WebSocket upgrade
/api/daemon/* Daemon token Task claiming, progress, heartbeat
/api/me, /api/workspaces User JWT/PAT User-scoped operations
/api/issues, /api/agents, etc. User + workspace membership Workspace-scoped operations

3. Event Bus (server/internal/events/bus.go:1-89)

In-process synchronous pub/sub with panic recovery:

type Event struct {
    Type        string // "issue:created", "task:completed", etc.
    WorkspaceID string
    ActorType   string // "member", "agent", "system"
    ActorID     string
    Payload     any
    TaskID        string // scope hints for realtime routing
    ChatSessionID string
}

Events flow: Handler -> Bus.Publish() -> Listeners -> Hub.Broadcast()

Event types (from protocol/events.go): issue, task, chat, autopilot, inbox, comment, reaction, activity, agent, skill, project, member, workspace.

4. Realtime System (server/internal/realtime/)

Hub (hub.go): Manages WebSocket connections per workspace+user. Supports scoped broadcasts:

Redis Relay (redis_relay.go): Multi-node fanout via Redis Streams (max 10K entries per stream, 90s heartbeat TTL, 5min consumer sweep). Deduplication per client prevents double delivery.

Single-node mode: Hub is the sole broadcaster. No Redis needed for dev/self-host.

5. Handler Layer (server/internal/handler/)

31 handler files. Constructor at handler.go:51-68:

type Handler struct {
    Queries          *db.Queries
    DB               dbExecutor
    Hub              *realtime.Hub
    Bus              *events.Bus
    TaskService      *service.TaskService
    AutopilotService *service.AutopilotService
    EmailService     *service.EmailService
    Storage          storage.Storage
    CFSigner         *auth.CloudFrontSigner
    Analytics        analytics.Client
    // ...
}

6. Service Layer (server/internal/service/)

Thin business logic layer between handlers and database:

7. Database Layer (server/pkg/db/)

sqlc pattern: Hand-written SQL in queries/ (27 files) -> code-generated Go in generated/. Config at sqlc.yaml:

queries: "pkg/db/queries/"
schema: "migrations/"
gen:
  go:
    emit_empty_slices: true
    emit_json_tags: true

8. Daemon (server/internal/daemon/)

The daemon is the bridge between the Multica server and local agent CLIs. It runs on the user's machine.

Lifecycle (daemon.go:92-139):

  1. Resolve auth (daemon token)
  2. Probe available agent CLIs on PATH
  3. Register runtimes with server
  4. Start workspace sync, heartbeat, and GC loops
  5. Poll for pending tasks and execute them

Execution environment (execenv/):

Dependency Flow

apps/web/ ---imports---> packages/views/ ---imports---> packages/core/
                                          ---imports---> packages/ui/

apps/desktop/ ---imports---> packages/views/ (same)
                             packages/core/ (same)
                             packages/ui/ (same)

packages/core/  -- zero react-dom, zero UI libs
packages/ui/    -- zero @multica/core imports
packages/views/ -- zero next/*, zero react-router-dom

Hard boundaries enforced by design:

Data Flow: Issue Creation

User clicks "Create Issue" in UI
    |
    v
packages/views/issues/ -> useMutation(createIssue)
    |
    v
packages/core/issues/mutations.ts -> api.createIssue(params)
    |
    v
packages/core/api/client.ts -> POST /api/issues
    |                           (X-Workspace-Slug header)
    v
server: middleware.Auth -> middleware.RequireWorkspaceMember
    |
    v
handler/issue.go: CreateIssue()
    |-- queries.CreateIssue(ctx, params)
    |-- bus.Publish(Event{Type: "issue:created", ...})
    v
Event listeners:
    |-- subscriber_listener: auto-subscribe creator
    |-- activity_listener: create activity log entry
    |-- notification_listener: notify relevant users
    |-- realtime_listener: hub.BroadcastToWorkspace(ws event)
    v
WebSocket -> all connected workspace members
    |
    v
packages/core/realtime/use-realtime-sync.ts
    |-- onIssueCreated: invalidate React Query cache
    v
UI re-renders with new issue in list/board

Data Flow: Agent Task Execution

Issue assigned to agent (UI or API)
    |
    v
handler/issue.go: UpdateIssue() detects assignee change
    |-- TaskService.EnqueueTaskForIssue()
    |   |-- queries.CreateAgentTask(status: "queued")
    |   |-- bus.Publish(EventTaskDispatch)
    v
Daemon polling loop (daemon.go)
    |-- GET /api/daemon/runtimes/{id}/tasks/pending
    |-- POST /api/daemon/runtimes/{id}/tasks/claim
    v
daemon.handleTask():
    |-- execenv.Prepare() -- create work directory
    |-- execenv.InjectRuntimeConfig() -- write CLAUDE.md/AGENTS.md
    |-- execenv.InjectSkills() -- write skills to provider paths
    |-- BuildPrompt(task) -- construct initial prompt
    |-- agent.Execute(ctx, prompt, opts) -- spawn CLI process
    v
Agent CLI runs (e.g., claude with stream-json):
    |-- Reads CLAUDE.md for environment context
    |-- Runs `multica issue get <id>` to understand task
    |-- Does work (code changes, analysis, etc.)
    |-- Runs `multica issue comment add` to post results
    |-- Runs `multica issue status <id> in_review`
    v
Daemon collects results:
    |-- POST /api/daemon/tasks/{id}/progress (streaming)
    |-- POST /api/daemon/tasks/{id}/messages (per-message)
    |-- POST /api/daemon/tasks/{id}/complete
    |-- POST /api/daemon/tasks/{id}/usage (token counts)
    v
Server updates task record, publishes events
    |-- hub.BroadcastToWorkspace(task:completed)
    v
UI shows task completion, comment appears on issue

Multi-Tenancy

Every query filters by workspace_id. The RequireWorkspaceMember middleware validates membership before any workspace-scoped handler executes. The X-Workspace-ID or X-Workspace-Slug header routes requests.

Workspace isolation is also enforced at the daemon level: each daemon authenticates with a workspace-scoped token and can only claim tasks for its registered runtimes.