A native macOS menu bar application that monitors your GitHub pull requests and notifies you when builds complete.
Note: this is not production quality code. It's a developer tool, created to meet a very particular need. It's unrepentently vibe coded, and while I have used it for a week or so and found it pretty handy, I can't warrant whether it will work for your needs or, indeed, work at all.
Thanks to my team at Doximity for encouragement, support, and some tokens.
-
Live PR Monitoring: Displays all your open pull requests with real-time build status
-
Review Requests: Shows both PRs you authored and PRs awaiting your review (with a special indicator)
-
Auto-Refresh: Polls GitHub every 30 seconds (configurable 10-300s)
-
Watch PRs: Mark specific PRs to get notified when their builds finish
-
Inactive Branch Detection: Highlights PRs that haven't been updated in N days (configurable)
-
Smart Sorting: Optionally sort non-success PRs to the top of the list
-
Age Indicators: Shows how long ago each PR was last updated
-
Draft PR Support: Clearly identifies draft pull requests with a DRAFT badge
-
Native Notifications: macOS notifications with sound and voice announcements
-
Multi-Repository: Monitors PRs across all repositories you have access to
-
Build Status Icons:
- β Merge Conflict (purple)
- β Failure (red)
β οΈ Error (orange)- π Changes Requested (orange)
- β³ Inactive (orange)
- β Success (green)
- β Unknown (gray)
- π΅ Pending (animated spinner)
Here's what it looks like in action:
- macOS 13.0 (Ventura) or later
- Xcode 15.0 or later
- GitHub CLI (gh) installed and authenticated
brew install ghgh auth loginFollow the prompts to authenticate with your GitHub account.
- Open
MonitorLizard/MonitorLizard.xcodeprojin Xcode - Select your development team under Signing & Capabilities if needed
- Press βR to build and run
- The app will appear in your menu bar with a lizard icon π¦
- Grant notification permissions when prompted
Note: The app runs as a menu bar-only application (no Dock icon). Look for the lizard icon in your menu bar.
- Launch: Click the lizard icon in your menu bar
- View PRs: See all your open pull requests with their build statuses
- Refresh: Click the refresh button or wait for auto-refresh
- Open PR: Click any PR to open it in your browser
- Start Watching: Click the eye icon on any PR
- Get Notified: When the build completes, you'll receive:
- A macOS notification
- A sound effect (Glass.aiff for success, Basso for failure)
- Voice announcement: "Build ready for Q A" (for successful builds)
- Stop Watching: Click the eye icon again to unwatch
Click Settings to configure:
General:
- Refresh Interval: 10-300 seconds (default: 30s)
- Sort non-success PRs first: Show failing/pending/inactive PRs at the top
- Inactive Branch Detection: Enable detection and set threshold (1-90 days)
Notifications:
- Show Notifications: Enable/disable macOS notifications
- Play Sounds: Enable/disable sound effects
- Voice Announcements: Enable/disable and customize text-to-speech message
The app follows MVVM architecture with SwiftUI:
MonitorLizard/
βββ Constants.swift # Centralized constants
βββ Models/ # Data models
β βββ BuildStatus.swift
β βββ PullRequest.swift
βββ Services/ # Business logic
β βββ GitHubService.swift # gh CLI wrapper
β βββ ShellExecutor.swift # Process execution
β βββ NotificationService.swift # Notifications
β βββ WatchlistService.swift # Persistent storage
β βββ WindowManager.swift # Settings window
βββ ViewModels/ # State management
β βββ PRMonitorViewModel.swift
βββ Views/ # UI components
βββ MonitorLizardApp.swift
βββ MenuBarView.swift
βββ PRRowView.swift
βββ SettingsView.swift
- Polling: Timer fires every N seconds (configurable)
- Fetch PRs: Executes two queries:
- PRs you authored:
gh search prs --author=@me --state=open - PRs awaiting your review:
gh search prs --review-requested=@me --state=open - Both queries fetch:
number,title,repository,url,author,updatedAt,labels,isDraft
- PRs you authored:
- Fetch Status: For each PR, executes
gh pr view N --json headRefName,statusCheckRollup,mergeable,mergeStateStatus,reviewDecision - Parse Status: Determines overall status from individual checks
- Priority: conflict > failure > error > changes requested > pending > inactive > success > unknown
- Inactive Detection: If enabled, marks PRs as inactive when
updatedAtexceeds threshold
- Display: Shows PRs with status icons, age indicators, labels, and review indicator
- Check Completions: Compares with previous status for watched PRs
- Notify: Sends notifications for completed builds
# Fetch PRs you authored
gh search prs --author=@me --state=open --json number,title,repository,url,author,updatedAt,labels,isDraft --limit 100
# Fetch PRs awaiting your review
gh search prs --review-requested=@me --state=open --json number,title,repository,url,author,updatedAt,labels,isDraft --limit 100
# Fetch PR details with status and merge state
gh pr view 123 --repo owner/repo --json headRefName,statusCheckRollup,mergeable,mergeStateStatus,reviewDecision
# Check gh CLI authentication
gh auth statusInstall gh CLI:
brew install ghAuthenticate:
gh auth login- Ensure you have open PRs:
gh pr list --author=@me --state=open - Check gh CLI version:
gh --version(should be 2.0+) - Try manual refresh
- Check System Settings > Notifications > MonitorLizard
- Ensure notifications are enabled in Settings
- Grant notification permissions when prompted
- Ensure macOS deployment target is 13.0+
- Check that all Swift files are added to the target
- Verify Info.plist is configured correctly
- Clean build folder: Product > Clean Build Folder (β§βK)
swift testThe codebase is structured for easy extension:
- New PR filters: Modify
GitHubService.fetchAllOpenPRs() - Custom notifications: Extend
NotificationService - Additional UI: Add views to
Views/directory - New status types: Extend
BuildStatusenum and update priority logic inGitHubService.parseOverallStatus() - New settings: Add to
Constants.swift, create@AppStorageproperties inSettingsView, and wire through to services - Time-based features: Use
Constants.secondsPerDayfor date calculations
To distribute MonitorLizard outside of the App Store, you'll need to notarize it with Apple.
- Apple Developer account
- Valid Developer ID Application certificate
- App-specific password for notarization
- In Xcode, select Product > Archive
- Select your development team in Signing & Capabilities
- Wait for the archive to complete
- In the Organizer window, select the archive and click Distribute App
- Choose Developer ID distribution method
- Select Upload or Export based on your workflow
- Xcode will automatically code sign with Hardened Runtime enabled
- Export the .app bundle
Apple requires notarization for apps distributed outside the App Store on macOS 10.15+.
Using Xcode (Automatic):
- During export, choose Upload to automatically submit for notarization
- Xcode will handle the notarization process
- Once complete, download the notarized app
Using Command Line:
# Create a zip of the app
cd /path/to/exported/app
ditto -c -k --keepParent MonitorLizard.app MonitorLizard.zip
# Submit for notarization (requires app-specific password)
xcrun notarytool submit MonitorLizard.zip \
--apple-id "your-apple-id@example.com" \
--team-id "YOUR_TEAM_ID" \
--password "your-app-specific-password" \
--wait
# Check status
xcrun notarytool log <submission-id> \
--apple-id "your-apple-id@example.com" \
--team-id "YOUR_TEAM_ID" \
--password "your-app-specific-password"
# Staple the notarization ticket (optional but recommended)
xcrun stapler staple MonitorLizard.appCreating an App-Specific Password:
- Go to appleid.apple.com
- Sign in with your Apple ID
- In the Security section, select App-Specific Passwords
- Click + to generate a new password
- Use this password for notarization (not your Apple ID password)
The project is configured with Hardened Runtime enabled, which is required for notarization. The entitlements file (MonitorLizard.entitlements) includes:
- App Sandbox disabled (required for shell command execution)
- Get Task Allow enabled (for debugging)
If you need additional entitlements, edit MonitorLizard/MonitorLizard.entitlements.
- Valid Developer ID certificate installed
- Hardened Runtime enabled (already configured)
- App signed with Developer ID
- App notarized by Apple
- Notarization ticket stapled to app (optional)
- Test on a different Mac to verify Gatekeeper acceptance
Inspired by the original watch-ci-build bash script that watched CircleCI builds via GitHub API.
MIT License - feel free to modify and distribute.

