Path to a submittable .lplug4 for the Logitech Marketplace, per the Actions SDK approval guidelines.
-
LoupedeckPackage.yamlpresent insrc/package/metadata/with a plugin icon (Icon256x256.png). - License is MIT (GPL is not allowed). whisper.cpp and the Whisper model are both MIT.
- PRIVACY.md (on‑device, no data leaves the machine) and a draft EULA.md.
- Fill
LoupedeckPackage.yaml: uncomment and setsupportPageUrlandhomePageUrl(e.g. the GitHub repo / issues page); consider a fullerauthor. - Bundle whisper.cpp (see below) —
tools/voice/bundle-whisper.shvendors Homebrew'swhisper-cli+ its dylib closure into a self‑contained~/.claude/claude-console/whisper-bin/, Developer‑ID signed + hardened‑runtime + notarized viatools/voice/sign-and-notarize.sh, and shipped inside the.lplug4bytools/voice/pack-release.sh(installed to the runtime home on first use, quarantine stripped, byBridgeManager.EnsureVoiceRuntimeInstalled). - Fetch the model (~142 MB) — the plugin downloads
ggml-base.en.binon first use and verifies its sha256 (BridgeManager.EnsureVoiceModel/DownloadVoiceModel). No manual step, no package bloat. - Sign + notarize
ClaudeVoiceHelper.app— done viatools/voice/sign-and-notarize.sh(Developer ID + hardened runtime + mic entitlement; notarized & stapled;spctl→ accepted, source = Notarized Developer ID). - Do not bundle ffmpeg/sox (GPL/LGPL). The runtime uses AVFoundation; they're dev‑only. ✅
- Finalize EULA with counsel; confirm privacy policy is reachable via a valid URL.
- Test on the supported hardware (MX Creative Keypad) and on a clean Mac (no dev tools) to validate the bundled binaries and permission prompts.
- Accept the Logitech Marketplace Developer Agreement.
- Package as
ClaudeConsole_1_0.lplug4and submit at marketplace.logitech.com/contribute (≈10 working days for review).
tools/voice/bundle-whisper.sh already does the vendoring: it copies Homebrew's whisper-cli plus
its full dylib closure (libwhisper, libggml, libggml-base, libomp), rewrites every install
name / rpath to @rpath (resolved via @loader_path), signs, includes the whisper.cpp + ggml MIT
licenses, and verifies the result runs with Homebrew off the PATH. Output:
~/.claude/claude-console/whisper-bin/ (≈2.4 MB). BridgeManager.StartVoiceCapture passes that path
via --whisper, and the helper's findWhisper() prefers it. For dev builds it ad‑hoc signs; for a
release, sign-and-notarize.sh exports SIGN_IDENTITY so the same code path signs with Developer ID
- hardened runtime, then notarizes the bundle.
Shipped in the package: tools/voice/pack-release.sh copies the relocated, signed whisper-bin/
and the notarized helper into the packed tree under bin/voice/. On first voice use,
BridgeManager.EnsureVoiceRuntimeInstalled dittos them into the runtime home and strips
com.apple.quarantine — so a package‑only install has working voice. (Loose Mach‑O can't be
stapled; stripping quarantine after install covers the offline Gatekeeper case, and the binaries
are notarized so the online check passes regardless.)
The ~142 MB model is not bundled — it downloads on first use (see the checklist above), which keeps the package small and within any Marketplace size limit.
tools/voice/sign-and-notarize.sh does the whole release flow (helper and whisper bundle):
# one-time: store a notarytool credential (App Store Connect API key or app-specific password)
xcrun notarytool store-credentials "claude-console-notary" --key … --key-id … --issuer …
# then, per release:
bash tools/voice/sign-and-notarize.shIt signs with Developer ID Application + hardened runtime, submits both artifacts to
xcrun notarytool submit --wait, staples the helper (.app carries its ticket offline), and
verifies with codesign/spctl/stapler. Override SIGN_IDENTITY / NOTARY_PROFILE via env.
Entitlements (required under the hardened runtime):
- Helper —
tools/voice/helper.entitlements:com.apple.security.device.audio-input(mic). whisper-cli—tools/voice/whisper.entitlements:disable-library-validation+allow-unsigned-executable-memory(+allow-jit). whisper.cpp runs inference on the GPU via Metal; without these the hardened runtime aborts Metal init (ggml_abortinggml_backend_dev_init) and every transcription comes back empty. Applied to the executable only.
A stable Developer‑ID identity also keeps the Microphone TCC grant from resetting on every rebuild (ad‑hoc hashes rotate; the Developer‑ID hash is stable).
bash tools/voice/sign-and-notarize.sh # Developer-ID sign + notarize helper + whisper
bash tools/voice/pack-release.sh 1_1 # build, embed voice, pack ClaudeConsole_1_1.lplug4
logiplugintool install ./ClaudeConsole_1_1.lplug4 # local test before submittingpack-release.sh embeds the notarized voice payload (bin/voice/) so voice works from a
package-only install. Verify the .lplug4 installs and runs on a clean machine (no dev tools,
no Homebrew), then submit.