# CLAUDE.md — Mosaic Stack ## Project Self-hosted, multi-user AI agent platform. TypeScript monorepo. ## Stack - **API**: NestJS + Fastify adapter (`apps/gateway`) - **Web**: Next.js 16 + React 19 (`apps/web`) - **ORM**: Drizzle ORM + PostgreSQL 17 + pgvector (`packages/db`) - **Auth**: BetterAuth (`packages/auth`) - **Agent**: Pi SDK (`packages/agent`, `packages/mosaic`) - **Queue**: Valkey 8 (`packages/queue`) - **Build**: pnpm workspaces + Turborepo - **CI**: Woodpecker CI - **Observability**: OpenTelemetry → Jaeger ## Commands ```bash pnpm typecheck # TypeScript check (all packages) pnpm lint # ESLint (all packages) pnpm format:check # Prettier check pnpm test # Vitest (all packages) pnpm build # Build all packages # Database pnpm --filter @mosaicstack/db db:generate # Offline migration artifact generation mosaic-db-migrator --run # Sole PostgreSQL DDL runner mosaic-db-migrator --verify # Verified readiness; no URL/SQL/schema/role argv # db:push is disposable-local-only; db:migrate/storage migrate --run must delegate only to the runner. # Dev docker compose up -d # Start PG, Valkey, OTEL, Jaeger pnpm --filter @mosaicstack/gateway exec tsx src/main.ts # Start gateway ``` ## Conventions - ESM everywhere (`"type": "module"`, `.js` extensions in imports) - NodeNext module resolution - Explicit `@Inject()` decorators in NestJS (tsx/esbuild doesn't support emitDecoratorMetadata) - DTOs in `*.dto.ts` files at module boundaries - OTEL tracing imported before NestJS bootstrap (`import './tracing.js'`) - All three gates must pass before push: typecheck, lint, format:check