A native macOS menu bar app for monitoring Apache Airflow DAGs.
- Menu bar status icon with dynamic badge showing failed/running DAG counts
- Real-time DAG monitoring via Airflow REST API (v1 and v2 auto-detection)
- Multi-environment support — monitor multiple Airflow instances, enable/disable each independently
- Authentication — Basic Auth and Bearer Token
- Configurable polling — intervals from 10 seconds to 30 minutes with exponential backoff
- Search & filter — by DAG ID, tag, owner, or state; regex-based DAG filtering
- Show/hide paused DAGs for a cleaner view
- macOS notifications for DAG failures and recoveries
- Health monitoring — track Airflow instance availability at a glance
- Automatic update checks — notifies you when a new version is available
- Zero dependencies — pure Swift using Foundation, CryptoKit, AppKit, and SwiftUI
brew tap maroil/airflow-bar
brew install --cask airflow-barDownload the latest DMG from the Releases page.
Note: The app is currently unsigned and not notarized. On first launch, right-click the app and select Open to bypass Gatekeeper.
Requires macOS 14+ and Swift 6.0+.
git clone https://github.com/maroil/airflow-bar.git
cd airflow-bar/macos
make release
make appThe .app bundle will be at AirflowBar.app. To create a DMG installer:
make dmg VERSION=0.1.0AirflowBar lives in your menu bar. On first launch, the settings window opens automatically.
| Setting | Description |
|---|---|
| URL | Base URL of your Airflow webserver (e.g. http://localhost:8080) |
| Auth | Basic Auth (username/password) or Bearer Token |
| Refresh interval | Polling frequency: 10s, 30s, 1m, 2m, 5m, 15m, or 30m |
| DAG filter | Regex pattern to include/exclude specific DAGs |
| Show paused | Toggle visibility of paused DAGs |
| Notifications | Alerts for DAG failures and recoveries |
| Update checks | Automatic daily check for new releases |
Configuration is stored at ~/.airflowbar/config.json. Credentials are encrypted with AES-GCM (via CryptoKit) and stored separately at ~/.airflowbar/credentials.enc. The encryption key is kept in ~/.airflowbar/.credentials.key with 600 file permissions.
Install the repo-managed Git hooks once after cloning:
./scripts/install-git-hooks.shThe hooks enforce conventional commit prefixes such as feat:, fix:, and chore:. They also run the same checks gated by CI before each commit:
cd macos && swift buildcd macos && swift testcd website && npm run build
- macOS 14+ (Sonoma)
- Swift 6.0+ / Xcode 16+
cd macos
make build # swift build
make test # swift test
make run # swift run AirflowBarFor website changes, install dependencies once and build locally with:
cd website
npm ci
npm run buildRun a single test suite:
cd macos
swift test --filter KeychainServiceTestsA Docker Compose file is included for local development:
cd macos
make airflow-up # starts Airflow at http://localhost:8080 (airflow/airflow)
make airflow-down # stops the stackGenerate screenshots for documentation without a live Airflow instance:
cd macos
make screenshotmacos/
├── Sources/
│ ├── AirflowBar/ # macOS app (SwiftUI + AppKit)
│ │ ├── Views/ # PopoverContent, SettingsView, FilterBar
│ │ ├── Resources/ # App icon
│ │ ├── ScreenshotMode.swift
│ │ └── UpdateCheckViewModel.swift
│ └── AirflowBarCore/ # Core library (no UI imports)
│ ├── Config/ # AppConfig, ConfigStore, KeychainService
│ ├── Models/ # DAGRun, HealthInfo, SemanticVersion, AppRelease
│ └── Networking/ # AirflowAPIClient, UpdateChecker
├── Tests/
│ └── AirflowBarCoreTests/ # Swift Testing (@Suite, @Test)
├── dmg-resources/ # DMG installer background
└── docker-compose.yaml # Local Airflow stack
website/ # Astro landing page
.github/workflows/ # CI and Release automation
The project uses a two-target Swift Package Manager structure:
- AirflowBarCore — Pure Swift library with no UI imports. Contains models, networking, and configuration logic. All testable code lives here.
- AirflowBar — SwiftUI views and AppKit integration. Depends on AirflowBarCore.
Key architectural decisions:
- Actors for thread safety (
AirflowAPIClient) async/awaitthroughout — no completion handlersTaskGroupfor concurrent multi-environment fetching@MainActorfor all UI state- File-based AES-GCM encryption instead of macOS Keychain (avoids permission prompts in unsigned builds)
