Rules every change follows. CI enforces what it can; the rest is review.
- Dependencies point strictly down the crate map in
docs/architecture.md. Adding an upward or sideways dep is an architecture change: discuss it in the PR body. rds-coreis a leaf: no io, no async runtime, no platform code.crates/rds-core/tests/layering.rsenforces the manifest side.- Shared identity/address types (
EndpointId,EndpointAddr,RelayUrl,SecretKey,TransportAddr) are owned byrds-coreand re-exported byrds-net. Backend-native types (iroh, noq) never appear in service surfaces — convert inside the backend adapter (rds_net::backends::iroh::convert). - No new third-party dependency without need: prefer standards,
thin FFI bindings to OS/driver APIs, and our own protocol code.
Justify in the PR description;
deny.tomlgates licenses. - Public API of a crate lives in
lib.rsre-exports; platform modules may bepubbut unstable surfaces are#[doc(hidden)]or doc-noted.
unsafeis confined to platform-backend modules (rds-desktopcapture/codec/input and native AppKit icon/quality/clipboard adapter,rds-netsocket layer, and the read-onlyrds-discovery/clock/macos.rsboot-identifier adapter). Workspace lint flags it everywhere else; backends opt out per module with a// SAFETY:note per block.- Never trust the wire: every decoder/parser bounds its inputs; every
record verifies before use (
rds-discoverydoes this onput).
- Library crates return typed errors (
thiserror); binaries may useanyhow. Nounwrap/expectoutside tests and impossible-invariant paths (commented). - Tokio is the only runtime. No
std::threadfor core loops;spawn_blockingfor sync FFI (capture backends, codecs).rds-observeisolates synchronous stderr in one bounded output adapter thread, outside service/transport loops; a stuck OS write must not hold Tokio runtime shutdown. See observability for the bounded wait and explicit possible record loss. - No unbounded queues on latency paths: bounded
mpsc, drop-stale policy at the producer, never let backlog accumulate.
rds-coreowns RDS control wire types; postcard + explicit length prefix; 64 KiB max frame on control paths. The async frame read/write half lives inrds-net::wire(re-exported asrds_net::{read_frame, write_frame}) sords-corestays runtime-free. Media streams carry raw codec bitstream with a fixed header — no serde in the hot path.- Standard SSH framing, key exchange and key formats belong to
russh, behindrds-ssh; do not duplicate them as RDS control messages. - Transport protocol selection uses ALPN (
rds/0,rds-relay/0). Signed objects and local IPC also carry independent explicit versions: grant v3 and IPC v5 require a coordinated upgrade without weakening authorization — v2 grants still verify, but a deployment that pins the v3 tenant/policy claims refuses them. General remote capability negotiation remains W2.2.
- One backend per file;
#[cfg(target_os)]on the module declaration, not inside functions. Preference orders are fixed and documented indocs/platforms.md. - A backend that probes unavailable returns
Ok(None); present-but- broken returnsErr— and the demotion is logged.
cargo fmt --check,cargo clippy --workspace --all-targets -- -D warnings,cargo test --workspace— green on Ubuntu and macOS in CI.- Feature lanes:
--features rds-desktop/x11on Linux;--features rds-agent/desktop,rds-cli/desktopon both OSes — the desktop feature must compile everywhere, not only where it runs. - Protocol/interop tests live in
tests/of the owning crate; e2e transport tests must not require a display. - Benchmarks are acceptance gates for the transport and media work —
numbers land in
docs/reports/per roadmap.
Native CMake dependencies use an out-of-source build directory and a local install prefix under the Cargo output. Reuse a configured native cache only with the same compiler/toolchain identity. If that identity changes, preserve the failed evidence and configure a fresh scoped build tree with all required flags together. An unexpected system install path is a configuration failure; do not elevate privileges or widen global directory permissions to finish it. See CMake build trees and install prefix.
- English only. Signed commits on
main(ruleset enforced). - Docs-as-code: architecture decisions in
docs/architecture.md, research indocs/research.md, platform facts indocs/platforms.md. A design change that doesn't update its doc is incomplete.