Two files, one repository
multica-ai/multica ships 2 formats across 3 indexed files. The question worth asking is whether the second one says anything the first does not.
CompareAGENTS.md ↔ CLAUDE.md
| Dimension | Shared | Only in A | Only in B | Overlap |
|---|---|---|---|---|
| Sections | 1 | 6 | 18 | 4% |
| Commands | 6 | 0 | 21 | 22% |
| Section tags | 5 | 0 | 8 | 38% |
What each file covers
Sections
1 shared · 6 only in A · 18 only in B- − Repository Guidelines
- − Quick Reference
- − Architecture
- − State Management (critical)
- − Package Boundaries (hard rules)
- − Database Migrations (hard rules)
- + CLAUDE.md
- + Conventions
- + Project Shape
- + State Rules
- + Package Boundaries
- + Sharing Rules
- + Database and Migration Rules
- + Coding Rules
- + API Compatibility
- + Backend UUID Rules
- + Web/Desktop Features
- + Desktop Rules
- + Mobile Rules
- + UI Rules
- + Testing
- + Verification
- + Commits and Releases
- + Domain Reminders
- Commands
Commands
6 shared · 0 only in A · 21 only in B- + make start
- + make stop
- + make db-drop
- + make remove-worktree WORKTREE=../path
- + make server
- + make daemon
- + make sqlc
- + pnpm install
- + pnpm dev:web
- + pnpm dev:desktop
- + pnpm build
- + pnpm lint
- + pnpm exec playwright test
- + pnpm ui:add badge
- + make worktree-env
- + make setup-worktree
- + make start-worktree
- + go vet
- + pnpm generate:reserved-slugs
- + pnpm ui:add <component>
- + pnpm ui:add @reui/<name>
- make dev
- pnpm typecheck
- pnpm test
- make test
- make check
- pnpm-workspace.yaml
Section tags
5 shared · 0 only in A · 8 only in B- + setup
- + code-style
- + types
- + testing-strategy
- + git-pr
- + api
- + ui
- + agent-behaviour
- test
- lint-format
- security
- database
- do-not
Line diff
multica-ai/multica · AGENTS.md
@@ −1 @@
1# Repository Guidelines
2
3This file provides guidance to AI agents when working with code in this repository.
4
5> **Single source of truth:** This file is a concise pointer document.
6> All authoritative architecture, coding rules, and conventions
7> live in **CLAUDE.md** at the project root. Read that file first.
8> Use `Makefile`, `package.json`, and `pnpm-workspace.yaml` as the
9> source of truth for the full command list.
10
11## Quick Reference
12
13### Architecture
14
15Go backend + monorepo frontend (pnpm workspaces + Turborepo) with shared packages.
16
17- `server/` - Go backend (Chi router, sqlc, gorilla/websocket)
18- `apps/web/` - Next.js frontend (App Router)
19- `apps/desktop/` - Electron desktop app
20- `apps/mobile/` - Expo / React Native iOS app (read `apps/mobile/CLAUDE.md` first)
21- `apps/docs/` - Fumadocs documentation site
22- `packages/core/` - Headless business logic (Zustand stores, React Query hooks, API client)
23- `packages/ui/` - Atomic UI components (shadcn/Base UI, zero business logic)
24- `packages/views/` - Shared business pages/components
25- `packages/tsconfig/` - Shared TypeScript config
26- `packages/eslint-config/` - Shared ESLint config
27
28### State Management (critical)
29
30- **React Query** owns all server state (issues, members, agents, inbox, workspace list)
31- **Zustand** owns client/view state (view filters, drafts, modals, desktop tab state); current workspace identity is route-driven and only mirrored for platform plumbing
32- All Zustand stores live in `packages/core/` - never in `packages/views/` or app directories
33- WS events update React Query for server data; store writes are only for clearing client-owned pointers with a single responder/self-event guard
34
35### Package Boundaries (hard rules)
36
37- `packages/core/` - zero react-dom, zero localStorage, zero process.env
38- `packages/ui/` - zero `@multica/core` imports
39- `packages/views/` - zero `next/*`, zero `react-router-dom`, use `NavigationAdapter` for routing
40- `apps/web/platform/` - only place for Next.js APIs
41
42### Database Migrations (hard rules)
43
44- Never add database foreign keys or cascading actions. Enforce relationships and perform dependent cleanup explicitly in the application layer, using transactions when the operation must be atomic.
45- Every index created by a migration, including unique indexes and indexes on new tables, must use `CREATE [UNIQUE] INDEX CONCURRENTLY`. Keep each concurrent index build in its own single-statement migration file.
46
47### Commands
48
49```bash
50make dev # Auto-setup + start everything
51pnpm typecheck # TypeScript check
52pnpm test # TS unit tests (Vitest)
53make test # Go tests
54make check # Full verification pipeline
55```
56
57See CLAUDE.md for the authoritative rules and common commands.
58
multica-ai/multica · CLAUDE.md
@@ +1 @@
1# CLAUDE.md
2
3Guidance for Claude Code when working in this repository. Keep this file short and authoritative: rules here should be hard to infer from code or easy to get wrong.
4
5## Conventions
6
7The source of truth for code naming, i18n glossary, and Chinese product voice is:
8
9- `apps/docs/content/docs/developers/conventions.mdx`
10- `apps/docs/content/docs/developers/conventions.zh.mdx`
11
12Read it before editing translations in `packages/views/locales/`, naming routes/packages/files/DB columns/types, or writing Chinese UI/docs copy. Do not rely on `packages/views/locales/glossary.md`; it is only a redirect stub.
13
14## Project Shape
15
16Multica is an AI-native task management platform for small teams, with agents as first-class assignees that can own issues, comment, and change status.
17
18- `server/`: Go backend, Chi router, sqlc, gorilla/websocket.
19- `apps/web/`: Next.js App Router.
20- `apps/desktop/`: Electron desktop app.
21- `apps/mobile/`: Expo / React Native iOS app. Read `apps/mobile/CLAUDE.md` before touching it.
22- `apps/docs/`: Fumadocs documentation site.
23- `packages/core/`: headless business logic, API client, React Query hooks, Zustand stores.
24- `packages/ui/`: atomic UI components only.
25- `packages/views/`: shared business pages/components for web and desktop.
26- `packages/tsconfig/`: shared TypeScript config.
27- `packages/eslint-config/`: shared ESLint config.
28
29Shared packages export raw `.ts` / `.tsx` and are compiled by consuming apps. Dependency direction is `views -> core + ui`; `core` and `ui` must stay independent.
30
31## State Rules
32
33Keep server state and client state separate.
34
35- TanStack Query owns server state: issues, users, workspaces, inbox, agents, members, and anything fetched from the API.
36- Zustand owns client/view state: filters, drafts, modals, tab layout, and navigation history. Current workspace identity is route-driven; platform stores/singletons may mirror slug/id only for headers, persistence namespaces, and reconnects.
37- Shared Zustand stores live in `packages/core/`, never in `packages/views/` or app directories.
38- React Context is for platform plumbing only, such as `WorkspaceIdProvider` and `NavigationProvider`.
39- Only auth/workspace stores may call `api.*` directly. Other server interaction belongs in queries/mutations.
40- Workspace-scoped query keys must include `wsId`.
41- Optimistic updates only when ALL hold: outcome locally predictable, user stays on the same screen (no navigation), failure is rare, rollback is trivial. Canonical: status/assignee/toggle field patches — patch determinate caches, roll back on failure, invalidate uncertain projections on settle.
42- Flows that navigate or confirm (create, delete, leave) must await the server before navigating or cleaning up; never optimistically remove an entity from cache.
43- Chat/message send uses the pending-message pattern: render immediately with a visible pending state and retry on failure, not silent optimism.
44- WebSocket events invalidate or patch Query cache for server data. They must never mirror server payload data into Zustand; clearing client-owned pointers (active session, selection, current workspace) is allowed only with a single responder and a self-initiated guard when this client can cause the event.
45- Persist durable preferences/drafts/layout. Do not persist server data or ephemeral UI state.
46- Zustand selectors must return stable references. Do not return freshly allocated objects/arrays from selectors without shallow comparison.
47- Hooks that need workspace context should accept `wsId`; do not call `useWorkspaceId()` internally unless the hook is guaranteed to run under the provider.
48
49## Package Boundaries
50
51These are hard constraints:
52
53- `packages/core/`: no `react-dom`, `localStorage` (use `StorageAdapter`), `process.env`, or UI libraries.
54- `packages/ui/`: no `@multica/core` imports and no business logic.
55- `packages/views/`: no `next/*`, no `react-router-dom`, no stores. Use `NavigationAdapter`, `useNavigation()`, and `<AppLink>`.
56- `apps/web/platform/`: only place for Next.js navigation/platform APIs.
57- `apps/desktop/src/renderer/src/platform/`: only place for `react-router-dom` navigation wiring.
58- Every workspace under `apps/` and `packages/` must declare directly imported external packages in its own `package.json`.
59- Shared dependencies use `catalog:` from `pnpm-workspace.yaml`; `apps/mobile/` pins Expo/React Native related versions directly.
60
61## Sharing Rules
62
63Web and desktop share business logic, hooks, stores, components, and views through `packages/core/`, `packages/ui/`, and `packages/views/`.
64
65If the same logic exists in both web and desktop, extract it unless it depends on platform APIs:
66
671. Next.js, Electron, or router APIs stay in the app/platform layer.
682. Headless logic belongs in `packages/core/`.
693. Shared UI or business views belong in `packages/views/`.
704. Shared primitives belong in `packages/ui/`.
71
72Mobile is independent. It may import types and pure functions from `@multica/core`, with `import type` for types, but owns its UI, state, hooks, providers, i18n, React version, build pipeline, and release cadence.
73
74## Commands
75
76Use the repo scripts as the source of truth. Common commands:
77
78```bash
79make dev # auto-setup and start the app
80make start # start backend + frontend
81make stop # stop app processes for this checkout
82make db-drop # permanently drop this checkout's local database
83make remove-worktree WORKTREE=../path # drop a linked worktree DB, then remove it
84make server # run Go server only
85make daemon # run local daemon
86make test # Go tests
87make sqlc # regenerate sqlc code after SQL changes
88pnpm install
89pnpm dev:web
90pnpm dev:desktop
91pnpm build
92pnpm typecheck
93pnpm lint
94pnpm test # TS/Vitest tests through Turborepo
95pnpm exec playwright test
96pnpm ui:add badge # shadcn/Base UI component into packages/ui
97```
98
99Worktrees share one PostgreSQL container and get isolated DB names/ports via `.env.worktree`. `make dev` auto-detects this. For manual setup use `make worktree-env`, `make setup-worktree`, and `make start-worktree`. `pnpm dev:desktop` additionally self-isolates per worktree (its own renderer port + app name) automatically, independent of `.env.worktree`.
100
101CI runs Node 22, Go 1.26.1, and a `pgvector/pgvector:pg17` PostgreSQL service.
102
103## Database and Migration Rules
104
105These are hard requirements for every new or modified database design and production migration:
106
107- Do not add database foreign keys (`FOREIGN KEY` / `REFERENCES`), cascading deletes, or cascading updates. Resolve relationships, validation, and dependent cleanup explicitly in application code. Use an application transaction when cleanup and the parent operation must commit or roll back atomically.
108- Every index created by a migration must use `CREATE INDEX CONCURRENTLY` or `CREATE UNIQUE INDEX CONCURRENTLY`, including indexes on newly created tables. PostgreSQL rejects concurrent index creation inside a transaction or a multi-command string, so keep each concurrent index build in its own single-statement migration file. The repository migration runner executes migration files outside an explicit transaction to support this.
109
110## Coding Rules
111
112- TypeScript strict mode is enabled; keep types explicit.
113- Go follows standard conventions: `gofmt`, `go vet`, checked errors.
114- Code comments must be English.
115- Prefer existing patterns/components over new parallel abstractions.
116- Avoid broad refactors unless required by the task.
117- For internal, non-boundary code, do not add compatibility layers, fallback paths, dual writes, legacy adapters, or temporary shims unless explicitly requested.
118- API boundaries are different: installed desktop clients can talk to newer backends, so response parsing must follow the API compatibility rules below.
119- If a flow or API is being replaced and the product is not live, prefer removing the old path instead of preserving both.
120- New global pre-workspace routes must be a single word (`/login`, `/inbox`) or `/{noun}/{verb}` (`/workspaces/new`). Do not add hyphenated root routes like `/new-workspace`.
121- Reserved slugs live in `server/internal/handler/reserved_slugs.json`. Edit it, run `pnpm generate:reserved-slugs`, and commit the generated `packages/core/paths/reserved-slugs.ts`.
122- When changing CLI commands/flags, API fields, or product behavior documented by built-in skills under `server/internal/service/builtin_skills/*`, update the relevant `SKILL.md` and `references/*-source-map.md` in the same PR.
123
124## API Compatibility
125
126Frontend code must survive backend response drift, especially in installed desktop builds.
127
128- Parse API JSON with `parseWithFallback` in `packages/core/api/schema.ts` and a zod schema. Do not cast network JSON to `T`.
129- Endpoint responses consumed by UI logic must pass through a schema before returning.
130- Downstream UI should optional-chain and default fields defensively.
131- Prefer explicit boolean checks (`=== true`) over truthy/falsy checks on server fields.
132- Do not pin critical affordances to one backend boolean; combine signals when possible.
133- Server-driven enum switches need a `default` branch.
134- When adding or changing an endpoint, add/update the schema and include a malformed-response test.
135
136## Backend UUID Rules
137
138In `server/internal/handler/`, always know where a UUID came from before using it in write queries.
139
140- Resource path params that may be UUIDs or human-readable IDs must be resolved through loaders such as `loadIssueForUser`, `loadSkillForUser`, `loadAgentForUser`, or `requireDaemonRuntimeAccess`; subsequent writes use the resolved `entity.ID`.
141- Pure UUID inputs from request boundaries use `parseUUIDOrBadRequest(w, s, fieldName)` and return immediately on `ok=false`.
142- Trusted UUID round-trips from sqlc results or test fixtures use `parseUUID(s)`, which panics on invalid input.
143- Outside handlers, `util.ParseUUID(s) (pgtype.UUID, error)` is the safe variant; always check the error.
144
145## Web/Desktop Features
146
147When adding a shared page or feature for web and desktop:
148
1491. Put the page/component in `packages/views/<domain>/`.
1502. Add platform wiring in both `apps/web/app/` and the desktop router, unless the desktop flow is a transition overlay.
1513. Use `useNavigation().push()` or `<AppLink>` in shared code.
1524. Use shared guards/providers such as `DashboardGuard` from `packages/views/layout/`.
1535. Keep platform-only UI in the app or inject it through props/slots.
1546. Hooks that need workspace context should accept `wsId`.
155
156CSS for web/desktop is shared from `packages/ui/styles/`. Use semantic tokens such as `bg-background` and `text-muted-foreground`; avoid hardcoded Tailwind colors and duplicated base styles.
157
158## Desktop Rules
159
160Desktop routing has three categories:
161
162- Session routes: workspace-scoped tab destinations such as `/:slug/issues`.
163- Transition flows: pre-workspace one-shot actions such as create workspace or accept invite. These are `WindowOverlay` state, not routes.
164- Error/stale states: stale workspace tabs should auto-heal by dropping stale tab groups, not render desktop error pages.
165
166More desktop constraints:
167
168- New pre-workspace desktop flows register a `WindowOverlay` type in `stores/window-overlay-store.ts`; do not add them to `routes.tsx`.
169- `setCurrentWorkspace(slug, uuid)` from `@multica/core/platform` mirrors the active route for headers, storage namespaces, and reconnects; workspace route layouts own setting it.
170- Code that leaves workspace context must call `setCurrentWorkspace(null, null)` explicitly.
171- Workspace delete must await the server before navigation/cleanup. Workspace leave currently clears/navigates before mutation only to avoid the `member:removed` realtime race; treat that as known debt, not a reusable pattern.
172- Cross-workspace navigation must go through the navigation adapter so it can call `switchWorkspace(slug, targetPath)`.
173- Full-window desktop views outside the dashboard shell must mount `<DragStrip />` from `@multica/views/platform` as the first flex child. Interactive controls in the top 48px need `WebkitAppRegion: "no-drag"`.
174
175## Mobile Rules
176
177Read `apps/mobile/CLAUDE.md` before touching `apps/mobile/`. It contains the mandatory pre-flight process, import limits, parity rules, tech stack, UI rules, data helpers, realtime strategy, and mobile release flow.
178
179Root-level reminders:
180
181- Mobile shares only `@multica/core` types and pure functions.
182- Mobile must match web/desktop product semantics: counts, permissions, enums/transitions, and data identity.
183- Mobile may differ in UI/interaction when the phone context requires it.
184
185## UI Rules
186
187- Prefer shadcn/Base UI components over custom implementations. Add them with `pnpm ui:add <component>` from the repo root.
188- The Pro `@reui` registry is configured in `packages/ui/components.json`; add items with `pnpm ui:add @reui/<name>` and answer `n` to every overwrite prompt so local component customizations survive. It reads `REUI_LICENSE_KEY` from the environment — agents get it from their Multica agent environment, humans export it in their own shell. Never write the key into a repo file.
189- ReUI ships source, not a dependency: route the vendored output to our layout (new primitives to `packages/ui/components/ui/`, compositions to `packages/views/<domain>/`) and rewrite it to our conventions before committing.
190- Use design tokens and semantic classes; avoid hardcoded colors. Font sizes come from the role-named `--text-*` scale in `packages/ui/styles/tokens.css` (`text-caption`, `text-body`, `text-title`, …), which is the authoritative list — not Tailwind's default `text-sm` / `text-base` ramp.
191- An active/selected state must stay identifiable while hovered. Express it on a dimension hover does not touch (weight, text color), or define the `data-active:hover:` compound explicitly — otherwise hovering a selected row visually downgrades it to plain hover.
192- Do not introduce extra local state unless the design requires it.
193- Handle overflow, long text, scrolling, alignment, and spacing deliberately. Prefer more spacing over adding a divider.
194- If a component is identical between web and desktop, it belongs in a shared package.
195
196## Testing
197
198Tests follow the code:
199
200| What is tested | Location |
201| --- | --- |
202| Shared business logic, stores, queries, hooks | `packages/core/*.test.ts` |
203| Shared UI components, pages, forms, modals | `packages/views/*.test.tsx` |
204| Platform wiring such as cookies, redirects, search params | `apps/web/*.test.tsx` or `apps/desktop/` |
205| End-to-end flows | `e2e/*.spec.ts` |
206| Backend | `server/` Go tests |
207
208Rules:
209
210- Never test shared component behavior in an app test file.
211- `packages/views/` tests must not mock `next/*` or `react-router-dom`.
212- Mock `@multica/core` stores with the Zustand callable-store shape (`selectorFn` plus `getState`).
213- Mock `@multica/core/api` for API calls.
214- E2E tests should use `TestApiClient` for setup/teardown.
215- Prefer writing the failing test in the correct package before implementation when the change is behavioral.
216- Default tests must never resolve or execute user-installed agent CLIs. Pass a test-created fake executable path or a test-created missing path to agent subprocess code.
217- Real-agent smoke tests belong behind the `agentintegration` build tag and must check `MULTICA_RUN_REAL_AGENT_SMOKE=1` before executable lookup or account access.
218- Run an explicitly authorized real-agent smoke test with `(cd server && MULTICA_RUN_REAL_AGENT_SMOKE=1 go test -tags=agentintegration ./pkg/agent -run '<test-name>' -count=1 -v)`. This command may access an authenticated account and consume quota.
219- When adding a default agent command, add it to `scripts/agent-cli-command-names.txt`; the normal Linux/macOS test entry points fail on ambient agent CLI execution.
220
221## Verification
222
223For code changes, run the narrowest useful checks while iterating, then run broader verification when risk justifies it or when asked.
224
225Useful checks:
226
227```bash
228pnpm typecheck
229pnpm test
230make test
231pnpm exec playwright test
232make check
233```
234
235Do not claim verification passed unless you ran it. If you skip checks because the change is docs-only or the user asked not to run them, say so.
236
237## Commits and Releases
238
239- Commits should be atomic and use conventional prefixes: `feat(scope)`, `fix(scope)`, `refactor(scope)`, `docs`, `test(scope)`, `chore(scope)`.
240- A production deployment requires a CLI release tag on `main`: create `v0.x.x`, push it, and let `release.yml` publish binaries and the Homebrew tap.
241- Bump patch by default unless the user specifies a version.
242
243## Domain Reminders
244
245- All queries filter by `workspace_id`; membership gates access; `X-Workspace-ID` selects the workspace.
246- Issue assignees are polymorphic: `assignee_type` plus `assignee_id` can reference a member or an agent.
247
@@ −1 +1 @@
1−# Repository Guidelines
1+# CLAUDE.md
22
3−This file provides guidance to AI agents when working with code in this repository.
3+Guidance for Claude Code when working in this repository. Keep this file short and authoritative: rules here should be hard to infer from code or easy to get wrong.
44
5−> **Single source of truth:** This file is a concise pointer document.
6−> All authoritative architecture, coding rules, and conventions
7−> live in **CLAUDE.md** at the project root. Read that file first.
8−> Use `Makefile`, `package.json`, and `pnpm-workspace.yaml` as the
9−> source of truth for the full command list.
5+## Conventions
106
11−## Quick Reference
7+The source of truth for code naming, i18n glossary, and Chinese product voice is:
128
13−### Architecture
9+- `apps/docs/content/docs/developers/conventions.mdx`
10+- `apps/docs/content/docs/developers/conventions.zh.mdx`
1411
15−Go backend + monorepo frontend (pnpm workspaces + Turborepo) with shared packages.
12+Read it before editing translations in `packages/views/locales/`, naming routes/packages/files/DB columns/types, or writing Chinese UI/docs copy. Do not rely on `packages/views/locales/glossary.md`; it is only a redirect stub.
1613
17−- `server/` - Go backend (Chi router, sqlc, gorilla/websocket)
18−- `apps/web/` - Next.js frontend (App Router)
19−- `apps/desktop/` - Electron desktop app
20−- `apps/mobile/` - Expo / React Native iOS app (read `apps/mobile/CLAUDE.md` first)
21−- `apps/docs/` - Fumadocs documentation site
22−- `packages/core/` - Headless business logic (Zustand stores, React Query hooks, API client)
23−- `packages/ui/` - Atomic UI components (shadcn/Base UI, zero business logic)
24−- `packages/views/` - Shared business pages/components
25−- `packages/tsconfig/` - Shared TypeScript config
26−- `packages/eslint-config/` - Shared ESLint config
14+## Project Shape
2715
28−### State Management (critical)
16+Multica is an AI-native task management platform for small teams, with agents as first-class assignees that can own issues, comment, and change status.
2917
30−- **React Query** owns all server state (issues, members, agents, inbox, workspace list)
31−- **Zustand** owns client/view state (view filters, drafts, modals, desktop tab state); current workspace identity is route-driven and only mirrored for platform plumbing
32−- All Zustand stores live in `packages/core/` - never in `packages/views/` or app directories
33−- WS events update React Query for server data; store writes are only for clearing client-owned pointers with a single responder/self-event guard
18+- `server/`: Go backend, Chi router, sqlc, gorilla/websocket.
19+- `apps/web/`: Next.js App Router.
20+- `apps/desktop/`: Electron desktop app.
21+- `apps/mobile/`: Expo / React Native iOS app. Read `apps/mobile/CLAUDE.md` before touching it.
22+- `apps/docs/`: Fumadocs documentation site.
23+- `packages/core/`: headless business logic, API client, React Query hooks, Zustand stores.
24+- `packages/ui/`: atomic UI components only.
25+- `packages/views/`: shared business pages/components for web and desktop.
26+- `packages/tsconfig/`: shared TypeScript config.
27+- `packages/eslint-config/`: shared ESLint config.
3428
35−### Package Boundaries (hard rules)
29+Shared packages export raw `.ts` / `.tsx` and are compiled by consuming apps. Dependency direction is `views -> core + ui`; `core` and `ui` must stay independent.
3630
37−- `packages/core/` - zero react-dom, zero localStorage, zero process.env
38−- `packages/ui/` - zero `@multica/core` imports
39−- `packages/views/` - zero `next/*`, zero `react-router-dom`, use `NavigationAdapter` for routing
40−- `apps/web/platform/` - only place for Next.js APIs
31+## State Rules
4132
42−### Database Migrations (hard rules)
33+Keep server state and client state separate.
4334
44−- Never add database foreign keys or cascading actions. Enforce relationships and perform dependent cleanup explicitly in the application layer, using transactions when the operation must be atomic.
45−- Every index created by a migration, including unique indexes and indexes on new tables, must use `CREATE [UNIQUE] INDEX CONCURRENTLY`. Keep each concurrent index build in its own single-statement migration file.
35+- TanStack Query owns server state: issues, users, workspaces, inbox, agents, members, and anything fetched from the API.
36+- Zustand owns client/view state: filters, drafts, modals, tab layout, and navigation history. Current workspace identity is route-driven; platform stores/singletons may mirror slug/id only for headers, persistence namespaces, and reconnects.
37+- Shared Zustand stores live in `packages/core/`, never in `packages/views/` or app directories.
38+- React Context is for platform plumbing only, such as `WorkspaceIdProvider` and `NavigationProvider`.
39+- Only auth/workspace stores may call `api.*` directly. Other server interaction belongs in queries/mutations.
40+- Workspace-scoped query keys must include `wsId`.
41+- Optimistic updates only when ALL hold: outcome locally predictable, user stays on the same screen (no navigation), failure is rare, rollback is trivial. Canonical: status/assignee/toggle field patches — patch determinate caches, roll back on failure, invalidate uncertain projections on settle.
42+- Flows that navigate or confirm (create, delete, leave) must await the server before navigating or cleaning up; never optimistically remove an entity from cache.
43+- Chat/message send uses the pending-message pattern: render immediately with a visible pending state and retry on failure, not silent optimism.
44+- WebSocket events invalidate or patch Query cache for server data. They must never mirror server payload data into Zustand; clearing client-owned pointers (active session, selection, current workspace) is allowed only with a single responder and a self-initiated guard when this client can cause the event.
45+- Persist durable preferences/drafts/layout. Do not persist server data or ephemeral UI state.
46+- Zustand selectors must return stable references. Do not return freshly allocated objects/arrays from selectors without shallow comparison.
47+- Hooks that need workspace context should accept `wsId`; do not call `useWorkspaceId()` internally unless the hook is guaranteed to run under the provider.
4648
47−### Commands
49+## Package Boundaries
4850
51+These are hard constraints:
52+
53+- `packages/core/`: no `react-dom`, `localStorage` (use `StorageAdapter`), `process.env`, or UI libraries.
54+- `packages/ui/`: no `@multica/core` imports and no business logic.
55+- `packages/views/`: no `next/*`, no `react-router-dom`, no stores. Use `NavigationAdapter`, `useNavigation()`, and `<AppLink>`.
56+- `apps/web/platform/`: only place for Next.js navigation/platform APIs.
57+- `apps/desktop/src/renderer/src/platform/`: only place for `react-router-dom` navigation wiring.
58+- Every workspace under `apps/` and `packages/` must declare directly imported external packages in its own `package.json`.
59+- Shared dependencies use `catalog:` from `pnpm-workspace.yaml`; `apps/mobile/` pins Expo/React Native related versions directly.
60+
61+## Sharing Rules
62+
63+Web and desktop share business logic, hooks, stores, components, and views through `packages/core/`, `packages/ui/`, and `packages/views/`.
64+
65+If the same logic exists in both web and desktop, extract it unless it depends on platform APIs:
66+
67+1. Next.js, Electron, or router APIs stay in the app/platform layer.
68+2. Headless logic belongs in `packages/core/`.
69+3. Shared UI or business views belong in `packages/views/`.
70+4. Shared primitives belong in `packages/ui/`.
71+
72+Mobile is independent. It may import types and pure functions from `@multica/core`, with `import type` for types, but owns its UI, state, hooks, providers, i18n, React version, build pipeline, and release cadence.
73+
74+## Commands
75+
76+Use the repo scripts as the source of truth. Common commands:
77+
4978 ```bash
50−make dev # Auto-setup + start everything
51−pnpm typecheck # TypeScript check
52−pnpm test # TS unit tests (Vitest)
79+make dev # auto-setup and start the app
80+make start # start backend + frontend
81+make stop # stop app processes for this checkout
82+make db-drop # permanently drop this checkout's local database
83+make remove-worktree WORKTREE=../path # drop a linked worktree DB, then remove it
84+make server # run Go server only
85+make daemon # run local daemon
5386 make test # Go tests
54−make check # Full verification pipeline
87+make sqlc # regenerate sqlc code after SQL changes
88+pnpm install
89+pnpm dev:web
90+pnpm dev:desktop
91+pnpm build
92+pnpm typecheck
93+pnpm lint
94+pnpm test # TS/Vitest tests through Turborepo
95+pnpm exec playwright test
96+pnpm ui:add badge # shadcn/Base UI component into packages/ui
5597 ```
5698
57−See CLAUDE.md for the authoritative rules and common commands.
99+Worktrees share one PostgreSQL container and get isolated DB names/ports via `.env.worktree`. `make dev` auto-detects this. For manual setup use `make worktree-env`, `make setup-worktree`, and `make start-worktree`. `pnpm dev:desktop` additionally self-isolates per worktree (its own renderer port + app name) automatically, independent of `.env.worktree`.
100+
101+CI runs Node 22, Go 1.26.1, and a `pgvector/pgvector:pg17` PostgreSQL service.
102+
103+## Database and Migration Rules
104+
105+These are hard requirements for every new or modified database design and production migration:
106+
107+- Do not add database foreign keys (`FOREIGN KEY` / `REFERENCES`), cascading deletes, or cascading updates. Resolve relationships, validation, and dependent cleanup explicitly in application code. Use an application transaction when cleanup and the parent operation must commit or roll back atomically.
108+- Every index created by a migration must use `CREATE INDEX CONCURRENTLY` or `CREATE UNIQUE INDEX CONCURRENTLY`, including indexes on newly created tables. PostgreSQL rejects concurrent index creation inside a transaction or a multi-command string, so keep each concurrent index build in its own single-statement migration file. The repository migration runner executes migration files outside an explicit transaction to support this.
109+
110+## Coding Rules
111+
112+- TypeScript strict mode is enabled; keep types explicit.
113+- Go follows standard conventions: `gofmt`, `go vet`, checked errors.
114+- Code comments must be English.
115+- Prefer existing patterns/components over new parallel abstractions.
116+- Avoid broad refactors unless required by the task.
117+- For internal, non-boundary code, do not add compatibility layers, fallback paths, dual writes, legacy adapters, or temporary shims unless explicitly requested.
118+- API boundaries are different: installed desktop clients can talk to newer backends, so response parsing must follow the API compatibility rules below.
119+- If a flow or API is being replaced and the product is not live, prefer removing the old path instead of preserving both.
120+- New global pre-workspace routes must be a single word (`/login`, `/inbox`) or `/{noun}/{verb}` (`/workspaces/new`). Do not add hyphenated root routes like `/new-workspace`.
121+- Reserved slugs live in `server/internal/handler/reserved_slugs.json`. Edit it, run `pnpm generate:reserved-slugs`, and commit the generated `packages/core/paths/reserved-slugs.ts`.
122+- When changing CLI commands/flags, API fields, or product behavior documented by built-in skills under `server/internal/service/builtin_skills/*`, update the relevant `SKILL.md` and `references/*-source-map.md` in the same PR.
123+
124+## API Compatibility
125+
126+Frontend code must survive backend response drift, especially in installed desktop builds.
127+
128+- Parse API JSON with `parseWithFallback` in `packages/core/api/schema.ts` and a zod schema. Do not cast network JSON to `T`.
129+- Endpoint responses consumed by UI logic must pass through a schema before returning.
130+- Downstream UI should optional-chain and default fields defensively.
131+- Prefer explicit boolean checks (`=== true`) over truthy/falsy checks on server fields.
132+- Do not pin critical affordances to one backend boolean; combine signals when possible.
133+- Server-driven enum switches need a `default` branch.
134+- When adding or changing an endpoint, add/update the schema and include a malformed-response test.
135+
136+## Backend UUID Rules
137+
138+In `server/internal/handler/`, always know where a UUID came from before using it in write queries.
139+
140+- Resource path params that may be UUIDs or human-readable IDs must be resolved through loaders such as `loadIssueForUser`, `loadSkillForUser`, `loadAgentForUser`, or `requireDaemonRuntimeAccess`; subsequent writes use the resolved `entity.ID`.
141+- Pure UUID inputs from request boundaries use `parseUUIDOrBadRequest(w, s, fieldName)` and return immediately on `ok=false`.
142+- Trusted UUID round-trips from sqlc results or test fixtures use `parseUUID(s)`, which panics on invalid input.
143+- Outside handlers, `util.ParseUUID(s) (pgtype.UUID, error)` is the safe variant; always check the error.
144+
145+## Web/Desktop Features
146+
147+When adding a shared page or feature for web and desktop:
148+
149+1. Put the page/component in `packages/views/<domain>/`.
150+2. Add platform wiring in both `apps/web/app/` and the desktop router, unless the desktop flow is a transition overlay.
151+3. Use `useNavigation().push()` or `<AppLink>` in shared code.
152+4. Use shared guards/providers such as `DashboardGuard` from `packages/views/layout/`.
153+5. Keep platform-only UI in the app or inject it through props/slots.
154+6. Hooks that need workspace context should accept `wsId`.
155+
156+CSS for web/desktop is shared from `packages/ui/styles/`. Use semantic tokens such as `bg-background` and `text-muted-foreground`; avoid hardcoded Tailwind colors and duplicated base styles.
157+
158+## Desktop Rules
159+
160+Desktop routing has three categories:
161+
162+- Session routes: workspace-scoped tab destinations such as `/:slug/issues`.
163+- Transition flows: pre-workspace one-shot actions such as create workspace or accept invite. These are `WindowOverlay` state, not routes.
164+- Error/stale states: stale workspace tabs should auto-heal by dropping stale tab groups, not render desktop error pages.
165+
166+More desktop constraints:
167+
168+- New pre-workspace desktop flows register a `WindowOverlay` type in `stores/window-overlay-store.ts`; do not add them to `routes.tsx`.
169+- `setCurrentWorkspace(slug, uuid)` from `@multica/core/platform` mirrors the active route for headers, storage namespaces, and reconnects; workspace route layouts own setting it.
170+- Code that leaves workspace context must call `setCurrentWorkspace(null, null)` explicitly.
171+- Workspace delete must await the server before navigation/cleanup. Workspace leave currently clears/navigates before mutation only to avoid the `member:removed` realtime race; treat that as known debt, not a reusable pattern.
172+- Cross-workspace navigation must go through the navigation adapter so it can call `switchWorkspace(slug, targetPath)`.
173+- Full-window desktop views outside the dashboard shell must mount `<DragStrip />` from `@multica/views/platform` as the first flex child. Interactive controls in the top 48px need `WebkitAppRegion: "no-drag"`.
174+
175+## Mobile Rules
176+
177+Read `apps/mobile/CLAUDE.md` before touching `apps/mobile/`. It contains the mandatory pre-flight process, import limits, parity rules, tech stack, UI rules, data helpers, realtime strategy, and mobile release flow.
178+
179+Root-level reminders:
180+
181+- Mobile shares only `@multica/core` types and pure functions.
182+- Mobile must match web/desktop product semantics: counts, permissions, enums/transitions, and data identity.
183+- Mobile may differ in UI/interaction when the phone context requires it.
184+
185+## UI Rules
186+
187+- Prefer shadcn/Base UI components over custom implementations. Add them with `pnpm ui:add <component>` from the repo root.
188+- The Pro `@reui` registry is configured in `packages/ui/components.json`; add items with `pnpm ui:add @reui/<name>` and answer `n` to every overwrite prompt so local component customizations survive. It reads `REUI_LICENSE_KEY` from the environment — agents get it from their Multica agent environment, humans export it in their own shell. Never write the key into a repo file.
189+- ReUI ships source, not a dependency: route the vendored output to our layout (new primitives to `packages/ui/components/ui/`, compositions to `packages/views/<domain>/`) and rewrite it to our conventions before committing.
190+- Use design tokens and semantic classes; avoid hardcoded colors. Font sizes come from the role-named `--text-*` scale in `packages/ui/styles/tokens.css` (`text-caption`, `text-body`, `text-title`, …), which is the authoritative list — not Tailwind's default `text-sm` / `text-base` ramp.
191+- An active/selected state must stay identifiable while hovered. Express it on a dimension hover does not touch (weight, text color), or define the `data-active:hover:` compound explicitly — otherwise hovering a selected row visually downgrades it to plain hover.
192+- Do not introduce extra local state unless the design requires it.
193+- Handle overflow, long text, scrolling, alignment, and spacing deliberately. Prefer more spacing over adding a divider.
194+- If a component is identical between web and desktop, it belongs in a shared package.
195+
196+## Testing
197+
198+Tests follow the code:
199+
200+| What is tested | Location |
201+| --- | --- |
202+| Shared business logic, stores, queries, hooks | `packages/core/*.test.ts` |
203+| Shared UI components, pages, forms, modals | `packages/views/*.test.tsx` |
204+| Platform wiring such as cookies, redirects, search params | `apps/web/*.test.tsx` or `apps/desktop/` |
205+| End-to-end flows | `e2e/*.spec.ts` |
206+| Backend | `server/` Go tests |
207+
208+Rules:
209+
210+- Never test shared component behavior in an app test file.
211+- `packages/views/` tests must not mock `next/*` or `react-router-dom`.
212+- Mock `@multica/core` stores with the Zustand callable-store shape (`selectorFn` plus `getState`).
213+- Mock `@multica/core/api` for API calls.
214+- E2E tests should use `TestApiClient` for setup/teardown.
215+- Prefer writing the failing test in the correct package before implementation when the change is behavioral.
216+- Default tests must never resolve or execute user-installed agent CLIs. Pass a test-created fake executable path or a test-created missing path to agent subprocess code.
217+- Real-agent smoke tests belong behind the `agentintegration` build tag and must check `MULTICA_RUN_REAL_AGENT_SMOKE=1` before executable lookup or account access.
218+- Run an explicitly authorized real-agent smoke test with `(cd server && MULTICA_RUN_REAL_AGENT_SMOKE=1 go test -tags=agentintegration ./pkg/agent -run '<test-name>' -count=1 -v)`. This command may access an authenticated account and consume quota.
219+- When adding a default agent command, add it to `scripts/agent-cli-command-names.txt`; the normal Linux/macOS test entry points fail on ambient agent CLI execution.
220+
221+## Verification
222+
223+For code changes, run the narrowest useful checks while iterating, then run broader verification when risk justifies it or when asked.
224+
225+Useful checks:
226+
227+```bash
228+pnpm typecheck
229+pnpm test
230+make test
231+pnpm exec playwright test
232+make check
233+```
234+
235+Do not claim verification passed unless you ran it. If you skip checks because the change is docs-only or the user asked not to run them, say so.
236+
237+## Commits and Releases
238+
239+- Commits should be atomic and use conventional prefixes: `feat(scope)`, `fix(scope)`, `refactor(scope)`, `docs`, `test(scope)`, `chore(scope)`.
240+- A production deployment requires a CLI release tag on `main`: create `v0.x.x`, push it, and let `release.yml` publish binaries and the Homebrew tap.
241+- Bump patch by default unless the user specifies a version.
242+
243+## Domain Reminders
244+
245+- All queries filter by `workspace_id`; membership gates access; `X-Workspace-ID` selects the workspace.
246+- Issue assignees are polymorphic: `assignee_type` plus `assignee_id` can reference a member or an agent.
58247
