# @platform — monorepo agent rules Inherits from `../CLAUDE.md`. Repo-wide rules apply; this file captures monorepo-internal conventions only. ## Stack (V4) - **Backends**: NestJS 11 (mirrors `@ai/ai-core`) - **Web frontends**: React 19 + Vite - **iOS frontend**: Swift 5.9+ / SwiftUI (iOS 17+), built on plum via `build-remote.sh` - **Workspace**: Turbo + pnpm 9, ESM (`"type": "module"`) - **TypeScript**: strict, no `any`, no implicit returns, `noUncheckedIndexedAccess` on - **Tests**: Vitest - **Private registry**: ct-forge / DO registry (e.g. http://forge.ct.uvlava.com:4873/ or cocotte-forge IP) for `@lilith/*` packages (see `.npmrc`). No more black.lan for CI/registry in new setup. ## Layout See `../DESIGN.md §4` for the canonical directory tree. Quick map: | Path | Owns | |------|------| | `codebase/@features/{name}/ai-core` | NestJS @ai instance (one per specialist) | | `codebase/@features/{name}/ios-fe` | Swift iOS package (NOT a pnpm workspace) | | `codebase/@features/{name}/web-fe` | React web client | | `codebase/@features/{name}/worker` | Cron / queue process | | `codebase/@features/platform-api` | V4 data plane (NestJS, port 3060, on black) | | `codebase/@features/{scheduler,ingestor,resolver,notifier,cache-rebuilder}` | Workers | | `codebase/@packages/*` | Shared libs (ContextProviders, auth, UI shared) | | `infrastructure/ports.yaml` | Single source of truth for ports | | `infrastructure/.env.ports` | Generated; do not edit by hand | | `infrastructure/sql/migrations/*.sql` | platform.db schema migrations | | `scripts/extract-archive.sh` | Mine code from `.archive/platform.{0,1,2,3}` tarballs | | `scripts/sync-ports.sh` | Regenerate `.env.ports` from `ports.yaml` | | `deployments/@domains/*` | Per-brand deploy configs | ## Adding a new TS workspace 1. Create the directory under `codebase/@features/{name}/{ai-core|web-fe|worker}` or `codebase/@packages/{name}`. 2. Add a `package.json` with `"name": "@cocottetech/{name}"` (provider-generic — NEVER `quinn-*`). 3. Add a `tsconfig.json` that `"extends": "../../../tsconfig.base.json"` (or appropriate relative path). 4. If the workspace path isn't covered by `pnpm-workspace.yaml` globs, add it explicitly. 5. Run `pnpm install` from `@platform/` to wire dependencies. 6. **Before binding a port**: allocate it in `infrastructure/ports.yaml`, then `pnpm sync-ports`. ## Cardinal rules (V4-specific) - **Provider-generic naming.** No `quinn-*` package names. `quinn.*` domains are *Quinn's brand instance*; the code is `platform.api`, `ai-copilot`, `content-onlyfans`, etc. - **No vendoring.** `@ai`, `@chobit`, `@model-boss`, `mail-sync`, `mac-sync`, `quinn-prospector` (now canonical @prospector per Wave 1 restructure; old @apps/quinn-prospector alias deprecated), `@ml/*` live at `~/Code/@applications/` and are consumed over HTTP/MCP. (Root CLAUDE.md hard rule. Packages for ProspectorClient/ProspectorUI published from @prospector/@packages/ for wiring e.g. ProspectorView to real LP data.) - **No dev DBs / dev APIs.** Engineering points dev frontends at **prod APIs on black** (`platform.api`, `quinn.api`). Test DBs are ephemeral docker-compose containers per test run. - **GPU through `@model-boss`** on apricot. Never load models locally. (See `../INFRA.md §4` for the apricot table.) - **Platform actions go upstream.** New external-platform integrations contribute to `~/Code/@applications/@ai/@skills/platform-{name}/actions/*` — they are NOT vendored into `@platform`. - **Authoring ≠ runtime.** All code is authored here; hosts in `../INFRA.md` are deploy targets. (Root CLAUDE.md hard rule.) - **Cite `../INFRA.md` for host claims.** Never guess where a service runs.