A collection of useful SwiftBar/xbar plugins for macOS.
- Description: A combined monitor for Memory, CPU, and Network latency.
- Features:
- Memory: Displays free GB with color coding based on system pressure. The dropdown also names the top memory-consuming process (
Top Memory: Messages (507M)), click-to-kill like the CPU list;kernel_task,WindowServer, and Chrome are excluded as never-interesting/never-useful-to-kill. - CPU: Shows usage percentage, temperature (°F via
smctemp), and thermal throttling status (pmset+powermetricssignals on Apple Silicon); usage is colored when throttling. - Top Processes: Lists the top CPU consumers; automatically surfaces the top non-kernel process in the menu bar if CPU usage exceeds 50%. Click any process in the dropdown to kill it — a confirmation dialog appears, then SIGKILL (
-9) is sent, so even a process that traps or ignores SIGTERM dies immediately; the plugin then redraws right away instead of waiting out the tick. - Sustained CPU-hog warning: warns proactively when a process stays hot, with no banner or popup — the CPU field in the menu bar gains a ⚠, turns red, and names the culprit (
⚠41%(WeatherMenu)), and the dropdown promotes a one-click Kill row plus Ignore for 1 hour to the top. Two tiers, because "a lot of CPU" means different things for different apps: ≥100% sustained 3 minutes (a runaway pegging a core), or ≥50% sustained 5 minutes (a background/menu-bar app that should be idle). A single tick below the threshold resets the streak, so spikes, compiles, and page loads never warn. If a process was killed by hand within the last hour it is treated as a known repeat offender and warns after just 45s, annotated(killed 22m ago); a Recently killed section lists those.kernel_task,WindowServer,mds*,backupd, and SwiftBar/xbar itself are never flagged. Thresholds are theHOG_*tunables near the top of the script. This is the only stateful part of the plugin — streaks, kill history, and cooldowns live in$TMPDIR/xbar-metrics.$UID/. Streaks are keyed by PID and names resolved viaps, sincetoptruncates the command column (com.apple.weather.menu→com.apple.weathe). - SwiftBar spin watchdog: the host app is excluded from the hog check above (click-to-kill must never target the app drawing the menu), so it gets its own clock and its own remedy. Menu-bar apps can fall into a self-sustaining
_activeTrackingAreasNeedUpdate → NSCursor setrun-loop cycle and hold a full core indefinitely — SwiftBar, Apple's own weather extra, and WindowServer all at once. If SwiftBar stays ≥60% CPU for 5 minutes (and has been up 10 minutes, so a restart loop is impossible), the plugin auto-restarts it, at most once per hour, via a detached helper that outlives the quit; the dropdown then shows↻ SwiftBar auto-restarted 12m agofor the rest of the cooldown, and the restart log lives in$TMPDIR/xbar-metrics.$UID/host_restarts. One cool tick of grace absorbstop's sampling swings without losing a long streak. The real cause is a customized accessibility pointer: with custom fill/outline colors there is no cached cursor, so everyNSCursor setregenerates the bitmap through_AXFMouseCursorGeneratorand re-registers it with SkyLight, turning an invisible cycle into a full core. WhenevercursorIsCustomizedis set, the warning adds a row linking straight to the Pointer pane — resetting those colors is the actual fix; the restart only buys time. Tunables are theHOST_*group near the top of the script. - SwiftBar death ledger: the watchdog above catches a host that is too busy; this catches one that is simply gone. SwiftBar crashes do leave an
.ipsin~/Library/Logs/DiagnosticReports/, but macOS moves them intoRetired/within the hour and purges that soon after — so each death erases the evidence of the last one, and "it keeps dying" becomes unanswerable. Every tick this harvests any new report into a durable log before it vanishes, parsing the crash time, exception/signal, the human-readable reason fromasi(SIGTRAP: BUG IN CLIENT OF LIBMALLOC: memory corruption of free block), how long the host had been up, and the app version — from the first 50 lines only, so the ~180 lines of thread dumps are never read. Deaths that leave no report at all (a clean quit, a hang killed by hand, the spin watchdog, a logout) are caught separately by noticing a changed host PID between ticks, and are labelledwatchdogwhenhost_restartsexplains them; a crash already logged in the same window is never double-counted. A quit that happened because the session ended (logout or reboot, detected as aloginwindowyounger than the old host's last tick) is logged asrebootand listed dimmed, but is not counted as a death — three of the first five "exits" were just the Mac restarting. Once there is anything to answer for, the dropdown leads with✕ SwiftBar died 3× in 7d — last 41m agoover a submenu of the last 8, each with cause, uptime, and version; it is silent while the host behaves. Unlike every other stateful part of this plugin, the log lives outside$TMPDIR— in~/Library/Application Support/xbar-metrics/host_deaths, 90 days of it — because$TMPDIRis wiped at every reboot and a reboot is exactly when you most want the history. Necessarily retroactive: the recorder is itself a SwiftBar plugin, so a death is logged on the first tick after the host is back, not while it is down. - Ping: Monitors network latency (mean ± standard deviation) to 8.8.8.8 and 1.1.1.1.
- Compact UI: Uses ANSI colors for per-metric status in a single line.
- Memory: Displays free GB with color coding based on system pressure. The dropdown also names the top memory-consuming process (
- Description: Detects active Chrome Remote Desktop sessions and optimizes system state.
- Dependencies: Passwordless sudo for
pmset(see Installation). - Features:
- Automatically dims the screen to 0 brightness when a remote session is established.
- Prevents lock screen by simulating mouse movement every 5s via a compiled Swift helper (
.crd-jiggle), resetting the HID idle timer. - Leaves hot corners alone; if the cursor is parked in a screen corner, the jiggler nudges it inward so it never re-triggers a hot corner.
- Prevents system and display sleep via
pmsetas a safety net (AC power only). - Leave On mode: an optional persistent toggle that keeps the system and display awake even when no session is detected. Survives reboots/sleep-wake (flag stored in the plugin dir, not
/tmp), keeps the local screen visible when idle (only dims while a session is actually active), and shows a filled-pin menu-bar icon. - Battery/lid safeguards: never keeps the machine awake on battery — unplugging (AC→battery) or running on battery tears down Leave On and session keep-awake, and a closed lid on battery with no session forces a full teardown so it can sleep in a bag. A closed lid on AC (clamshell with external display) is respected, so a manual "Enable CRD Mode" still sticks.
- Foreign sleep-blocker detection: shows 😴 in the menu bar plus a
Sleep blocked by: <process>status line when another process holds aPreventSystemSleep/InternalPreventSleepassertion. Those defeat lid-close (clamshell) sleep regardless of this plugin'spmsetstate, so the machine can stay awake in a bag even with CRD mode fully off — this makes the culprit visible at a glance instead of looking like a plugin bug. Where the holder names a beneficiary in its assertion details, that is reported too (caffeinate→osxphotos):caffeinateis a generic wrapper that tools invoke around themselves, so the bare name says nothing about what to stop or wait for — and because it runs as a child of the real job, it is not where you would look for it in Activity Monitor either. - Logs lock state (
locked=0/1) on every tick and alerts on lock-during-active failures. - Restores original brightness and sleep settings when the session ends.
- Description: Switches between display layout presets from the menu bar.
- Dependencies: displayplacer
- Features:
- Preset layouts: External 2560×1440 clamshell, iPad Sidecar extended, Built-in only.
- Dynamically detects built-in and external display IDs at runtime.
- Automatically triggers iPad Sidecar connection via a Shortcuts shortcut if the iPad isn't already connected.
- Menu bar icon reflects the current display mode (🖥️ / 📱 / 💻).
- Description: Quickly toggle between different mouse tracking speed profiles.
- Features:
- Profiles: Supports "Home" (1.0) and "On-the-Go" (3.0/Fastest) speed settings.
- Instant Apply: Uses a combination of
defaultswrites and a System Settings refresh to ensure hardware speed updates immediately. - Refresh interval: 5 minutes, not seconds. The speed only ever changes through this plugin's own click action, and that action already carries
refresh=true, so polling faster just makes SwiftBar rebuild a status item that cannot have changed. - Minimal UI: Icon-only menu bar title — a
tortoise.fillSF Symbol for Home,hare.fillfor On-the-Go, bothtemplate=trueso they invert with the menu bar in light/dark. The fullM:/T:speeds are in the dropdown. If a symbol ever fails to resolve the item renders empty; swap thesfimagelines back to plain 🐢/🐇 emoji in that case.
- Description: Toggle macOS Background Sounds from the menu bar.
- Features:
- Detects whether the
hearddaemon is playing by inspecting its open.m4afiles. - Shows the current sound name when active.
- On/off actions invoke the "Background sounds On" / "Background sounds Off" Shortcuts.
- Self-guarding:
lsofwalks the whole open-file table and blocks for as long as an unreachable SMB mount takes to time out. Since SwiftBar re-fires a plugin every interval whether or not the last run returned, a stalled probe used to queue a dozen invocations that then completed in the same millisecond — enough concurrent teardown on oneNSOperationQueueto corrupt SwiftBar's heap and crash the host. A single-instance lock now prevents any backlog, a 3s watchdog boundslsofitself, and a timed-out probe replays the last answer rather than falsely reporting "Off".
- Detects whether the
- Description: Shows the current macOS Desktop Space number in the menu bar, with a per-space summary of what's running in the dropdown.
- Features:
- Uses private CoreGraphics APIs (
CGSCopyManagedDisplaySpaces,CGSGetActiveSpace,CGSCopySpacesForWindows) via inline Swift to identify the active space and map each window to its space. - Per-space summary: lists the key app(s) on each space, and for Chrome shows the active tab's page title (the "topic") — e.g.
Desktop 4 — Chrome: Travel planning. - Filters out minimized/hidden windows and transient popovers/panels by requiring a real window title, so the summary matches what you actually see on each space.
- Fully native (one window-list pass plus a per-window space lookup, a few ms) — no AppleScript, polling, or caching.
- Chrome topics require Screen Recording permission for xbar (to read window titles); without it the summary degrades gracefully to app names only and shows an inline hint.
- Compiles the inline Swift to a cached binary, recompiling only when the script changes (~20ms/tick vs ~750ms to JIT each tick).
- Self-guarding: a single-instance lock plus a watchdog keep a stalled WindowServer call (during sleep/wake, lock, or fast user switching) from piling 1s ticks into stuck processes — new ticks skip while a run is active, and a wedged run is bounded and killed.
- Refreshes every second for near-live tracking as you switch spaces.
- Uses private CoreGraphics APIs (
- Description: Shows which TP-Link Deco mesh node this Mac is on as an icon only —
cable.connectorfor Main (the wired gateway),arrow.upfor Upstairs,arrow.downfor Downstairs,wifi.exclamationmarkif unknown, a redexclamationmark.triangle.fillin place of the node icon whenever any Deco reports offline or Tailscale is on at home (a utun with a 100.64.0.0/10 address; named at the top of the dropdown),globewhen away from home — tinted red when on 2.4 GHz or on any other issue (weak signal < −70 dBm, jittery or unreachable gateway, unknown node, failed Deco query), default otherwise (5/6 GHz and healthy). - Dependencies:
uvfrom Homebrew or the standalone installer (~/.local/bin); it resolvestplinkrouterc6u+pyobjc-framework-CoreWLANfrom the helper's inline metadata on first run. Deco admin password in the login keychain of each Mac:security add-generic-password -s deco -a admin -w. - Hardcoded for one home network — edit these at the top of
.deco.py(anddeco.30s.sh) on any other network:HOST = "http://10.0.0.1": the Deco controller (main node), also the gateway ping target and theen0router that marks "at home" (asked ofen0, not the default route, so a VPN such as a Tailscale exit node doesn't look like being away).NODE_ICONS: maps Deco nicknames (as named in the Deco app:Main,Upstairs,Downstairs) to SF Symbols. Unlisted names fall back towifi.exclamationmark.- Keychain item: service
deco, accountadmin. en0: the Wi-Fi interface power-cycled by Re-join Wi-Fi indeco.30s.sh.
- Features:
- macOS hides the BSSID from processes without Location Services, so the node comes from the Deco controller. Its global client list reports every client's
access_hostas1, so the helper asks each node for its own clients, last-known node first. - Deco logins are slow and single-session (they also bump Home Assistant's
tplink_routerpoller), so the answer is cached and re-asked only on a probable roam (band/channel change or ≥12 dB RSSI jump), every 5 min (1 min if no node listed this Mac — a freshly roamed client can take a moment to appear on its new node), or on Refresh now. Band, channel, width, RSSI/SNR, and Tx rate come from CoreWLAN every tick for free. - Dropdown lists every Deco with model, IP, backhaul level (the better of its 5 and 6 GHz links on tri-band nodes like the XE75), and client count, plus a 5-ping gateway latency ± stddev to separate Wi-Fi jitter from WAN jitter.
- Re-join Wi-Fi (radio off/on) makes macOS re-pick the strongest node.
- 2.4 GHz is flagged red, even when a Mac is pinned to 2.4 in the Deco app on purpose (Deco firmware tends to lock 5 GHz clients onto the farther Main node).
- Jitter note: AWDL (AirDrop, Universal Control, Handoff, and even wired Sidecar) time-shares the single Wi-Fi radio and was measured adding 100 ms–3 s stalls;
sudo ifconfig awdl0 downremoves most of it, but Sidecar re-raises AWDL within seconds. - Away from home (
en0's router isn'tHOST), the Deco isn't queried: the icon is a neutralglobeand the dropdown says "Not on the Deco network" with band and signal. The cached node is kept for the next run at home. - Same single-instance lock as
bgs.5s.sh; a failed query keeps the last answer and shows the error.
- macOS hides the BSSID from processes without Location Services, so the node comes from the Deco controller. Its global client list reports every client's
SwiftBar is a login item, not a launchd job, so nothing relaunches it when it dies. metrics.30s.sh restarts a host that is spinning, but it cannot notice one that is gone — it runs inside SwiftBar, so its ticks stop the instant the host does. The death ledger showed what that cost: a SIGSEGV on 2026-09-20 left the menu bar empty for 3h47m, and a 2026-09-09 death went 116h before the next tick.
This closes the hole from outside the process. A launchd job polls every 60s and relaunches SwiftBar only when it is absent — deliberately not KeepAlive on SwiftBar itself, which would make launchd own the process and race the login item into two instances. Measured recovery is ~64s.
Install:
cp .swiftbar-watchdog.plist ~/Library/LaunchAgents/com.mmichon.swiftbar-watchdog.plist
launchctl load -w ~/Library/LaunchAgents/com.mmichon.swiftbar-watchdog.plist
To stop it resurrecting an intentional quit, without unloading the job:
touch ~/Library/Application\ Support/xbar-metrics/watchdog_paused
Remove that file to resume. Relaunches are logged to ~/Library/Application Support/xbar-metrics/watchdog_log.
- Install SwiftBar.
- Point SwiftBar to this directory in its preferences.
- Ensure the scripts are executable:
chmod +x *.sh. - For the resolution switcher, install
displayplacer:brew install displayplacer. - For the CRD plugin, grant passwordless sudo for
pmset:echo "$USER ALL = (ALL) NOPASSWD:/usr/bin/pmset" | sudo tee /etc/sudoers.d/pmset