Opensource alternative to wisprflow and superwhisper
Flexible Recording Activation Choose how you trigger recordings in Settings. Use Click to Start / Click to Stop (toggle mode) for hands-free dictation, or Press and Hold to record only while the hotkey is held down — the transcription is sent the moment you release.
Escape to Cancel Changed your mind mid-sentence? Press Escape at any point during an active recording to immediately discard the audio. Nothing is transcribed and nothing is pasted — it's as if you never started.
Automatic Fallback Provider Configure a secondary provider in Settings under Providers. If your primary provider returns an error, times out, or gets rate-limited, OpenWispher automatically retries your request through the fallback provider — no interruption to your workflow.
50+ Models Across ElevenLabs & Deepgram When using ElevenLabs or Deepgram, you can now browse and select from the full catalog of models each provider offers — including Nova-2, Nova-3, Flux (Deepgram) and Scribe v1/v2 (ElevenLabs) — along with fine-grained language selection.
Bulk Export
Added an Export button to both the transcription history view and Settings > History. Export all your transcriptions at once to a plain .txt file.
- Press your global hotkey (default
⌥ Space) - Speak
- Release / press again / the app transcribes via your chosen AI provider
- The text is automatically copied to your clipboard and pasted into whatever app is in focus
A floating notch overlay shows you the current state: Listening → Processing → Copied!
| Requirement | Minimum |
|---|---|
| macOS | 14 Sonoma |
| Xcode | 15+ |
| Swift | 5.9+ |
| API Key | At least one of: Groq, ElevenLabs, or Deepgram |
| Provider | Models | Languages |
|---|---|---|
| Groq | whisper-large-v3 |
English |
| ElevenLabs | scribe_v1, scribe_v2 |
Auto-detect + 90+ languages |
| Deepgram | nova-3 (default), nova-2, flux |
Auto-detect + 40+ locale variants (flux is English-only) |
API keys are stored securely in the macOS Keychain. During development, you can also set them via environment variables (GROQ_API_KEY, DEEPGRAM_API_KEY, ELEVENLABS_API_KEY).
- Global hotkey — fully customizable, default
⌥ Space - Two activation modes — toggle (click to start, click to stop) or hold-to-record
- Escape to cancel — discard a recording at any point without transcribing
- Notch overlay — animated status pill anchored to the MacBook notch
- Auto-paste — pastes transcribed text into the active app via Accessibility API
- Transcription history — persistent local storage with 30-day auto-cleanup; favorites are never deleted
- Bulk export — export all history to a
.txtfile - Fallback provider — automatic failover to a secondary provider on error or timeout
- 50+ model choices — full model + language selection for ElevenLabs and Deepgram
- Auto-updater — checks GitHub Releases for new versions and verifies DMG integrity via SHA-256
- Launch at Login — optional background agent mode
- Privacy-first analytics — PostHog with
personProfiles = .never; no PII collected
dhavnii/
├── .github/
│ └── workflows/
│ ├── ci.yml # Build check on every PR / push to main
│ └── release.yml # DMG + latest.json published on version tags
├── Scripts/
│ ├── build_release.sh # Local release build
│ ├── reset_permissions.sh # Clears UserDefaults + resets mic/accessibility
│ └── generate_icons.sh # Regenerates app icon set
├── dhavnii.xcodeproj/ # Xcode project (scheme: openwispher)
├── dhavnii/ # Main app source
│ ├── App/
│ │ └── AppState.swift # Global app state observable
│ ├── Core/
│ │ ├── Feedback/ # User-facing feedback system
│ │ ├── Security/ # Keychain wrapper (SecureStorage)
│ │ └── UI/ # Shared UI constants, animations, window helpers
│ └── Features/
│ ├── Clipboard/ # Auto-paste via CGEvent + NSPasteboard
│ ├── History/ # SwiftData models, retention, export
│ ├── Home/ # Main window (HomeView + ViewModel)
│ ├── Hotkeys/ # Carbon global hotkey registration + Escape monitor
│ ├── Notch/ # Floating notch overlay window + animated view
│ ├── Onboarding/ # 5-step first-run flow
│ ├── Permissions/ # Microphone + Accessibility permission management
│ ├── Settings/ # Full settings UI (5 sections)
│ └── Transcription/ # Audio recording, provider clients, fallback orchestrator
└── openwispher/
├── openwispherApp.swift # @main entry point, hotkey wiring, lifecycle
└── AnalyticsManager.swift # PostHog analytics
- Pattern: Feature-based folder structure with MVVM inside each feature
- State:
@Observable(Swift 5.9 macro) throughout;@MainActorfor all UI-touching code - Persistence: SwiftData (
TranscriptionRecord,HistoryPreferencesmodels) - API clients: Swift actors (
GroqAPIClient,ElevenLabsAPIClient,DeepgramAPIClient) — one per provider, isolated for thread safety - Audio: AVFoundation recording to a temp
.m4a(AAC, 16 kHz mono) deleted after transcription - Hotkeys: macOS Carbon Event Manager (
RegisterEventHotKey) for the global hotkey;NSEventlocal monitor for Escape - Keychain: All API keys stored under
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
git clone https://github.com/maker-or/openwispher.git
cd openwispheropen dhavnii.xcodeprojSelect the openwispher scheme and your Mac as the destination.
You can supply keys via environment variables so you don't have to go through onboarding on every run. In Xcode, edit the scheme (Product → Scheme → Edit Scheme → Run → Arguments) and add:
GROQ_API_KEY=<your key>
DEEPGRAM_API_KEY=<your key>
ELEVENLABS_API_KEY=<your key>
Or just run the app and complete onboarding normally.
Analytics is a no-op if no PostHog key is present. For CI/release builds, set the following secrets in your GitHub repository:
POSTHOG_API_KEYPOSTHOG_HOST
Press ⌘R in Xcode. The app will walk you through onboarding on first launch.
| Script | Purpose |
|---|---|
Scripts/build_release.sh |
Build a release DMG locally |
Scripts/reset_permissions.sh |
Reset all UserDefaults and revoke mic/accessibility permissions — useful when testing onboarding |
Scripts/generate_icons.sh |
Regenerate the app icon set from a source image |
See Scripts/README.md for full usage details.
Contributions are welcome. Here's how to get set up and what to keep in mind.
- Fork the repository and create a branch from
main:git checkout -b feature/your-feature-name
- Make sure the project builds cleanly before making changes (
⌘Bin Xcode). - Run
Scripts/reset_permissions.shif you need to test the onboarding flow from scratch.
- Swift: Follow standard Swift API Design Guidelines. Use
@Observableand structured concurrency (async/await, actors) — no completion handlers or Combine for new code. - SwiftUI: Prefer small, composable views. Avoid putting business logic in views — extract to a
@Observableview model or a service. - Actors: API clients (
GroqAPIClient, etc.) are Swift actors. Keep all network calls inside them. @MainActor: All code that touches SwiftUI state or AppKit must be@MainActor.- Keychain: Store all secrets via
SecureStorage— never inUserDefaultsorInfo.plist. - Analytics: Add a
AnalyticsManager.shared.track*()method for any new user-facing action. Always callcaptureAndFlushso events send immediately.
- Add a case to
TranscriptionProviderTypeinTranscriptionProvider.swift. - Create
<Provider>APIClient.swiftinFeatures/Transcription/as a Swift actor conforming toTranscriptionProvider. - Register the provider in
TranscriptionService.swiftinsidemakeClient(for:). - Add model and language enums / arrays as needed.
- Add API key fields to
SecureStorageand wire them intoSettingsViewandOnboardingView.
- Ensure the project builds without warnings on the
openwispherscheme. - Test manually:
- Onboarding flow (use
reset_permissions.shto start fresh) - Recording in both toggle and hold modes
- Escape-to-cancel
- Fallback provider triggering (you can force this by entering a bad API key as primary)
- History export
- Onboarding flow (use
- Open a PR against
mainwith a clear description of what changed and why. - The CI workflow will run an unsigned build automatically — fix any build failures before requesting review.
Please include:
- macOS version
- Which provider you are using
- Steps to reproduce
- Expected vs. actual behaviour
- Any relevant output from Console.app (filter by process name
openwispher)