Files
vdm/CLAUDE.md
samiandClaude Sonnet 5 1aed222ae2 docs: ADR-number convention in CLAUDE.md §7 — second merger renumbers
Six lanes pick ADR numbers with no allocator. This lane dodged one collision
by taking 0012 while DAEMON drafted 0011, and just hit a real one — two 0014s
in the same integration round. Codify what already happened in practice: take
the next free number in main's docs/adr/, and on collision whoever merges
second renumbers and fixes cross-refs rather than round-tripping.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_012fgjnqFCS5h5L7gZTZo3rV
2026-09-10 15:31:01 +04:00

3.5 KiB

Rules of engagement — agents working in this repo

Read this before touching anything. Then read your lane brief in docs/agents/.

1. Stay in your lane

Lane Owns Never writes
PROTO contracts/, tools/mockd/, tests/conformance/ everything else
CORE core/, tools/bench/, tools/fuzz/ daemon/, gui/, extension/, contracts/
DAEMON daemon/, cli/, nmhost/, packaging/nativehost/ core/, gui/, extension/, contracts/
GUI gui/ everything else
EXT extension/ everything else
PKG/QA packaging/, .github/, tools/testserver/, tests/integration/, tests/e2e/, root build files any lane's feature code

If your task seems to require editing another lane's files, that is a signal the interface is wrong. File the request; don't reach across.

2. contracts/ is sacred

  • Only PROTO commits there.
  • Generated code (core/generated/, extension/src/shared/protocol/) is committed and must never be hand-edited. Fix the schema, regenerate.
  • Need a new field? Open a contracts/-only PR: schema + fixtures + regenerated code + VERSION bump. Optional field or new method = minor; rename/remove/retype = major + ADR.
  • Working around a wrong contract locally is the single failure mode most likely to sink this project. Don't.

3. Layering

core        → no JSON, no SQL, no Qt, no RPC. Ever.
daemon      → depends on core. No Qt.
gui / ext   → zero download logic. They render state and forward user intent.
nmhost      → a dumb pipe. Under 300 lines. No logic.

A grep for curl|pwrite|sqlite in gui/ must come back empty. Same for download logic in extension/.

4. Non-negotiable behaviours

  • Capture fails open. Daemon down, slow, or erroring → Firefox downloads normally. Never swallow a user's download. capture.offer answers within 750 ms or the extension gives up.
  • Resume is validated. If-Range with ETag/Last-Modified; a 200 where 206 was expected means the file changed — ask the user, never silently corrupt.
  • Never bind beyond 127.0.0.1. The WS transport is token-authenticated, origin-checked, and rate-limited.
  • Secrets go to the Secret Service, never SQLite, never logs.
  • Paths are canonicalized and checked against allowed roots before any write.
  • No allocation in the transfer hot path.

5. Definition of done, everywhere

Code + tests + docs updated in the same change. A feature with no test does not exist. If you change observable behaviour, update the doc in docs/ that describes it in the same PR.

6. Style

  • C++23, -Wall -Wextra -Werror, clang-format (config at root), clang-tidy clean.
  • TypeScript strict mode, ESLint, no any on protocol boundaries.
  • Commit messages: lane: imperative summary (e.g. core: add dynamic segment stealing).
  • One logical change per commit. Rebase onto main; no merge commits.

7. When you're unsure

Ask in the PR rather than guessing at the interface. A day of clarification is cheaper than an M2 integration rewrite. And record real decisions as an ADR in docs/adr/ — the next agent to touch this will have none of your context.

ADR numbers: there is no allocator. Take the next free number in main's docs/adr/ (gaps from reserved-but-unwritten entries are fine to fill). Lanes draft in parallel, so collisions happen: whoever merges second renumbers, updates any cross-references, and keeps going — it is not worth a round trip.