distribution
Desktop launcher internals
Desktop launcher internals
What this page does
Architecture walkthrough of the deputyos-desktop crate — the
“download + double-click → wizard in browser” launcher for Linux,
Windows, and macOS. The launcher is a Rust binary per platform that
consumes existing deputyOS image artefacts (the same qcow2 / img.xz
files that ship for the QEMU and Pi targets) and orchestrates the
host’s native virtualization to boot them.
The user-facing surface is documented in Reference → CLI → deputyos-desktop; this page is the implementation-side reference for contributors and auditors.
Crate architecture
deputyos-desktop/
├── src/
│ ├── main.rs ← CLI dispatch (clap)
│ ├── lib.rs ← public modules
│ ├── config.rs ← cache locations, version pinning, prefs
│ ├── manifest.rs ← reuses deputyctl::release types for verify
│ ├── download.rs ← image fetch + sha256 + minisig verify
│ ├── browser.rs ← cross-platform "open URL" shim
│ ├── driver.rs ← Driver trait + `current_driver()` factory
│ └── drivers/
│ ├── mod.rs
│ ├── linux.rs ← qemu+KVM driver
│ ├── windows.rs ← WSL2-mandate driver
│ └── macos.rs ← UTM-mandate driver
└── Cargo.toml
The user-facing CLI surface
deputyos-desktop install # prereq + download + cache + import
deputyos-desktop start # boot VM + open browser. Default action.
deputyos-desktop stop # graceful shutdown
deputyos-desktop status # running/stopped + URL
deputyos-desktop update # check manifest + (not yet implemented) apply
deputyos-desktop uninstall [--data] # remove cache; --data also wipes data dir
Invoking with no subcommand mimics double-click: install (if needed), start, then open the wizard URL in the default browser. That’s the “non-technical user double-clicks the icon” path.
Driver model
Each platform implements the Driver trait:
pub trait Driver {
fn check_prereqs(&self) -> Result<()>;
fn start(&self, image_path: &Path) -> Result<VmStatus>;
fn stop(&self) -> Result<()>;
fn status(&self) -> Result<VmStatus>;
}
Where VmStatus reports running/stopped + the wizard URL (always
http://localhost:8088/wizard per the loopback-only design).
Linux driver
- Mandate: qemu+KVM. The driver checks
/dev/kvmis accessible andqemu-system-x86_64(orqemu-system-aarch64) is on PATH. - No bundled hypervisor. Linux distros all ship qemu+KVM; we don’t re-bundle.
- Boot command: roughly
qemu-system-<arch> -m 4G -accel kvm -drive file=<image>,if=virtio -netdev user,id=net0, hostfwd=tcp:127.0.0.1:8088-:8088 -device virtio-net,netdev=net0 -nographic -daemonize -pidfile <cache>/vm.pid. - Stop: SIGTERM to the pid in the pidfile.
- Status:
kill -0 <pid>pluscurl -fsS http://localhost:8088/healthz.
Windows driver
- Mandate: WSL2. The driver checks for the WSL2 distro that
deputyos-desktop installimports (or thatwsl/Install-DeputyOS.ps1imported earlier). - No bundled hypervisor. WSL2 is the right shape on Windows; we don’t run nested qemu in WSL.
- Boot command:
wsl --distribution deputyos --user agent /opt/deputyos/start.sh. - Stop:
wsl --terminate deputyos. - Status:
wsl --list --runningplus the healthz probe.
macOS driver
- Mandate: UTM. The driver checks for UTM at
/Applications/UTM.appand theutmctlCLI it ships. - No bundled hypervisor. Apple’s restrictions on third-party hypervisors plus UTM’s existing ecosystem make UTM the right shape.
- Apple Silicon (aarch64): HVF acceleration; near-native speed.
- Intel x86_64 macOS: TCG (slow) — supported but not recommended.
- Boot:
utmctl start deputyos. - Stop:
utmctl stop deputyos. - Status:
utmctl status deputyos.
Cross-compile per host triple
The make desktop-launcher target builds for the host triple by
default; pass DESKTOP_TARGET=<rust-triple> to cross-compile:
| Host | Target triple | Notes |
|---|---|---|
| Linux x86_64 | x86_64-unknown-linux-gnu | native |
| Linux arm64 | aarch64-unknown-linux-gnu | native |
| Windows | x86_64-pc-windows-msvc | from Windows host |
| Windows (cross) | x86_64-pc-windows-gnu | from Linux via cross |
| macOS Intel | x86_64-apple-darwin | must build on a Mac |
| macOS Apple Silicon | aarch64-apple-darwin | must build on a Mac |
macOS builds need Apple’s toolchain blobs we cannot legally redistribute. macOS contributors build on a Mac.
Manifest fetch + sha + minisig verify
The launcher reuses deputyctl::release types — the same code path the
on-device update verifier uses. Steps in download.rs:
- Fetch
manifest.jsonandmanifest.json.minisigfrom the deputyOS CDN URL (DEPUTYOS_DESKTOP_MANIFEST_URLenv override; or the baked default). - Verify the minisign signature against the pubkey baked into the binary at build time.
- Find the artefact for the host’s
(target, profile)— for Linux this isqemu-x86_64orqemu-aarch64, for Windows it’swsl2, for macOS it’smacos-qemu. - Download to the cache. Verify sha256. Verify per-artefact minisig.
- Cache hit → use cached image.
Cache locations
| Platform | Cache root |
|---|---|
| Linux | ${XDG_CACHE_HOME:-~/.cache}/deputyos-desktop/ |
| Windows | %LOCALAPPDATA%\deputyos-desktop\ |
| macOS | ~/Library/Caches/deputyos-desktop/ |
Cache contents:
images/<release>/<artefact>— downloaded and verified images.vm.pid(Linux) — running VM PID.state.json— current install state.
deputyos-desktop uninstall removes the cache. --data also wipes
the persistent data dir at:
| Platform | Data dir |
|---|---|
| Linux | ${XDG_DATA_HOME:-~/.local/share}/deputyos-desktop/ |
| Windows | %APPDATA%\deputyos-desktop\ |
| macOS | ~/Library/Application Support/deputyos-desktop/ |
Code-signing per platform
Distributing the binary needs platform-specific signing — without it, Gatekeeper / SmartScreen will block the launch.
| Platform | Signing requirement | Status |
|---|---|---|
| Linux | gpg-signed AppImage | not yet built |
| Windows | Authenticode EV cert | not yet built |
| macOS | Apple Developer ID + notarization | not yet built |
The CI signing infrastructure for these is not yet built. Today
the launcher binaries are unsigned — distribution is “build it
yourself with make desktop-launcher” pending the signing path.
Browser open
browser.rs is a thin shim over the platform default. Linux:
xdg-open. Windows: start (via cmd). macOS: open. The launcher
always opens http://localhost:8088/wizard; the wizard’s first-boot
state is persistent in the data dir, so successive start invocations
go straight to whatever step the user left off.
Update flow
deputyos-desktop update:
- Fetch the latest manifest.
- Compare to the cached manifest’s release_version.
- If newer: download + verify the new image. (This step is in the
not yet implemented; today’s
updateis check-only.) - On next
start, boot the new image.
The launcher does not yet support A/B for desktop the way the appliance images do (planned). Replacement is in-place; the previous image is removed only after the new one verifies.
Verification
# Build for host
cargo build --release -p deputyos-desktop
# Run install + start (interactive)
./target/release/deputyos-desktop install
./target/release/deputyos-desktop start
# Status / logs
./target/release/deputyos-desktop status