diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..68ddb2d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,51 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Commands + +```bash +pnpm check # Merge gate — must pass before every commit (format + lint + typecheck + test) +pnpm test # Run all tests (Vitest) +pnpm test:watch # Tests in watch mode +pnpm typecheck # tsc --build (project references) +pnpm lint # Biome lint +pnpm format # Biome format (writes) +pnpm --filter web dev # Vite dev server (localhost:5173) +pnpm --filter web build # Production build +``` + +Run a single test file: `pnpm vitest run packages/domain/src/__tests__/advance-turn.test.ts` + +## Architecture + +Strict layered architecture with ports/adapters and enforced dependency direction: + +``` +apps/web (React 19 + Vite) → packages/application (use cases) → packages/domain (pure logic) +``` + +- **Domain** — Pure functions, no I/O, no framework imports. All state transitions are deterministic. Errors returned as values (`DomainError`), never thrown. Adapters may throw only for programmer errors. +- **Application** — Orchestrates domain calls via port interfaces (e.g., `EncounterStore`). No business logic here. +- **Web** — React adapter. Implements ports using hooks/state. + +Layer boundaries are enforced by `scripts/check-layer-boundaries.mjs`, which runs as a Vitest test. Domain and application must never import from React, Vite, or upper layers. + +## Conventions + +- **Biome 2.0** for formatting and linting (no Prettier, no ESLint). Tab indentation, 80-char lines. Imports are auto-organized alphabetically. +- **TypeScript strict mode** with `verbatimModuleSyntax`. Use `.js` extensions in relative imports when required by the repo's ESM settings (e.g., `./types.js`). +- **Branded types** for identity values (e.g., `CombatantId`). Prefer immutability/`readonly` where practical. +- **Domain events** are plain data objects with a `type` discriminant — no classes. +- **Tests** live in `packages/*/src/__tests__/*.test.ts`. Test pure functions directly; map acceptance scenarios and invariants from specs to individual `it()` blocks. +- **Feature specs** live in `specs//` with spec.md, plan.md, tasks.md. The project constitution is at `.specify/memory/constitution.md`. + +## Constitution (key principles) + +The constitution (`.specify/memory/constitution.md`) governs all feature work: + +1. **Deterministic Domain Core** — Pure state transitions only; no I/O, randomness, or clocks in domain. +2. **Layered Architecture** — Domain → Application → Adapters. Never skip layers or reverse dependencies. +3. **Clarification-First** — Ask before making non-trivial assumptions. +4. **MVP Baseline** — Say "MVP baseline does not include X", never permanent bans. +5. **Every feature begins with a spec** — Spec → Plan → Tasks → Implementation.