Files
initiative/CLAUDE.md

4.2 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Commands

pnpm check              # Merge gate — must pass before every commit (audit + knip + biome + typecheck + test/coverage + jscpd)
pnpm knip               # Unused code detection (Knip)
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 (EncounterStore, BestiarySourceCache). No business logic here.
  • Web — React adapter. Implements ports using hooks/state. All UI components, routing, and user interaction live here.

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.

Data & Storage

  • localStorage — encounter persistence (adapter layer, JSON serialization)
  • IndexedDB — bestiary source cache (apps/web/src/adapters/bestiary-cache.ts, via idb wrapper)
  • data/bestiary/index.json — pre-built search index for creature lookup, generated by scripts/generate-bestiary-index.mjs

Project Structure

apps/web/                  React app — components, hooks, adapters
packages/domain/src/       Pure state transitions, types, validation
packages/application/src/  Use cases, port interfaces
data/bestiary/             Bestiary search index
scripts/                   Build tooling (layer checks, index generation)
specs/<feature>/           Feature specs (spec.md, plan.md, tasks.md)
.specify/memory/           Project constitution

Tech Stack

  • TypeScript 5.8 (strict mode, verbatimModuleSyntax)
  • React 19, Vite 6, Tailwind CSS v4
  • Lucide React (icons)
  • idb (IndexedDB wrapper for bestiary cache)
  • Biome 2.0 (formatting + linting), Knip (unused code), jscpd (copy-paste detection)
  • Vitest (testing, v8 coverage), Lefthook (pre-commit hooks)

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/<feature>/ with spec.md, plan.md, tasks.md. The project constitution is at .specify/memory/constitution.md.
  • Quality gates are enforced at pre-commit via Lefthook's pnpm check — the project's single earliest enforcement point. No gate may exist only as a CI step or manual process.

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.