Native macOS menu bar application for reading text and URLs aloud using Apple's native text-to-speech.
- Native macOS text-to-speech using AVSpeechSynthesizer
- Menu bar interface with SwiftUI
- URL content extraction with HTML parsing
- Customizable voice and playback speed
- Real-time playback progress with word highlighting
- Play, pause, resume, and stop controls
- macOS 14.0+
- Xcode 15.0+ (for development)
- Swift 5.9+
Note: This app is not code-signed (no Apple Developer ID). On first launch, macOS Gatekeeper will show a security warning. To bypass: right-click the app → Open. You only need to do this once.
- Download the latest release from the Releases page
- Drag
Speakeasy.appto your Applications folder - First launch: Right-click → Open (to bypass Gatekeeper)
- Launch normally from Applications or Spotlight
# Clone the repository
git clone https://github.com/minac/speakeasy-mac.git
cd speakeasy-mac
# Build and create app bundle
./create-app-bundle.sh release
# Install to Applications
cp -r build/release/Speakeasy.app /Applications/- Click the speaker icon in the menu bar
- Select "Read Text..."
- Enter text or paste a URL
- Click "Play" (becomes "Stop" during playback)
- Voice: Choose from available macOS system voices
- Speed: Adjust playback speed (0.5x - 2.0x)
For more natural-sounding free voices for macOS:
- Open System Settings > Accessibility > Spoken Content
- Click System Voice > Manage Voices...
- Download Enhanced or Premium versions
# Debug build (for development)
./create-app-bundle.sh debug
open build/debug/Speakeasy-build.appswift test --package-path SpeakeasyOr in Xcode: Cmd+U
Speakeasy/
├── Speakeasy/
│ ├── SpeakeasyApp.swift # App entry point
│ ├── Core/
│ │ ├── AppState.swift # Central state management
│ │ ├── SpeechEngine.swift # TTS engine wrapper
│ │ └── TextExtractor.swift # URL/HTML processing
│ ├── Models/
│ │ ├── SpeechSettings.swift # Settings model
│ │ ├── Voice.swift # Voice wrapper
│ │ └── PlaybackState.swift # Playback states
│ ├── Services/
│ │ ├── SettingsService.swift # UserDefaults persistence
│ │ └── VoiceDiscoveryService.swift # System voice enumeration
│ ├── Views/
│ │ ├── MenuBarView.swift # Menu bar interface
│ │ ├── InputWindow.swift # Text input window
│ │ ├── SettingsWindow.swift # Settings interface
│ │ └── Components/
│ │ ├── VoicePicker.swift
│ │ ├── SpeedSlider.swift
│ │ └── HighlightedTextView.swift
│ ├── ViewModels/
│ │ ├── InputViewModel.swift
│ │ └── SettingsViewModel.swift
│ └── Resources/
│ └── Info.plist
└── Tests/
├── CoreTests/
├── ServicesTests/
└── ViewModelTests/
- SwiftSoup - HTML parsing
The project uses Swift Package Manager with a custom build script to create proper macOS .app bundles.
Why the custom script?
Swift Package Manager executables don't generate proper .app bundles with Info.plist by default. The create-app-bundle.sh script:
- Builds the executable with
swift build - Creates proper
.appbundle structure - Copies
Info.plistwith bundle identifier - Sets correct permissions
Make sure you're running the app as a proper .app bundle (not via swift run), as terminal-launched apps capture keyboard input.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Write tests first (TDD)
- Implement feature
- Run tests (
swift test) - Commit your changes
- Push to the branch
- Open a Pull Request
MIT
- Built with Claude Code



