Skip to content

Latest commit

 

History

History
106 lines (83 loc) · 5 KB

File metadata and controls

106 lines (83 loc) · 5 KB

AGENTS.md

Guidance for coding agents working in this repository. Humans: see README.md to run it and docs/ for the full design.

What this is

An AI-driven, web-based D&D experience: an LLM Dungeon Master narrates, a deterministic rules engine adjudicates, multiple players share a real-time session, and art is generated on demand. Monorepo of npm workspaces (packages/engine, protocol, server, web).

Read docs/architecture.md first — it's the code map and the turn-flow walkthrough. The deeper rationale is in docs/DESIGN.md (cited from source comments as docs/DESIGN.md §N).

The invariant you must not break

The engine is the source of truth; the LLM only narrates.

The LLM proposes actions through the tool layer (server/src/gameEngine.ts); the engine (packages/engine) validates, rolls dice (seeded), and applies results. The model never sets HP, decides hits, or invents numbers. If a change would let the LLM mutate state directly, it's wrong — route it through a tool that calls the engine.

Setup & commands

Node 20+ (CI uses 22). From the repo root:

npm install
npm run build --workspace @ai-dm/engine   # MUST build engine first — others consume its dist/
npm run typecheck                          # all workspaces
npm test                                   # engine unit tests + server integration tests

Run locally:

npm run dev:server   # http + ws on :8787  (scripted DM, JSON store — no cloud needed)
npm run dev:web      # Vite on :5173, proxies /api and /ws to the server

A single package: append --workspace @ai-dm/<name> to typecheck/test/build.

Before you say "done"

Always, from the root: npm run build --workspace @ai-dm/engine && npm run typecheck && npm test. If you touched a package's behavior, add or update its tests. Report failures with the actual output — don't claim green you haven't seen. Tests are colocated as *.test.ts (engine: pure unit tests; server: backend.test.ts + focused loop/memory/dm tests).

Code conventions

  • Strict TypeScript (tsconfig.base.json): strict, noUncheckedIndexedAccess, noImplicitOverride, verbatimModuleSyntax.
  • ESM / NodeNext: relative imports use a .js extension even from .ts files (e.g. import { x } from "./store.js"). Type-only imports use import type.
  • Seeded randomness only. Never call global Math.random() in the engine or game logic — use the session's RNG, so turns replay identically and snapshots are exact.
  • Wire types live in @ai-dm/protocol. Don't redefine DTOs/messages in the web; import them. Changing a shape? Update protocol, then both sides.
  • Match the surrounding style (comment density, naming, idiom). Files carry a short top-of-file comment explaining their role and citing docs/DESIGN.md §N where relevant — keep that habit.
  • Client never sees enemy stat blocks. CreatureView.sheet is for PCs only.

Where things live

You want to change… Look in
Rules / dice / combat math packages/engine/src/*
What the DM can do (tools) server/src/gameEngine.ts
DM prompt / context / scripted fallback server/src/dm.ts, geminiDm.ts
The turn loop / WebSocket server/src/index.ts
Session shape, snapshots, toView server/src/session.ts
DM memory (recap / key facts) server/src/memory.ts
Long-term recall (embeddings, retriever, recall() tool) server/src/embeddings.ts, recall.ts
Persistence server/src/store.ts, postgres.ts
Scaling (broadcast/lock/presence) server/src/realtime.ts, runtime.ts
Character building / spells / inventory / XP server/src/srd.ts, srdContent.ts
REST endpoints server/src/routes.ts
Wire types packages/protocol/src/index.ts
UI screens / play table packages/web/src/screens/*, components.tsx

Git & deployment

  • This repo deploys on push to main via GitHub Actions → Cloud Run. Don't push or commit unless the user asks; branch off main if they do.
  • Commit messages end with the trailer: Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
  • After a deploy, verify the run's conclusion (gh run view <id> --json conclusion), not just that the command exited — gh run watch can report success for a run that already failed.
  • Deployment setup and topology: docs/DEPLOY.md; infra is Terraform in infra/.

Gotchas learned the hard way

  • Build the engine before typecheck/test, or you'll hit Cannot find module '@ai-dm/engine'.
  • Backtick characters inside SQL string templates in postgres.ts break the JS template literal — avoid them in comments there.
  • ensureCharacterFields runs on read and must stay idempotent (returns true only when it actually changed something). New backfills go there.
  • Cloud Run reserves /healthz at the frontend — the health endpoint is /api/health.