Repository navigation
Building from source
Needs macOS 14 or later and Xcode 16 or later (Swift 6). No other dependencies.
git clone https://github.com/roypadina/NtfyBar.git
cd NtfyBar
swift test # unit and integration tests, no network
Scripts/package_app.sh # builds dist/NtfyBar.app (universal)RELEASE=1 Scripts/package_app.sh also makes dist/NtfyBar.zip.
Copy dist/NtfyBar.app to /Applications and open it from there.
swift run starts the app without a bundle. macOS notifications do not work then, and the bundled plugins are not found. Unknown --flags are refused instead of starting the GUI.
Never run in CI.
NTFYBAR_LIVE_TEST=1 swift test --filter Live # real ntfy.sh, random throwaway topic
NTFYBAR_PLUGINS_REPO=../NtfyBar-Plugins swift test --filter MarketplaceRepoNTFYBAR_TEST=1 plus NTFYBAR_CONFIG_DIR=<empty dir> runs the app on a throwaway config and prints each effect (notify, popup, command, …) to stdout.
Rendered off screen with demo data:
dist/NtfyBar.app/Contents/MacOS/NtfyBar --render-popup popup.png
NTFYBAR_RENDER_TAB=topics dist/NtfyBar.app/Contents/MacOS/NtfyBar --render-settings settings.png
dist/NtfyBar.app/Contents/MacOS/NtfyBar --render-history history.pngSources/NtfyBarCore pure logic, Swift 6 strict concurrency, fully unit-tested
Config/ config.json / rules.json / state.json
Stream/ one /json stream per server: reconnect, backoff, since=, keepalive watchdog
History/ SQLite message store (dedupe, paging, search, retention)
Dispatch/ message → Effects (topic defaults, rules, catch-up, flood guard, pause)
Rules/ rule engine, built-in conditions/actions, templates
Commands/ Publish/ shell commands, publishing, quiet hours, ntfy http actions
Popup/ what a popup shows
Plugins/ manifest, JavaScriptCore runtime + permission bridge, loader, marketplace
Engine.swift wires it together
Sources/NtfyBarApp SwiftUI + AppKit: menu, popup panel, Settings, History, notifications
Resources/BundledPlugins plugins shipped in the app
Tests/NtfyBarCoreTests Swift Testing
The Dispatcher only decides: it returns Effects. EffectPerformer in the app carries them out. That keeps every decision testable without AppKit.
-
mainis protected. Changes land through pull requests with CI green. - Smallest diff that solves the problem. New behaviour comes with a test.
- Never commit real topic names, server addresses or credentials. Use fake ones like
ntfybar-9f3a1c7b2eandexample.com. - Changes to the plugin runtime need tests where every permission is: absent fails, granted works, revoked fails.
See CONTRIBUTING.md.
NtfyBar · MIT © Roy Padina · Support on Ko-fi ☕