Build & Contribute

Build it from source, the four gates CI enforces, and the one rule this codebase will not bend on.

Written for Wira Desk 0.3.0

Contributions are welcome by pull request. This is a Win32 FFI codebase, so the conventions below are about keeping it reviewable rather than about ceremony.

Build from source

Requires Rust (stable) and the MSVC toolchain on Windows.

.\build.ps1 -Mode prod

Output: target\release\wiradesk.exe and target\release\wiradesk-settings.exe.

Building from source is also the strongest verification available to a user today, because releases are not code-signed yet. That is why the full source is published rather than binaries alone.

Running the tests

The suite needs one environment variable. The daemon links an elevation manifest, which would otherwise apply to the test harness too and make it fail before any test ran:

$env:WIRADESK_SKIP_MANIFEST = '1'
cargo test --workspace

What to run before submitting

cargo fmt --all
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace

The four gates CI enforces

GateWhat it does
Buildfmt, clippy -D warnings, tests, and a release build, on Windows.
Secret scangitleaks over both history and the working tree, using .gitleaks.toml.
Dependenciescargo-deny check over advisories, licenses, bans and sources, with the graph pinned to x86_64-pc-windows-msvc.
LicensePart of the same cargo-deny run: a new dependency carrying a license outside the allow-list fails the build, deliberately.
Do not widen the gitleaks allowlist to make a finding go away. Triage it.

Unsafe code

This is a Win32 FFI codebase, so unsafe is unavoidable. Undocumented unsafe is not. undocumented_unsafe_blocks and missing_safety_doc are deny in the workspace lints, so every unsafe block needs a SAFETY: comment and the build fails without one.

Write the precondition the block actually relies on, not a description of the call. The useful ones usually name one of these:

  • a buffer capacity, against the size argument passed to Win32;
  • which component owns a handle, and where it is released exactly once;
  • which thread the call must run on;
  • why an invalid handle is tolerable, because the API reports failure rather than faulting.

The daemon runs elevated with a global keyboard hook. That is why this boundary, and not some other, is the one held to a standard.

Conventions worth knowing

  • CLAUDE.md, AGENTS.md, and .cursorrules hold the instructions AI coding tools read, and they are kept in sync. Change one and change all three in the same commit; drift between them is silent, and the tool reading the stale copy is the one that misbehaves.
  • CHANGELOG.md is not free-form. release.yml extracts the ## [x.y.z] section matching the git tag and publishes it as the release notes, and the in-app updater shows that same section to whoever is deciding whether to update. A tag with no matching section fails the release rather than shipping notes nobody wrote.
  • Who may move which version digit is a rule, not a convention. Work needing a minor or major bump belongs under Unreleased until the owner decides.

Reporting something

A bug or an idea

Open an issue on the repository. Useful: your Windows build, the Wira Desk version, what you did, what happened, and what you expected instead.

A vulnerability

Not an issue. Use GitHub Security Advisories so the report stays private until a fix exists. There is no bounty and no guaranteed response time.

Writing a changelog entry

Write it for the person deciding whether to update, not for the commit log. The in-app updater shows that text verbatim; it is the last thing someone reads before they let an elevated installer run.