Skip to content

Building from source

Roy Padina edited this page Oct 23, 2026 · 1 revision

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.

Optional live tests

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 MarketplaceRepo

Test without touching your setup

NTFYBAR_TEST=1 plus NTFYBAR_CONFIG_DIR=<empty dir> runs the app on a throwaway config and prints each effect (notify, popup, command, …) to stdout.

Screenshots

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.png

Architecture

Sources/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.

Contributing

  • main is 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-9f3a1c7b2e and example.com.
  • Changes to the plugin runtime need tests where every permission is: absent fails, granted works, revoked fails.

See CONTRIBUTING.md.

Clone this wiki locally