This document covers the local development workflow for OpenLogi. For end-user build instructions, see the README.
- Stable Rust (Edition 2024, MSRV 1.88)
- macOS: Xcode 16+ with the optional Metal Toolchain component (required by
GPUI's
gpui_macosbuild script to compile shaders) - Linux: system libraries β on Debian/Ubuntu:
sudo apt-get install libudev-dev gcc g++ clang libfontconfig-dev libwayland-dev libxkbcommon-x11-dev libx11-xcb-dev libssl-dev libzstd-dev pkg-config create-dmgfor packaging (brew install create-dmg);cargo-bundleis installed automatically bycargo run -p xtask -- macos bundle
CLI:
git clone https://github.com/AprilNEA/OpenLogi
cd OpenLogi
cargo run -p openlogi --release -- listDesktop app:
cargo run -p openlogi-gui --releaseOn macOS the desktop binary is launched from inside a throwaway
target/dev/OpenLogi.app β a Cargo runner wired in .cargo/config.toml
(scripts/cargo-run-macos.sh). This makes the dev build show the real
OpenLogi name in the menu bar and the app icon in the Dock; a bare
cargo run binary has no bundle, so macOS would otherwise fall back to the
openlogi-gui executable name and a generic icon. The binary is hardlinked in
(no copy) and the icon is generated on demand by
cargo run -p xtask -- macos icns. The runner is a transparent passthrough for
everything else (the CLI, tests); set
OPENLOGI_DEV_BUNDLE=0 to launch the raw openlogi-gui binary instead.
To install the CLI binary on PATH:
cargo install --path .The repo's devenv.nix provisions a Nix-based dev shell with sccache, the
stable Rust toolchain, and the env overrides GPUI needs. It exposes tasks that
mirror CI and packaging:
devenv tasks run openlogi:gui # run the desktop app
devenv tasks run openlogi:check # fmt + clippy + tests (run before committing)
devenv tasks run openlogi:dmg # build the macOS DMG
devenv tasks run openlogi:i18n-upload # upload English source strings to Crowdin
devenv tasks run openlogi:i18n-download # download translations and run i18n testsThe first time you cd into the repo after pulling a change to devenv.nix,
reload direnv so the new env vars (DEVELOPER_DIR, SDKROOT, the PATH
filter that strips Nix's xcbuild xcrun stub) take effect:
direnv reload # or: exit your shell and `cd` back inWithout that, GPUI's gpui_macos build script can't find Apple's metal
shader compiler, and link errors about missing _write / _sysconf /
_waitpid symbols show up because the Nix apple-sdk-14.4 stub doesn't
expose libSystem the way Apple's real linker wants.
src/ the `openlogi` binary (workspace root package) β a thin wrapper over openlogi-cli
crates/
openlogi-core/ types, config (TOML), paths, button + action catalog β no HID, no async
openlogi-hidpp/ vendored HID++ protocol crate (lib name `hidpp`)
openlogi-hid/ hidpp + async-hid: enumerate(), DPI (0x2201) and SmartShift (0x2111) writes
openlogi-assets/ device-render registry schema + cached HTTP fetch from assets.openlogi.org
openlogi-cli/ CLI implementation: command tree + `run()`, called by the `openlogi` binary
openlogi-agent-core/ headless orchestration shared by agent and GUI: hook runtime, HID++ writes, IPC
openlogi-agent/ the `openlogi-agent` binary β background agent owning device I/O and the hook
openlogi-hook/ OS mouse hook: macOS CGEventTap, Linux evdev/uinput, Windows WH_MOUSE_LL
openlogi-gui/ the `openlogi-gui` binary β GPUI + gpui-component
Before committing, the following must pass:
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspaceEquivalent to devenv tasks run openlogi:check.
cargo run -p xtask -- macos package # β target/release/OpenLogi.dmgEnvironment overrides:
OPENLOGI_BUNDLE_ASSETS=1β bundle every device render into the.appfor a fully offline build (default: fetched on demand at first launch).OPENLOGI_SIGN_IDENTITY=<identity>β codesign the.appand.dmgwith the given Developer ID.OPENLOGI_DMG_BACKGROUND_URL=<url>β override the branded DMG background TIFF URL (default:https://assets.openlogi.org/dmg/dmg-background.tiff).
The local packaging command and release workflow both use the same branded DMG
layout: a 760Γ480 background image in a 760Γ512 Finder window, with 128px icons
positioned at (212, 250) for OpenLogi.app and (548, 250) for
Applications.
Requires nfpm on PATH; the package arch is
derived from the host (override with PKG_ARCH):
cargo run -p xtask -- linux package # β target/release/openlogi_*.deb / .rpmThe package contents (binaries, udev rules, systemd user unit, desktop entry,
icon) are declared in packaging/linux/nfpm.yaml.
Tagged releases still attach DMGs and SHA256SUMS to GitHub Releases for manual
downloads and the Homebrew cask. The release workflow also publishes the same
DMGs to Cloudflare R2 and writes a static updater manifest at:
${OPENLOGI_UPDATE_BASE_URL}/channels/stable/latest.json
The app embeds that manifest URL at build time via
OPENLOGI_UPDATE_MANIFEST_URL, derived from OPENLOGI_UPDATE_BASE_URL in the
release workflow. Release builds also embed OPENLOGI_UPDATE_MINISIGN_PUBLIC_KEY
and run with Verification::Strict: an update is installed only if the manifest
asset carries a minisign signature that verifies against that key, plus a
matching SHA-256. A build without the key embedded (local/dev) fails closed β
the update check errors rather than installing an unverified artifact.
Configure the R2/update settings in one 1Password item referenced by the GitHub
secret OP_R2_SECRET_ITEM. The item must contain:
OPENLOGI_UPDATE_BASE_URLβ public HTTPS base URL, for examplehttps://updates.openlogi.org.OPENLOGI_UPDATE_MINISIGN_PUBLIC_KEYβ base64 minisign public key embedded in the app and used to verify updater artifacts.OPENLOGI_UPDATE_MINISIGN_SECRET_KEYβ the passwordless minisign secret key file, base64-encoded (base64 < minisign.key), used only in the release publish job to sign DMGs beforelatest.jsonis generated. It is stored base64 (not raw) so its two lines survive 1Password's paste handling; the workflow decodes it, mirroring the GitHub App key.CLOUDFLARE_R2_ACCOUNT_IDβ Cloudflare account ID used for the S3 endpoint.CLOUDFLARE_R2_BUCKETβ bucket name.CLOUDFLARE_R2_ACCESS_KEY_IDβ R2 S3 access key.CLOUDFLARE_R2_SECRET_ACCESS_KEYβ R2 S3 secret key.
The workflow uploads immutable artifacts under /releases/<tag>/ and only the
channel manifest under /channels/stable/latest.json is mutable.
The manifest is generated by the workspace xtask helper:
cargo run -p xtask -- release latest-json \
--dist dist \
--tag v0.2.0 \
--base-url https://updates.openlogi.org \
--output dist/latest.json