Build & package

The .app (Apple Silicon)

Single entrypoint — everything is bundled (Python + mitmproxy):

python3 build_app.py                       # dist/Wispr Proxyflow.app (arm64)
python3 build_app.py --arch universal2     # arm64 + Intel fat binary
python3 build_app.py --name "Wispr Proxyflow"    # custom name
python3 build_app.py --clean               # wipe previous outputs first

The result is dist/<name>.app:

Wispr Proxyflow.app/
└── Contents/
    ├── Info.plist            # LSUIElement, bundle id com.local.wispr-proxyflow
    ├── MacOS/
    │   ├── wispr-pro         # the onefile proxy binary
    │   └── wispr-pro-launcher# double-click entry (background start)
    └── Resources/
        └── AppIcon.icns

Double-clicking starts the proxy in the background; logs go to ~/.wispr_pro/proxy.log (override with WISPR_PRO_LOG).

Build deps: python3 -m pip install mitmproxy pyinstaller

The .dmg (CI)

The GitHub Action .github/workflows/build-app-dmg.yml builds, packages and publishes a DMG on every tag push:

git tag v1.0.0
git push origin v1.0.0
  1. Runs on macos-14 (arm64).
  2. Installs deps → runs pytest + wispr_pro.py selftest.
  3. python build_app.py → dist/Wispr Proxyflow.app.
  4. hdiutil create → dist/Wispr-Pro-<version>.dmg (UDZO).
  5. Uploads the DMG as a workflow artifact and attaches it to a GitHub Release (tagged builds only). Ad-hoc signed — first launch on another Mac may need right-click → Open or removing the quarantine attribute.

Local DMG (one-liner)

hdiutil create -volname "Wispr Proxyflow" \
  -srcfolder "dist/Wispr Proxyflow.app" \
  -ov -format UDZO "dist/Wispr-Pro-1.0.0.dmg"