# caddie — agents.md

Project constitution. Inherits from `/srv/CLAUDE.md` (server scope) and
`/srv/apps/CLAUDE.md` (tenant scope). Only rules meeting the admission rubric
(failure-backed, tool-enforceable, decision-encoding, or triggerable) belong
here — no generic advice a model already applies. Budget: ~200 lines.

Model-independence: this file is the source of truth. `CLAUDE.md` is a symlink
to it so Claude Code loads the same content.

## Read first (in order)
1. **`brief.md`** — what this project is, and the stack decision.
2. **`.logs/planning/`** — the build plan: locked decisions, milestones, gates.
3. **`/srv/projects/standards/README.md`** — server-wide coding standards
   (dispatches by stack: `coding.md` → your stack doc → `frontend.md`).
4. **`.logs/handoff.md`** — newest-first; where the last session left off.

## Project-specific rules
- **Caddie has no workflow engine, and does not own the ball.** Stages are
  concurrent, declarative, human-advanced workstreams — never a state machine,
  never one-active-at-a-time, never conditional (plan D4, D13). Whose turn it
  is comes from the TOOL that owns the work, over the contract's status report;
  if you find yourself deriving turn state inside caddie, stop (D14).
- **Project context is dictionary-backed.** A new data point is created by
  searching existing `field_definitions` first; "create new" is the secondary
  action and must surface near-matches. Inconsistent labels across projects are
  the failure this exists to prevent (D15).
- **No caddie FK ever points at a kit table.** The kit instance id is
  referenced as a plain string; actor columns are username strings with
  display-name snapshots. Rebuild insurance (plan D5).
- **Identity is never caddie's to assert.** Launch tokens carry context and an
  advisory `sub`; tools authenticate against the IdP themselves. Never design
  a flow where a tool trusts caddie about who the user is (contract §0.2-0.3).
- **Comments live in the app that owns the subject; notifications aggregate
  into ONE inbox** (plan D11). Never give an app its own private bell, and
  never move comment storage into caddie — the first breaks cross-app
  seamlessness, the second dies with a caddie rebuild.
- **The tool report body is frozen** at the 6-state enum + counts + one opaque
  summary + seq (contract §5). The moment caddie grows a per-tool column or
  parses a summary, the contract has failed (plan D9).
- **Editing a template must be structurally unable to mutate live work**
  (plan D10) — caddie enforces it by deep copy at instantiation; punchlist by
  pinning immutable published template versions. Same invariant, two
  mechanisms; never blur them.
- **Vendored kit files and the standard test pack are scaffolder-owned** —
  never hand-edit them; product code lives in app-owned files, app tests
  extend via `tests/app_conftest.py` (bw-app-standard).
- **The shared chrome is the `caddie-ui` pack, canonical at
  `packs/caddie-ui/`.** Caddie's own copy in `main/frontend/src/caddie-ui/`
  is STAMPED (`packs/stamp-caddie-ui.sh /srv/apps/caddie`), never
  hand-edited: a change goes to the canonical copy, bumps `PACK_VERSION`,
  gets a README changelog line, and re-stamps every consumer. Three apps
  hand-rolled three bells in three weeks; the pack is what stops the fourth.
- **The app never draws a second bell, drawer or comment surface.** Caddie's
  page components map rows into the pack's `ThreadRow`s and wire the API to
  its callbacks (`Discussion.tsx`, `Bell.tsx`); the pack owns the look.

## Operational
- **Manage:** `srv-gw {deploy,restart,logs,status} --project caddie`.
- **Deploy confirmation:** the running version is visible (`/api/meta`, UI
  footer, or equivalent). Every change bumps it and adds a newest-first
  CHANGELOG line — the visible version is how you confirm a deploy landed.
- **Deploy gate — all three green before `srv-gw deploy`:**
  `npx tsc --noEmit` in `main/frontend`; the full backend suite from `main/`
  with the project venv, `/srv/apps/caddie/.bw-venv/bin/python -m pytest -q`
  (the system python has no fastapi); and
  `packs/stamp-caddie-ui.sh /srv/apps/caddie --check`.
- **Write access:** `caddie-dev` Unix group (setgid + default ACL). New files need
  `chmod 664` / dirs `775`, or `srv-gw fix-permissions --project caddie`,
  so the service user can read them.
- **Create new subdirectories under `sg caddie-dev`.** If the session's groups
  don't include `caddie-dev`, the kernel silently strips setgid on `chmod 2775`
  and files underneath get the wrong group.

## Layout
```
/srv/apps/caddie/          # workspace — docs and runtime state
├── brief.md  agents.md  CLAUDE.md -> agents.md
├── .logs/{planning/, handoff.md, diary.md}
├── .memory/  .archive/  notes/
├── packs/caddie-ui/       # the shared chrome — CANONICAL copy + stamp script
└── main/                  # the instance — code only
```
Runtime state (uploads, dumps) belongs at the workspace root, not in
`main/`. The compose file and `.env` sit at the workspace root because
`srv-gw deploy` requires them there — a documented deviation until T3.1.
