Files
initiative/CLAUDE.md
Lukas a89fac5c23 Slim CLAUDE.md with progressive disclosure, add project purpose
Move niche conventions (component props, export compat) to
docs/conventions.md, trim Speckit/Constitution sections to link to
source files, and add a one-line project description.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 23:07:18 +02:00

5.5 KiB

CLAUDE.md

Initiative is a browser-based combat encounter tracker for tabletop RPGs (D&D 5.5e, Pathfinder 2e). It runs entirely client-side — no backend, no accounts — with localStorage and IndexedDB for persistence.

Commands

pnpm check              # Merge gate — must pass before every commit (audit + knip + biome + oxlint + typecheck + test/coverage + jscpd + jsinspect)
pnpm oxlint             # Type-aware linting (oxlint — complements Biome)
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 check:props        # Component prop count enforcement (max 8)
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 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/NNN-feature-name/    Feature specs (spec.md, plan.md, tasks.md)
.specify/                  Speckit config (templates, scripts, constitution)
docs/agents/               RPI skill artifacts (research reports, plans)
.claude/skills/            Agent skills (rpi-research, rpi-plan, rpi-implement)

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.4 (formatting + linting), oxlint (type-aware linting), Knip (unused code), jscpd (copy-paste detection), jsinspect-plus (structural duplication)
  • Vitest (testing, v8 coverage), Lefthook (pre-commit hooks)

Conventions

  • Biome 2.4 for formatting and linting (no Prettier, no ESLint). Tab indentation, 80-char lines. Imports are auto-organized alphabetically.
  • oxlint for type-aware linting that Biome can't do. Configured in .oxlintrc.json.
  • TypeScript strict mode with verbatimModuleSyntax. Use .js extensions in relative imports.
  • 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 from specs to individual it() blocks.
  • Quality gates are enforced at pre-commit via Lefthook (parallel jobs). No gate may exist only as a CI step or manual process.

For component prop rules, export format compatibility, and ADRs, see docs/conventions.md.

Self-Review Checklist

Before finishing a change, consider:

  • Is this the simplest approach that solves the current problem?
  • Is there duplication that hurts readability? (But don't abstract prematurely.)
  • Are errors handled correctly and communicated sensibly to the user?
  • Does the UI follow modern patterns and feel intuitive to interact with?

Speckit Workflow

Specs are living documents in specs/NNN-feature-name/ that describe features, not individual changes. Use /speckit.* and RPI skills (rpi-research, rpi-plan, rpi-implement) to manage them — skill descriptions have full usage details.

Scope Workflow
Bug fix / CSS tweak Just fix it, commit
Small change to existing feature /integrate-issue → implement → commit
Larger addition to existing feature /integrate-issuerpi-researchrpi-planrpi-implement
New feature /speckit.specify/speckit.clarify/speckit.plan/speckit.tasks/speckit.implement

Research scope: Always scan for existing patterns similar to what the feature needs. Identify extraction and consolidation opportunities before implementation, not during.

Constitution

Project principles governing all feature work are in .specify/memory/constitution.md. Key rules: deterministic domain core, strict layer boundaries, clarification before assumptions.