Agent CLI macOS app
July 25, 2026 · View on GitHub
This directory contains a native SwiftUI menu bar wrapper for agent-cli.
The app does not reimplement any agent behavior. By default, it bundles uv,
installs a private agent-cli[audio,llm] tool into the user's Application
Support directory on first use, and shells out to that private executable.
Users who already manage their own agent-cli install can enable
Use User-Installed agent-cli in Settings to run the agent-cli found on
PATH with their normal config instead.
Transcription is the default zero-config path. The first transcription action
installs and starts the local Whisper launchd daemon with
agent-cli daemon install whisper -y; the model is downloaded lazily by the
server on first transcription request. No existing agent-cli config file is
required.
The packaged app registers native macOS global hotkeys itself:
Fn+Spacetoggles transcriptionFnrecords while held and inserts the transcriptCmd+Shift+Aautocorrects clipboard textCmd+Shift+Vstarts voice edit
Choose Settings... from the menu bar app to change these shortcuts, enable
Start at Login, or switch between the bundled runtime and a user-installed
agent-cli. The settings UI uses the KeyboardShortcuts Swift package for
shortcut parsing and UserDefaults storage. Transcription shortcuts are handled
by a small CGEvent tap so Fn, Fn+Space, and plain Space remain distinct; the
clipboard utility shortcuts still use KeyboardShortcuts global handlers. The
login option uses Apple's login item API for the main app bundle, so macOS may
require approval in System Settings → General → Login Items.
The app uses Sparkle for direct app updates. Release builds stamp
SUPublicEDKey into Info.plist, publish signed updates in macos/appcast.xml,
upload AgentCLI.zip for Sparkle, and expose Check for Updates... from the
menu bar and Settings. Local builds without a Sparkle public key still run, but
update checks are disabled.
Build
From the repository root:
./macos/build-macos-app.sh
The app bundle is written to dist/macos/AgentCLI.app.
Install locally
./macos/build-macos-app.sh --install
This builds the app, copies it to /Applications/AgentCLI.app, and opens it.
Build a DMG
./macos/build-macos-app.sh --dmg
The DMG is written to dist/macos/AgentCLI.dmg.
End-to-end packaging check
./macos/test-macos-app-e2e.sh
The E2E test builds the app and DMG, verifies code signing and the image, then
uses a fake bundled uv to prove the app bootstraps its private CLI, installs
the Whisper daemon, and runs the default transcription command without network
downloads.
Signing
By default the script ad-hoc signs the local app bundle. For public distribution, pass a Developer ID identity and then notarize the resulting app or DMG:
CODESIGN_IDENTITY="Developer ID Application: Your Name (TEAMID)" ./macos/build-macos-app.sh --dmg
To notarize during the build, set NOTARIZE=1 and provide Apple notary
credentials:
CODESIGN_IDENTITY="Developer ID Application: Your Name (TEAMID)" \
NOTARIZE=1 \
APPLE_ID="you@example.com" \
APPLE_APP_SPECIFIC_PASSWORD="xxxx-xxxx-xxxx-xxxx" \
APPLE_TEAM_ID="TEAMID" \
SPARKLE_PUBLIC_ED_KEY="public-ed25519-key" \
./macos/build-macos-app.sh --dmg
Release CI
Publishing a GitHub release runs .github/workflows/release.yml, which imports
the Developer ID certificate with apple-actions/import-codesign-certs, builds,
notarizes, staples, and uploads dist/macos/AgentCLI.dmg to the release. The
workflow expects these repository secrets:
MACOS_CODESIGN_CERTIFICATE_BASE64: base64-encoded Developer ID Application.p12certificate exportMACOS_CODESIGN_CERTIFICATE_PASSWORD: password for that.p12MACOS_KEYCHAIN_PASSWORD: temporary CI keychain passwordAPPLE_ID: Apple ID email for notarizationAPPLE_APP_SPECIFIC_PASSWORD: app-specific password fornotarytoolAPPLE_TEAM_ID: Apple Developer Team IDSPARKLE_PRIVATE_ED_KEY: private Sparkle EdDSA key for signing updates
The Homebrew cask is not published from here. basnijholt/homebrew-tap runs a
daily cron that reads the latest release and bumps Casks/agent-cli.rb itself;
run it on demand with
gh workflow run update-agent-cli-cask.yml --repo basnijholt/homebrew-tap.
The workflow also expects the repository variable SPARKLE_PUBLIC_ED_KEY.
Generate the key pair with Sparkle's generate_keys tool and store only the
private key as a GitHub secret.