Building dictate.app¶
dictate is designed to be run from source. This guide is for power users who want their own .app bundle for personal use; signed-and-notarised public distribution is intentionally out of scope (see the FAQ).
Quick build (development, unsigned)¶
For local use without signing:
Alias mode is much faster and symlinks back to your source, useful while iterating.
For a real bundle that's portable to other machines, drop --alias.
The unsigned .app will show a Gatekeeper warning on first launch. Right-click → Open to bypass it. This is fine for personal use; if you want a signed bundle for your own machine, see the optional section below.
Optional: signing your own bundle¶
One-time setup¶
- Enroll in the Apple Developer Program ($99/year): https://developer.apple.com/programs/
- Download a "Developer ID Application" certificate from the developer portal and install it in Keychain Access.
- Generate an app-specific password at https://appleid.apple.com and store it:
Per-release build¶
# 1. Build
./scripts/build_app.sh --clean
# 2. Sign
export DEVELOPER_ID="Developer ID Application: Your Name (TEAMID)"
./scripts/sign_app.sh
# 3. Notarize + staple
./scripts/notarize_app.sh
# 4. Package for distribution
# Wrap into DMG using create-dmg:
# brew install create-dmg
# create-dmg --volname dictate --window-size 500 300 \
# --icon dictate.app 125 150 --app-drop-link 375 150 \
# dist/dictate-0.1.0.dmg dist/dictate.app
Verifying the bundle¶
# Signature
codesign --verify --deep --verbose=2 dist/dictate.app
# Notarization (after stapling)
xcrun stapler validate dist/dictate.app
# Gatekeeper acceptance
spctl -a -vvv -t install dist/dictate.app
Common gotchas¶
- py2app + faster-whisper / onnxruntime: these C-extension heavy deps sometimes fail to bundle. If you hit issues, try alias mode first to confirm the app boots, then experiment with the
includes/excludeslists in setup_app.py. - pyobjc framework discovery: py2app sometimes misses pyobjc framework subpackages. Add them explicitly to
includesif you see import errors at runtime. - Code signing fails on nested binaries: use
--deepfor the codesign call (already in sign_app.sh). - Notarization rejects: read the JSON log via
xcrun notarytool log <submission-id> --keychain-profile AC_PASSWORD: usually a missing entitlement. - App launches but hotkey doesn't work: the bundle needs Accessibility + Input Monitoring permissions. Grant via System Settings → Privacy & Security.
Roadmap¶
dictate stays self-hosted by design. There is no plan to ship a signed DMG, Homebrew cask, or App Store listing. This guide is the supported path.