Skip to content

docs(adr): Linux-first Rust port — one core, per-OS backends - #18

Merged
chaodu-agent merged 2 commits into
mainfrom
adr/linux-rust-port
Sep 27, 2026
Merged

chaodu-agent merged 2 commits into
mainfrom
adr/linux-rust-port

Conversation

@chaodu-agent

Copy link
Copy Markdown
Contributor

Adds ADR for the Linux-first Rust port decision (Proposed).

Closes the design discussion in #15 by recording:

  • Rewrite in Rust, Linux-first, as one cross-platform core with per-OS backends behind a PlatformBackend trait (#[cfg(target_os)]).
  • Keep Swift as a transitional macOS backend; retire after the Rust macOS backend (objc2/core-graphics FFI) reaches parity.
  • Alternatives considered (Swift-for-Linux, immediate full-Rust, two permanent codebases, Node/Go) and why rejected.
  • Verified rpi1 environment (Debian 13, labwc/Wayland, grim/wlr-randr, /dev/uinput).
  • Validation plan: PoC on rpi1 before marking Accepted.

Refs #15.

@chaodu-agent

Copy link
Copy Markdown
Contributor Author

Independent review — two reviewers, both NEEDS_CHANGES

Two independent reviewers (fable / claude-fable-5.1, sol / gpt-5.6-sol) reviewed this ADR in parallel. Both returned NEEDS_CHANGES and independently converged on the same weaknesses.

Convergent findings

  1. The ~62% figure is misleading — rewrite ≠ port. "Platform-agnostic" is not "reusable": zero Swift lines carry over. The 62% (auth, reverse-attach, JSON-RPC, upstream proxy, job registry) must be re-implemented in Rust and re-earn every security property. That is the harder part; the "shell out to grim/ydotool" de-risking applies only to the ~640-line minority. The risk framing is backwards.
  2. Security parity of reverse-attach is unaddressed and untested. WSS dial-out + sha256 verifier + credential-never-in-shell + per-connection tool profiles is a bespoke auth/authz protocol. A Rust reimplementation risks divergence (constant-time verifier compare, TLS/cert handling, WS upgrade/origin checks, profile enforcement at dispatch). The Validation PoC (initialize + sys_info + screenshot) exercises none of it — the highest-risk component is untested before "Accepted."
  3. "Single static binary / minimal deps" contradicts the plan. tokio + hyper + rustls + tungstenite is a large transitive tree; and shelling out to grim/ydotool/wlr-randr + ydotoold daemon + root-only /dev/uinput means external prerequisites, not scp-and-run. TLS stack (rustls vs native) is unspecified.
  4. Wayland verified on exactly one hand-configured Pi. grim/wlr-randr are wlroots-specific (won't work on GNOME/KDE without xdg-desktop-portal/PipeWire). Worse, cheap headless Linux VMs often have no compositor / WAYLAND_DISPLAY / seat — colliding with the "scale on cheap Linux" thesis. Screenshot/input need a live graphical seat.
  5. The biggest unknown (Phase 2) is scheduled last. objc2/ScreenCaptureKit + TCC + macOS signing/notarization from a Rust toolchain is the largest technical risk; if it proves impractical, the "converge to one codebase / retire Swift" endgame collapses into the exact two-codebase trap the ADR rejects.
  6. Missing alternatives. (a) "Thin Rust/Go Linux host, keep the proven Swift core" hybrid — ships Linux with far less re-secured surface. (b) Swift-on-Linux + shell-out — the ADR rejects Swift-on-Linux for "weak systems ecosystem," but the shell-out plan neutralizes that objection; the rejection is partly self-contradictory.

Agreed actionable changes

  1. Reframe 62% honestly (re-implementation, not reuse); add a versioned MCP + reverse-attach conformance/differential test suite as the shared anti-drift contract for both backends.
  2. Put auth + reverse-attach into the Phase-1 Validation gate (WSS + verifier + constant-time compare + tool profiles), not just initialize/sys_info/screenshot, before Status → Accepted.
  3. Resolve the headless/seat contradiction: specify headless compositor vs "graphical seat required" provisioning; verify on a non-hand-configured node, not just rpi1.
  4. Pin the deps/deployment reality: choose rustls explicitly; enumerate the tokio/hyper/ws set with cargo-audit/deny; define the external-CLI/udev/uinput/ydotoold provisioning story; reconcile with "single static binary."
  5. Move the macOS objc2/ScreenCaptureKit/TCC + signing/notarization spike earlier (Phase 0/1.5); add the "thin Rust/Go host, keep Swift core" alternative and give Swift-on-Linux+shell-out a fair re-evaluation.

The direction (Linux-first, converge later, strangler-fig) is reasonable; the ADR is Accept-able only after it stops leaning on the 62% framing, tests its highest-risk components before declaring victory, and de-risks the macOS endgame it depends on. The ADR is being revised on this branch to incorporate these points (kept Proposed).

Records the decision to rewrite in Rust, Linux-first, as one cross-platform core with per-OS backends behind a PlatformBackend trait; keep Swift as a transitional macOS backend until the Rust macOS backend reaches parity, then retire. Refs #15.
Incorporates convergent NEEDS_CHANGES findings: reframe 62% as re-implementation not reuse; add reverse-attach conformance suite + put auth/reverse-attach in the validation gate; add Phase 0 macOS-FFI and headless/seat spikes; pin rustls + dependency reality; add thin-host and reconsider Swift-on-Linux alternatives; add Open questions. Refs #15.
@chaodu-agent
chaodu-agent merged commit 1938885 into main Sep 27, 2026
3 of 4 checks passed
@chaodu-agent
chaodu-agent deleted the adr/linux-rust-port branch September 27, 2026 14:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant