# AGENTS.md This document defines the laws, principles, and rule sets that govern this codebase. Any agent or developer making changes has to adhere to these rules. **Before starting off** — Read the README.md file to understand the project's goals and objectives. --- ## Agent Rules (Override Everything) 1. **No testing by yourself** — All testing is done by the team. 2. **No assumptions about code or domain logic** — Always confirm and be sure before making changes. 3. **No running scripts** — Do not run build, dev, test, or migrate scripts unless explicitly approved. More rules are only to be added by the human, in case such a suggestion becomes viable. --- ## 1. Project Overview - **Monorepo**: Turbo repo - **Package Manager**: pnpm - **Language**: TypeScript everywhere - **Node**: >= 24 > **Note**: The monorepo architecture is currently in flux. Some patterns are being refined; follow existing conventions and confirm before introducing new ones. ### Applications | App | Purpose | | ---------------- | ----------------------------------------------------------------------------------- | | `apps/main` | SvelteKit UI — the primary user-facing application | | `apps/processor` | Hono web server — intended for asynchronous processing (jobs, workers). Currently minimal; structure is evolving. | ### Packages Packages live under `packages/` and are **standalone, modular** pieces consumed by apps: | Package | Purpose | | ------------- | -------------------------------------------- | | `@pkg/logic` | Domain logic (DDD, controllers, repositories) | | `@pkg/db` | Drizzle schema, database access | | `@pkg/logger` | Logging, `getError` for error construction | | `@pkg/result` | Result type, `ERROR_CODES`, `tryCatch` | | `@pkg/keystore` | Redis instance (sessions, 2FA, etc.) | | `@pkg/settings` | App settings / env config | ### Data Stores - **PostgreSQL (Drizzle)** — Primary relational data (auth, users, accounts, etc.) - **Redis (Valkey)** — Sessions, 2FA verification state (via `@pkg/keystore`) Additional stores (NoSQL DBs, R2, etc.) may be introduced later. Follow existing domain patterns when adding new data access. --- ## 2. The Logic Package: DDD + Layered Architecture The `@pkg/logic` package contains **all domain logic**. It follows: 1. **Domain-Driven Design (DDD)** — Bounded contexts as domains 2. **Layered architecture** — Clear separation of concerns 3. **Result-style error handling** — Errors as values; avoid try-catch in domain code ### Domain Structure Each domain is a folder under `packages/logic/domains/`: ``` domains/ / data.ts # Types, schemas (Valibot) repository.ts # Data access controller.ts # Use cases / application logic router.ts # HTTP routes (when exposed via API) errors.ts # Domain-specific error constructors (using getError) ``` Not every domain has a router (e.g. auth uses `config.base.ts` with better-auth). Add new domains as needed; mirror existing patterns. ### Path Aliases (logic package) - `@/*` → `./*` - `@domains/*` → `./domains/*` - `@core/*` → `./core/*` ### Flow Execution Context Domain operations receive a `FlowExecCtx` (`fctx`) for tracing and audit: ```ts type FlowExecCtx = { flowId: string; userId?: string; sessionId?: string; }; ``` --- ## 3. Error Handling: Result Pattern (neverthrow) Errors are **values**, not exceptions. The codebase uses Result-style handling. ### Current Conventions 1. **Logic package** — Uses `neverthrow` (`ResultAsync`, `okAsync`, `errAsync`) for async operations that may fail. 2. **`@pkg/result`** — Provides `Result`, `ERROR_CODES`, and `tryCatch()`. The `Result` type is legacy; as the project is moving toward neverthrow. Use `ERROR_CODES` for consistent error codes. 3. **`getError()`** — From `@pkg/logger`. Use at boundaries when converting a thrown error to an `Err` object: `return getError({ code: ERROR_CODES.XXX, message: "...", description: "...", detail: "..." }, e)`. 4. **Domain errors** — Each domain has an `errors.ts` that exports error constructors built with `getError`. Use these instead of ad-hoc error objects. 5. **Check before use** — Always check `result.isOk()` / `result.isErr()` before using `result.value`; never assume success. ### Err Shape ```ts type Err = { flowId?: string; code: string; message: string; description: string; detail: string; actionable?: boolean; error?: any; }; ``` --- ## 4. Frontend (Main App) The main app is a **SvelteKit** application with a domain-driven UI structure. ### Structure - **Routes**: File-based routing under `src/routes/`. Layout groups (e.g. `(main)`, `auth`) wrap related pages. - **Domain-driven UI**: Feature code lives under `src/lib/domains//` — each domain has its own folder with view models and components. - **View Model (VM) pattern**: Domain logic and state for a screen live in `*.vm.svelte.ts` classes. VMs hold reactive state (`$state`), orchestrate API calls, and expose methods. Pages import and use a VM instance. - **API layer**: A typed Hono client (`hc`) is used against a Router composed from logic package routers. The API is defined in `$lib/api.ts` and proxied through SvelteKit route handlers at `/api/v1/[...paths]`. Auth/session context is injected at the proxy layer. ### Context Injection Logic routers receive `user`, `session`, and `fCtx` via `c.env.locals`. The shape is defined in `HonoContext` (`@core/hono.helpers`). The API proxy builds this context from the session before forwarding requests. ### Global Stores Shared state (e.g. `apiClient`, `user`, `session`, `breadcrumbs`) lives in `$lib/global.stores.ts`. ### Conventions - Pages are thin: they mount a VM, render components, and wire up lifecycle. - VMs own async flows, polling, and error handling for their domain. - UI components under `$lib/components/` are shared; domain-specific components live in `$lib/domains//`. --- ## 5. Processor App The processor is a **Hono** server intended for **background workers** and async jobs. Its structure is still evolving. ### Current State - Minimal Hono server; no BullMQ or job processors yet. - When workers are added, processing logic should live under `src/domains//` and call into `@pkg/logic` controllers and repositories. - HTTP routes will expose internal APIs (e.g. task status, webhooks), secured (e.g. API key), for use by the main app or external services. - Async work should be triggered by calling the processor HTTP API, not by importing job queues in the main app or logic package. ### Conventions (when implemented) - The worker processes jobs; do not block it with long-running HTTP logic. - Job payloads should be validated before processing. - Follow existing domain patterns for controllers and repositories. --- ## 6. Validation & Schemas - **Valibot** is used for schema validation in the logic package. - Domain data types are defined in `data.ts` per domain. - Use `v.InferOutput` for TypeScript types. - Routers use `sValidator` from `@hono/standard-validator` with Valibot schemas for request validation. --- ## 7. Package Naming - Apps: `@apps/*` (e.g. `@apps/main`, `@apps/processor`) - Packages: `@pkg/*` (e.g. `@pkg/logic`, `@pkg/db`, `@pkg/logger`)