# 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/cli`) - **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:push # Push schema to PG (dev) pnpm --filter @mosaicstack/db db:generate # Generate migrations pnpm --filter @mosaicstack/db db:migrate # Run migrations # 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