Changelog
Entries under Unreleased go into the next release’s notes; scripts/release-notes.sh
builds the GitHub release body from the matching ## <version> section.
Unreleased
0.5.0 — 2026-10-07
Changed
- Breaking:
rdc serverefuses to run with root privileges (thanks @Mrigbozurike). It never needs them and a remote-control surface should not hold them; started with a real or effective uid of 0 (sudo rdc serve, a system-level unit, a container whose process is root, a setuid-root binary) it exits with a message. Run it as the desktop user instead.rdc doctorreports the process user and flags root. Unix only.
Added
- Audit lines record the focused window and the screenshot hash. Screenshot, input, focus
and clipboard entries carry
window(app: titleof the window that had focus when the request arrived, sanitised and truncated like every other field), and screenshot entries carryscreenshot_sha256of the bytes returned, so an action can be tied to what was on screen and a saved image to the line that produced it. The lookup is a direct focused-window query per platform —GetForegroundWindowon Windows,hyprctl activewindowon Hyprland,NSWorkspace’sactiveApplicationon macOS — and reads the title and application of that one window, rather than enumerating the desktop. It runs off the request thread under one timeout for every backend;rdc doctorreports how long it takes. Titles are recorded by default and can carry document names, URLs and mail subjects, in the local log and in any audit stream;[serve.audit].window_titles = falseomits them (thanks @Mrigbozurike). - The systemd
--userunit is sandboxed.rdc service installwritesNoNewPrivileges, a@system-servicesyscall filter minus@privileged/@resources,RestrictAddressFamilies,RestrictNamespaces/RestrictRealtime/RestrictSUIDSGID/LockPersonalityandUMask=0077into the unit, and the directives that need user namespaces (PrivateUsers, an empty capability set, theProtect*family,ProtectSystem=strict,ProtectHome=read-only,PrivateTmpwith the X11 socket bound back) into a drop-in written only when a realsystemd-run --userprobe starts a transient unit carrying them, since those would otherwise stop the unit from starting at all. Paths are quoted and%escaped, so a binary or audit directory containing a space or a percent sign is written correctly. Installing restarts a running daemon rather than leaving the old one in place, and the unit isType=exec, so install can wait pastRestartSecand confirmNRestartsis 0 instead of mistaking a restart loop for success (thanks @Mrigbozurike).
0.4.0 — 2026-09-11
Added
- Audit streaming.
[serve.audit] stream = "http://…/v1/ingest"(orrdc serve --audit-stream URL) POSTs every audit entry, batched asapplication/x-ndjson, to an HTTP endpoint, with retry and backoff; the local file stays the record.stream_tokenadds a bearer token for third-party collectors. rdc audit-view, a live audit viewer: receives streams from any number of daemons (and follows local files with--follow), stores them, and serves a page that updates as entries arrive, with text, outcome and host filters. Same gate as the daemon: Tailscale bind, Host check,whoisidentity, allowlist. Configured under[audit_view].- Audit entries carry
host(the daemon’s node name, the first label of its MagicDNS name); the viewer addsvia(the sending node) and never trusts the sender for it. Old lines withouthoststill parse.
Changed
- Release flow: pull requests target a
release/<version>branch, which is tested on real machines before a reviewed merge intomain.mainis protected. CONTRIBUTING and AGENTS spell out the testing bar: unit tests for new logic, a regression test per bug fix, and a router test for anything touching authentication, capabilities, routes or the audit log. - Router tests (
src/server/tests.rs) drive the real axum stack with a fake desktop and a fake identity table: Host check, unknown and non-Tailscale peers, per-capability denials, screenshot headers, and audit completeness and sanitisation.
Fixed
- Audit completeness that 0.3.0’s notes claimed but did not ship:
whoami,/health, unknown routes, malformed action bodies and screenshot parameter errors are now written to the audit log. The 0.3.0 release only fixed the middleware’s recorded status.
Changed
- Windows: the scheduled task no longer runs elevated by default (thanks @Mrigbozurike).
rdc service installnow registers the logon task atLeastPrivilegerun level, so the daemon holds only the user’s standard token and the install itself no longer needs an Administrator shell. Input aimed at elevated windows is dropped by UIPI in this mode; passrdc service install --elevated(from an elevated PowerShell) to get the previousHighestAvailablebehaviour. Existing installs keep their run level until reinstalled. - Windows setup docs scope the firewall rule to the tailnet (
100.64.0.0/10, Tailscale interface). - Docs: the configuration guide now shows the Tailscale access-policy rule (
grantsandaclsforms) that must accompany rdc’s grants, and the troubleshooting table distinguishes a policy timeout from an rdc 403.
0.3.0 — 2026-09-10
Added
- Config file permission check (Unix) (thanks @Mrigbozurike).
rdc serveandrdc service installrefuse to run whenconfig.tomlor its directory is owned by another user or writable by group/others, because editing the allowlist is equivalent to desktop access.rdc doctorreports the check asconfig perms;RDC_INSECURE_CONFIG=1downgrades the refusal to a warning. - Windows support, verified on Windows 11.
rdc service installcreates an elevated Task Scheduler logon task that runs the daemon in the interactive session with a log file;service uninstallstops the running daemon. Windowfocusimplemented (foreground-thread attach with an Alt-tap fallback). Absolute pointer moves useSendInputover the whole virtual desktop so secondary monitors are addressable (untested on real hardware yet). --log-file/RDC_LOG_FILEto append logs to a file instead of stderr.
Fixed
- Windows: the service path no longer carries the
\\?\verbatim prefix.
0.2.1 — 2026-09-09
Changed
- License is now GPL-3.0-or-later (was AGPL-3.0-or-later). rdc is a program you run on your own machines, not a hosted service, so the AGPL network clause added friction without protecting anything; plain GPL keeps the requirement that distributed modifications are published. There are no external contributions to date, so no consent was needed.
- GitHub releases carry the changelog section for the version as their notes.
- CONTRIBUTING asks for DCO sign-off (
git commit -s).
0.2.0 — 2026-09-09
Added
- Capabilities. Grants can limit an identity to
view,inputand/orclipboard. Config accepts plain strings (full control), inline tables{ who = "...", can = [...] }insideallow, or[[serve.grant]]blocks; the CLI accepts--allow who=view,clipboard. Missing capability →403 forbidden.whoamireportscaps. - Audit log. One JSON line per authorized request or rejection (host, identity and
capability denials included) with identity, action summary, outcome and duration. Mode 0600,
size-rotated, configurable under
[serve.audit]. Newrdc auditcommand to read it. rdc doctorprints the configured grants and the audit log path.
Changed
--allowand[serve].allowentries are now grants; existing plain-string configs behave exactly as before (full control).
0.1.0 — 2026-09-08
First public release. Remote desktop control for AI agents over Tailscale: screenshot, mouse, keyboard, window focus and clipboard as MCP tools and a CLI. Tailscale whois identity with an allowlist, Host-header check, input validation. Verified on Linux (Hyprland) and macOS (Apple silicon); Windows compiles but is untested.