Files
vdm/CLAUDE.md
T
samiandClaude Opus 5 facd851824
CI / clang-format (push) Canceled after 0s
CI / testserver (push) Canceled after 0s
CI / bootstrap-script (push) Canceled after 0s
CI / bootstrap-script-2604 (push) Canceled after 0s
CI / extension-lint (push) Canceled after 0s
CI / build (clang) (push) Canceled after 0s
CI / build (gcc) (push) Canceled after 0s
CI / sanitizers (dev) (push) Canceled after 0s
CI / sanitizers (tsan) (push) Canceled after 0s
CI / clang-tidy (push) Canceled after 0s
CI / conformance (push) Canceled after 0s
CI / nightly-integration (push) Canceled after 0s
CI / gui-dod (push) Canceled after 0s
CI / gui-dod-nightly (push) Canceled after 0s
docs: define the cross-platform porting strategy (ADR 0020, macOS first)
The tree is Ubuntu-first, but the Linux-specific surface is about ten files and
already sits at the bottom of the I/O and RPC stacks. Rather than fork the repo
or scatter ifdefs, platform differences go behind narrow seams with one backend
directory per OS, selected centrally in cmake/platform.cmake.

Linux stays the reference implementation and its behaviour does not change: the
owning lanes (CORE, DAEMON) move today's Linux code behind the seams on Ubuntu
first, with the suite still green, before any macOS code exists. A new PORT lane
owns only the per-OS backends, so macOS work never writes shared logic and
CLAUDE.md's lane rule stays intact.

Adds ADR 0020 (the decision and phases), docs/08-porting.md (seam list, API
mapping for macOS and Windows, dependency table, verification gates) and
docs/agents/AGENT-PORT.md (the lane brief), plus the PORT row in the ownership
table.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-15 17:36:27 +04:00

3.6 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
PORT **/platform/<os>/**, cmake/platform*.cmake, packaging/macos/, packaging/windows/ all logic — see ADR 0020

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.