{
  "markdown": "<div align=\"center\">\n\n# DeskHelm\n\nNative macOS menu-bar volume control for an external LG display.\n\n[![License](https://img.shields.io/badge/License-GPLv3%20only-blue.svg)](https://spdx.org/licenses/GPL-3.0-only.html)\n[![Docs](https://img.shields.io/docsrs/deskhelm)](https://docs.rs/deskhelm)\n[![Language Checks](https://github.com/acg-box/deskhelm/actions/workflows/language.yml/badge.svg?branch=main)](https://github.com/acg-box/deskhelm/actions/workflows/language.yml)\n[![Release](https://github.com/acg-box/deskhelm/actions/workflows/release.yml/badge.svg)](https://github.com/acg-box/deskhelm/actions/workflows/release.yml)\n[![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/acg-box/deskhelm)](https://github.com/acg-box/deskhelm/tags)\n[![GitHub last commit](https://img.shields.io/github/last-commit/acg-box/deskhelm?color=red&style=plastic)](https://github.com/acg-box/deskhelm)\n\n</div>\n\n## Feature Highlights\n\n### Native LG Display Volume Control\n\nDeskHelm has a Rust display core and a Swift native application layer. The Rust\ndisplay core owns display discovery and identity verification, DDC/CI transport,\nverified sessions, the CLI, and the C ABI. The Swift layer owns the macOS\nlifecycle, application state, Core Audio route qualification, media-key handling,\nand AppKit/SwiftUI presentation. The Swift app links the Rust core in process;\nneither product entrypoint invokes another display-control executable.\n\n## Status\n\nDeskHelm is an early Apple Silicon macOS prototype. The verified hardware point\nis an LG 39GX950B connected directly to an M4 Max Mac through USB-C. Display\nfirmware, cables, adapters, and docks can change DDC/CI compatibility.\n\n## Workspace Posture\n\n- `apps/deskhelm/` owns the Rust display core, CLI, and C ABI.\n- `apps/deskhelm/macos/` owns the Swift native application layer, including app\n  state, native services, and AppKit/SwiftUI presentation.\n- `script/` owns native build, release, and diagnostic commands, while\n  `scripts/` owns repository-maintenance TypeScript programs.\n- `packages/` is reserved for reusable shared packages.\n- The root `Cargo.toml` owns Rust workspace metadata, profiles, and dependency\n  versions.\n- The root `package.json`, `package-lock.json`, and `tsconfig.json` own the\n  TypeScript maintenance toolchain and its exact development dependencies.\n- `openwiki/` is the authoritative repository knowledge and agent-routing\n  surface.\n\n## Usage\n\n### Installation\n\n#### Build from Source\n\nThe native app requires an Apple Silicon Mac, macOS 14 or later, and Xcode with\nSwift 6.2. The display must expose DDC/CI audio volume as a 0–100 range.\n\n```sh\n# Clone the repository.\ngit clone https://github.com/acg-box/deskhelm\ncd deskhelm\n\n# Build the Rust CLI.\ncargo build --locked -p deskhelm\n\n# Build, stage, and open the native menu-bar app.\n./script/build_and_run.sh\n```\n\n#### Download DeskHelm for macOS\n\nStable [GitHub Releases](https://github.com/acg-box/deskhelm/releases/latest)\nprovide `deskhelm-aarch64-apple-darwin.zip`. The archive contains the signed and\nunnotarized `DeskHelm.app` for Apple Silicon. On first launch, macOS can block\nthe app because this open-source release uses a free Apple Development\ncertificate. Open **System Settings > Privacy & Security**, select **Open\nAnyway** for DeskHelm, then confirm **Open**. DeskHelm does not publish Windows\nor Linux archives because display control is not implemented on those platforms.\n\n### Configuration\n\n#### Keyboard Volume Keys\n\nKeyboard volume control starts automatically. If Accessibility access is\nmissing, open **Settings > Volume Keys** and select **Grant**. DeskHelm\nopens the correct macOS settings page and shows a floating guide with a\ndraggable app chip. It does not request the native macOS Accessibility prompt.\nThe guide closes when you close DeskHelm Settings. After you grant access,\nDeskHelm starts volume-key interception automatically.\n\nDeskHelm intercepts volume-up and volume-down only when the current output\nuniquely matches the supported LG display. macOS classifies this USB-C audio\nroute as a DisplayPort transport. Other outputs, including Bluetooth\nheadphones and Mac speakers, keep normal system volume-key behavior. Set\n`DESKHELM_CODE_SIGN_IDENTITY` to an authorized Apple Development identity when\nAccessibility authorization must persist across rebuilds.\n\nDeskHelm follows the macOS **Play feedback when volume is changed** preference.\nA tap plays the installed macOS volume cue through the current LG audio endpoint\nafter its final DDC/CI preview write is accepted. A held key does not stack a cue\nfor every system repeat: it plays once on release. At maximum volume, the cue\nstarts immediately and repeats about once per second until release. Holding\nShift alone reverses the feedback preference for that key sequence, as macOS\ndoes. A failed write or output-route change stays silent.\n\nDuring display reconfiguration or a temporary DDC/CI failure, DeskHelm stops\ninterception and cancels queued display work, so volume keys return to macOS. It\ndiscards the old display session. After the connection settles, it discovers the\ndisplay again, uses bounded fresh reads, and restores interception.\n\nOpen **Settings > General** to enable launch at login. The About pane shows the\ncurrent update configuration. A source build without the production Sparkle\npublic key opens GitHub Releases instead of claiming that an in-app update is\navailable.\n\n### Interaction\n\nSelect the image-only DeskHelm menu-bar icon to open its native menu. Select\n**Settings…**, or press Command-, while DeskHelm is active. Press Command-Q to\nquit. Settings uses four compact toolbar panes: Display, Volume Keys, General,\nand About. Settings and update windows keep DeskHelm in accessory mode, so they\ndo not add a Dock icon.\n\nUse the Display pane to drag the volume control, use the arrow keys, or use the\nVoiceOver adjustable action. DeskHelm coalesces rapid preview writes and\nconfirms the final target through hardware readback. When keyboard volume\ncontrol is enabled, a transient HUD shows accepted LG volume changes, including\nwhile Settings is open. The HUD does not take keyboard focus from Settings.\n\nAudible feedback starts after the display transport accepts the final preview\nwrite; the later readback remains the authoritative confirmed value. If the\ncompatible macOS sound resource is not available, volume control continues\nwithout a cue and DeskHelm records the condition in its log.\n\nUse the CLI to read or set the display volume:\n\n```sh\ncargo run --locked -p deskhelm -- volume\ncargo run --locked -p deskhelm -- volume 25\n```\n\nConfirm native menu construction, or also open and validate Settings:\n\n```sh\n./script/build_and_run.sh --verify\n./script/build_and_run.sh --verify-settings\n```\n\n### Update\n\nA distributed app uses `appcast.xml`; each enclosure carries the Sparkle\nsignature for its release archive. Open **Settings > About** and select\n**Check Now**, or choose an automatic update mode. A source build has no\nproduction update key and opens GitHub Releases instead.\n\nTo update a source build, pull `main` and rebuild:\n\n```sh\ngit pull --ff-only\n./script/build_and_run.sh\ncargo build --locked -p deskhelm\n```\n\n## Development\n\nInstall the exact TypeScript development graph without running package lifecycle\nscripts:\n\n```sh\nnpm ci --ignore-scripts\n```\n\nList tracked template markers:\n\n```sh\ncargo make list-template-markers\n```\n\nRun the complete Rust, Swift, TypeScript, and TOML validation gate:\n\n```sh\ncargo make check\n```\n\nRun the credential-free release contract checks separately when changing the\nrelease workflow:\n\n```sh\ncargo make test-release\n```\n\n### Release Maintainers\n\nThe release workflow starts only for an annotated `vX.Y.Z` tag. The tag version\nmust match the workspace version, and its commit must be reachable from the\ncanonical `main` branch. The workflow validates on Linux, builds and signs the\napp on `macos-26`, then returns to Linux to validate a GitHub draft before\nit publishes the draft. All tag releases share one non-canceling concurrency\ngroup. Before it changes a draft and again immediately before publication, the\npublisher checks the remote annotated tag, `main` ancestry, and every published\nstable version. A release must advance the complete stable history.\n\nThe Node 24 TypeScript publisher validates local artifacts before its first\nGitHub mutation. It repairs only a same-tag private draft by replacing all draft\nassets with the exact release triplet. After the final source and version checks,\nit downloads and validates the exact draft bytes again as the last operation\nbefore publication. It then fetches the public release and validates its\ndownloaded bytes. A retry of an already public same-tag release is read-only and\nvalidates the downloaded public bytes. The publisher also supports a\ncredential-free `--dry-run` that performs local validation only. There is no\nmanual preparation, `workflow_dispatch`, or dry-run workflow.\n\nThe checked-in `script/release/sparkle-public-ed-key.txt` contains DeskHelm's\npublic Sparkle key. Configure the matching private key as the repository secret\n`DESKHELM_SPARKLE_PRIVATE_ED_KEY`. The key verifier accepts the Sparkle 2.9.4\n32-byte seed and legacy 96-byte secret formats, and rejects a private secret\nwhose public key does not match the checked-in key. Make these organization\nsecrets available to the repository:\n\n- `APPLE_CERTIFICATE_P12_BASE64`\n- `APPLE_CERTIFICATE_PASSWORD`\n- `APPLE_SIGNING_IDENTITY`\n\nDeskHelm must use its own Sparkle key pair. Do not reuse another application's\nprivate or public key. The `release` environment protects only the final Linux\npublisher. The release scripts require an Apple Development identity label\nending in `RD3D4LH465` and require signed code to report TeamIdentifier\n`T54QFA7W2S`; a different identity suffix or code-signing team is rejected. The\nbuild uses Hardened Runtime without a signing timestamp and is not notarized.\nOnly the final publisher receives GitHub contents write permission. The\nworkflow does not publish the Rust crate.\n\n### Architecture\n\nDeskHelm is a workspace-first monorepo:\n\n- the Rust display core, CLI, and C ABI belong under `apps/deskhelm/`\n- the Swift native application layer belongs under `apps/deskhelm/macos/`\n- repository-maintenance programs belong under `scripts/`\n- repository-native checks are exposed through `Makefile.toml`\n- durable architecture, runbook, and routing notes belong under `openwiki/`\n\nThe Swift native application layer uses AppKit for the status menu, windows, and\nHUD panel, and it uses SwiftUI for Settings and HUD content. It also owns native\napp state and services. The Rust display core remains the sole owner of display\ndiscovery, verified DDC/CI sessions, and transport. The app links that core in\nprocess, and the CLI calls the same Rust API.\n\n## Support Me\n\nIf you find this project helpful and would like to support its development, you can buy me a coffee!\n\nYour support is greatly appreciated and motivates me to keep improving this project.\n\n- **Fiat**\n    - [Ko-fi](https://ko-fi.com/hack_ink)\n    - [Afdian](https://afdian.com/a/hack_ink)\n- **Crypto**\n    - **Bitcoin**\n        - `bc1pedlrf67ss52md29qqkzr2avma6ghyrt4jx9ecp9457qsl75x247sqcp43c`\n    - **Ethereum**\n        - `0x3e25247CfF03F99a7D83b28F207112234feE73a6`\n    - **Polkadot**\n        - `156HGo9setPcU2qhFMVWLkcmtCEGySLwNqa3DaEiYSWtte4Y`\n\nThank you for your support!\n\n## Appreciation\n\nWe would like to extend our heartfelt gratitude to the following projects and contributors:\n\n- The Rust community for their continuous support and development of the Rust ecosystem.\n\n## Additional Acknowledgements\n\n- TODO\n\n---\n\n<div align=\"right\">\n\n### License\n\n<sup>Licensed under [GPL-3.0-only](LICENSE).</sup>\n\n</div>\n",
  "bytes": 11753,
  "sha": "b4c2dd8fd661e07600a344b4e5c5ba1b1351d783cc0e72c62e84cfdd3c2b0f57",
  "repo_slug": "acg-box/deskhelm",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/okf_acg_box_deskhelm_openwiki_index_md_960b4efc/readme"
}