# Multica Mental Model Wiki > A mental model of how Multica makes humans and agents first-class peers through workspace-scoped data, strict state ownership, package boundaries, polymorphic execution, and real-time invalidation — enabling the same logic to run safely on web and desktop. This is a Grok-Wiki source-grounded repository wiki. Use the complete Markdown link when an agent needs the full repo context. ## Context Links - [Complete Markdown wiki](https://grok-wiki.com/public/wiki/multica-ai-multica-fd1dd916d3bf/llms-full.txt) - [Complete Markdown alias](https://grok-wiki.com/public/wiki/multica-ai-multica-fd1dd916d3bf.md) - [Human interactive wiki](https://grok-wiki.com/public/wiki/multica-ai-multica-fd1dd916d3bf) - [GitHub repository](https://github.com/multica-ai/multica) ## Repository - Repository: multica-ai/multica - Generated: 2026-05-21T23:30:56.122Z - Updated: 2026-05-21T23:31:38.719Z - Runtime: Grok CLI - Format: Mental Model - Pages: 8 ## Pages - [The Mental Model](https://grok-wiki.com/public/wiki/multica-ai-multica-fd1dd916d3bf/pages/01-the-mental-model.md): The unifying picture: agents are teammates (not tools), multiplexing work like Multics for small human+AI teams. Workspace is the atomic unit of isolation and visibility. Server data lives only in TanStack Query; client UI state lives only in Zustand. WS events never write state — they only invalidate. The same business logic runs on web and desktop because three package layers plus thin platform adapters enforce the boundaries. - [The State Ownership Contract](https://grok-wiki.com/public/wiki/multica-ai-multica-fd1dd916d3bf/pages/02-the-state-ownership-contract.md): React Query owns every server fact (issues, agents, members, inbox, workspace list). Zustand owns only ephemeral client facts (current tab, filters, drafts, modal open/closed). Copying a query result into a store creates two drifting sources of truth. WS listeners only call queryClient.invalidateQueries; they never call store setters. Auth and workspace stores are the sole exceptions allowed to call api.* directly because queries cannot run until they exist. Selectors must return stable references or the UI will re-render forever. - [Workspace Isolation & Multi-Tenancy](https://grok-wiki.com/public/wiki/multica-ai-multica-fd1dd916d3bf/pages/03-workspace-isolation-multi-tenancy.md): Every row is filtered by workspace_id. Every query key must contain the current wsId; changing workspace automatically swaps the visible data because the cache key changes. X-Workspace-ID header routes requests. setCurrentWorkspace(null, null) must be called explicitly before leave/delete or the next render will see stale data and hard-reload. Desktop tabs are grouped per workspace; cross-workspace push is rewritten by the navigation adapter into a workspace switch, never a navigation inside the current tab router. - [The Package Contract: Core, UI, Views](https://grok-wiki.com/public/wiki/multica-ai-multica-fd1dd916d3bf/pages/04-the-package-contract-core-ui-views.md): Three layers with iron boundaries. packages/core exports raw .ts/.tsx (no build step), contains every Zustand store and the API client, and forbids react-dom, localStorage, and process.env. packages/ui contains only pure Base UI + shadcn components and may never import @multica/core. packages/views contains all business screens and may never import next/* or react-router-dom; it receives routing via NavigationAdapter injected by the platform layer. Each consuming app supplies its own thin adapter (web/platform/navigation.tsx, desktop/.../navigation.tsx) and wraps its root with CoreProvider. This is why the identical page component works in both apps and survives HMR. - [Backend Safety Rails](https://grok-wiki.com/public/wiki/multica-ai-multica-fd1dd916d3bf/pages/05-backend-safety-rails.md): Three UUID rules prevent silent zero-row deletes and 204 responses that lie. Resource path params that can be human slugs (MUL-123) or UUIDs must go through loadIssueForUser / loadAgentForUser first; the resolved .ID is then used for all subsequent queries. Pure-UUID inputs from the wire use parseUUIDOrBadRequest which returns 400 on failure. Trusted round-trips (sqlc results, test fixtures) may use MustParseUUID which panics — a deliberate signal that unvalidated user input reached it. WS listeners (activity, autopilot, runtime sweeper) exist only to invalidate queries; they never mutate client state. Every handler that performs a write must ask “where did this UUID come from?” - [Navigation, Tabs & Route Isolation](https://grok-wiki.com/public/wiki/multica-ai-multica-fd1dd916d3bf/pages/06-navigation-tabs-route-isolation.md): useNavigation().push and AppLink are the only allowed navigation primitives in shared code. Desktop distinguishes three route categories: session routes (real tabs under WorkspaceRouteLayout), transition flows (create workspace, accept invite — rendered as WindowOverlay state, never real routes), and error states (never rendered; stale tabs are healed by dropping the tab group). The navigation adapter detects cross-workspace push and calls switchWorkspace instead of letting the memory router navigate inside the wrong tab. Web uses ordinary Next.js routes plus searchParams; desktop memory router + tab-store keep each workspace’s tabs isolated by construction. - [Agent Execution & Runtime Model](https://grok-wiki.com/public/wiki/multica-ai-multica-fd1dd916d3bf/pages/07-agent-execution-runtime-model.md): Assignee is polymorphic (assignee_type + assignee_id). An agent can be assigned exactly like a member; it claims work, streams progress, posts comments, and may create new issues. Two runtime surfaces exist: local daemon (CLI-managed, talks to desktop via daemon-ipc-bridge) and cloud runtimes. The daemon advertises available CLIs; the sweeper reaps dead runs. Every completed execution becomes a reusable skill stored under the workspace; future agents can invoke the same skill without re-learning. Health derivation and version detection live in packages/core/runtimes so both apps see identical status without duplication. - [Core Invariants & Safe Evolution Rules](https://grok-wiki.com/public/wiki/multica-ai-multica-fd1dd916d3bf/pages/08-core-invariants-safe-evolution-rules.md): The system stays coherent only while these hold: (1) server facts never live in Zustand, (2) WS events only invalidate, (3) every workspace-scoped query keys on wsId, (4) mutations are optimistic then invalidate, (5) core never touches react-dom or framework routers, (6) views never import next/* or react-router, (7) UUIDs from the wire are validated before any write query, (8) desktop destructive workspace ops call setCurrentWorkspace(null) before the mutation. Violating any produces drift, white-screens on older desktop builds, or cross-workspace data leaks. To change safely: add the Zod response schema in the same PR, write a test that feeds it malformed data, run make check, and only then consider the contract stable. These rules are the price of a desktop app that is always older than the server it talks to. ## Source Files - `AGENTS.md` - `apps/desktop/src/renderer/src/App.tsx` - `apps/desktop/src/renderer/src/platform/daemon-ipc-bridge.ts` - `apps/desktop/src/renderer/src/platform/navigation.tsx` - `apps/desktop/src/renderer/src/stores/tab-store.ts` - `apps/web/components/web-providers.tsx` - `apps/web/platform/navigation.tsx` - `CLAUDE.md` - `Makefile` - `packages/core/auth/store.ts` - `packages/core/navigation/store.ts` - `packages/core/pins/mutations.ts` - `packages/core/pins/queries.ts` - `packages/core/platform/core-provider.tsx` - `packages/core/platform/index.ts` - `packages/core/platform/workspace-storage.ts` - `packages/core/query-client.ts` - `packages/core/runtimes/cloud-runtime.ts` - `packages/core/runtimes/derive-health.ts` - `packages/core/runtimes/index.ts` - `packages/core/runtimes/local-skills.ts` - `packages/core/types/workspace.ts` - `pnpm-workspace.yaml` - `README.md` - `server/cmd/server/listeners.go` - `server/cmd/server/main.go` - `server/cmd/server/runtime_sweeper.go` - `server/internal/handler/agent.go` - `server/internal/handler/handler.go` - `server/internal/handler/scope_authorizer.go` - `server/internal/util/pgx.go` - `server/migrations/001_init.up.sql` - `turbo.json`