A native macOS menu bar app that tracks your homemade persistent services with live health pings and a friendly JSON config. Click the menu bar icon, see each service's state at a glance, the port it listens on, and quick actions to restart, tail logs, or pop the endpoint open in a browser. When a service goes down, BCCST can POST to a Pushcut webhook so your phone buzzes.
🟢 BCCST
─────────────────────────────────────
Bois Club Custom Services
5/5 healthy
─────────────────────────────────────
🟢 📨 AOL Daemon :3312
🟢 💡 Light Controller :31337
🟢 🎮 Displayathon :49696
🟢 📚 Docmaster HTTP :31415
🔴 📖 Readthey Server :34206
─────────────────────────────────────
Last check: 09:08:42
Refresh now ⌘R
Reload config ⌘L
Edit config.json… ⌘,
Reveal config in Finder
─────────────────────────────────────
Quit BCCST ⌘Q
Each service expands to a submenu with PID, last exit code, ping ms, probe type,
endpoint URL, restart/stop/start (launchctl kickstart -k), reveal-working-dir,
and tail-log-in-Terminal.
Each push to main builds a fresh release via the self-hosted macOS runner.
- Grab the latest
BCCST.app.zipfrom Releases. - Unzip and drag
BCCST.appto/Applications. - First launch: right-click → Open (the app is ad-hoc signed, so Gatekeeper asks once; after that it launches normally from the menu bar).
- BCCST seeds
~/.config/bccst/config.jsonfrom its bundled example. Open it from the menu (Edit config.json…) and replace the placeholder service with your own — BCCST watches the file and reloads on save. - (Optional) Add
BCCST.appto System Settings → General → Login Items so it starts at sign-in.
Requires the Swift toolchain (Xcode or the standalone Swift package). macOS 13+.
git clone https://github.com/bryanthaboi/BCCST.git
cd BCCST
# Optional: seed your real config locally (gitignored) so your dev builds
# start with your settings instead of the example placeholder.
cp config.example.json config.json
$EDITOR config.json
./Scripts/build.sh # → dist/BCCST.app
./Scripts/build.sh run # build + launch
./Scripts/build.sh install # build + copy to /ApplicationsThe build produces dist/BCCST.app. It's an LSUIElement bundle (menu bar only,
no dock icon, no main window) and ad-hoc codesigned.
Edit ~/.config/bccst/config.json. BCCST watches this file and reloads on save.
On first launch the file is seeded from the bundled config.json.
{
"pollIntervalSeconds": 10,
"menuBarTitle": "BCCST",
"showOverallDot": true,
"services": [
{
"id": "my-service",
"name": "My Service",
"emoji": "🚀",
"launchdLabel": "com.example.myservice",
"host": "127.0.0.1",
"port": 8080,
"healthCheck": { "type": "auto", "timeoutSeconds": 3 },
"workingDirectory": "~/code/my-service",
"configFiles": ["~/code/my-service/config.yml"],
"logPaths": ["~/Library/Logs/myservice/out.log"],
"description": "Optional one-liner"
}
]
}| field | type | notes |
|---|---|---|
id |
string | unique key per service |
name |
string | display name in the menu |
emoji |
string | optional decoration |
launchdLabel |
string | launchctl list <label> checked for PID + last exit |
host |
string | default 127.0.0.1 |
port |
int | shown next to name; used for TCP probe and "Open http://…" |
healthCheck.type |
enum | auto (default), launchd, tcp, http, none |
healthCheck.url |
string | required when type=http |
healthCheck.expectStatus |
int | default: any 2xx |
healthCheck.timeoutSeconds |
number | default 3 |
workingDirectory |
string | "Reveal working dir" in submenu |
configFiles |
[string] | "Open " entries |
logPaths |
[string] | "Tail log " — opens Terminal with tail -F |
description |
string | one-liner inside submenu |
healthCheck.urlset → HTTP GETportset → TCP connect probelaunchdLabelset →launchctl listPID + exit status- Otherwise → no probe (unknown)
| dot | state | meaning |
|---|---|---|
| 🟢 | healthy | probe succeeded |
| 🟡 | running | launchd PID present, no deeper probe configured |
| 🟠 | degraded | launchd PID present but TCP/HTTP probe failed |
| 🔴 | down | launchd has no PID |
| ❌ | failed | launchd shows non-zero LastExitStatus |
| ⚪️ | unknown | no probe possible |
When a service transitions from healthy/running → down/failed, BCCST POSTs to a
Pushcut webhook so you get a notification on your phone. Configure in the
notifications block:
{
"notifications": {
"enabled": true,
"pushcutUrl": "https://api.pushcut.io/<token>/notifications/<name>",
"notifyOnRecovery": false,
"minSecondsBetween": 60,
"downTitle": "Service Down",
"recoveryTitle": "Service Recovered"
}
}Payload sent matches the curl example Pushcut provides:
{ "title": "Service Down", "text": "Docmaster HTTP is down at 09:42:11. (...err...) port :31415" }Behavior:
- First poll after launch never notifies — otherwise BCCST would page you for anything already down at startup.
- Only state transitions trigger — flapping
down → downdoes nothing. minSecondsBetweenthrottles per-service so a flapping service can't spam.notifyOnRecovery: trueadds the inverse alert when a service comes back.- The menu gains a "Send test Pushcut notification" item whenever
pushcutUrlis set — use it to verify wiring without waiting for a real outage.
Set BCCST_CONFIG to point elsewhere:
BCCST_CONFIG=~/.my-bccst.json open /Applications/BCCST.appBCCST/
├── Package.swift
├── README.md
├── config.json ← bundled seed (copied to ~/.config/bccst/ on first run)
├── Scripts/
│ └── build.sh
└── Sources/BCCST/
├── main.swift ← @MainActor bootstrap
├── AppDelegate.swift ← NSStatusItem, menu, polling, action handlers
├── Config.swift ← Codable model + locator
├── HealthChecker.swift ← actor; launchctl / TCP / HTTP probes
└── ServiceStatus.swift ← state enum + dots