The idle Macs on your tailnet are wasted glass. ScreenBar makes them extra displays — or windows into their desktops — in one menu-bar click. It runs over Tailscale, so it works across networks.
ScreenBar is a native SwiftUI menu-bar app that links the Macs on your Tailscale network (or any reachable LAN) in two directions. It reads real connection state instead of stale flags, tells you which links are fast enough to actually use (Tailscale direct vs relay), and ships with a CLI and a doctor self-check. All system interaction lives in the app — no external shell scripts.
| Direction | Who shows what | Mechanism |
|---|---|---|
| Second screen | the other Mac shows this Mac | this Mac spins up a virtual display (BetterDisplay); the other Mac connects over Screen Sharing and goes full-screen → an extra monitor |
| Remote view | this Mac shows the other | this Mac acts as a Screen Sharing / Jump Desktop client → remote desktop (headless Mac minis too) |
- Live status — online · viewable · acting-as-screen · being-viewed, from real connections (inbound/outbound
:5900), not stale marker files. - Link quality — Tailscale direct vs relay; relay is laggy as a second screen, so you see which devices are usable at a glance.
- Per-device virtual displays with independent resolution / HiDPI.
- Auto-connect & reconnect — flagged devices attach the moment they come online.
- Post-connect verification & orphan cleanup — actionable hints on failure; unused virtual screens are reclaimed.
- Wake-on-LAN & launch-at-login.
- Jump Desktop (Fluid) view path for relayed devices — smooth where VNC lags.
- Built-in CLI +
doctorself-check; exports~/.config/screenbar/status.jsonfor dashboards.
- macOS 14+ / Swift 6
betterdisplaycli—brew install waydabber/betterdisplay/betterdisplaycli(for the second-screen direction)- Target Macs reachable (e.g. the same Tailscale tailnet) with key-based SSH
swift build # debug build
swift test # unit tests
Scripts/build-app.sh # release → ~/Applications/ScreenBar.app + launch-at-login- Devices — add or edit them in Settings → Device Management; stored in
~/.config/screenbar/devices.json. - This Mac's Tailscale IP — the address other Macs dial for the second-screen direction; set it in
~/.config/screenbar/m5host.
Neither file is committed to the repo.
The same binary doubles as a CLI (symlinked to ~/bin/screenbar):
screenbar status # all devices: online / viewable / in-use / link
screenbar list # id · name · mode · host
screenbar connect <id> # use a device as a second screen
screenbar disconnect <id>
screenbar view <id> # view a device's screen here (VNC)
screenbar unview
screenbar jump <id> # view via Jump Desktop (Fluid)
screenbar wake <id> # Wake-on-LAN
screenbar doctor # check environment + per-device readinessInherent to macOS Screen Sharing, not a limitation of this app.
- On the first connection to a device, tick Remember password.
- As a second screen, choose Standard mode on the other Mac — not High Quality, which dedicates (and blanks) your main display.
- For true multi-display, pick the matching
ScreenBar-<id>virtual display once in the other Mac's Screen Sharing Displays menu.
Sources/ScreenBar/
ScreenBarApp.swift @main — MenuBarExtra panel + Settings (+ CLI dispatch)
Model/ Device · DeviceMode · DeviceStatus · StatusDump
Store/ConfigStore.swift JSON persistence + first-run seed
State/AppModel.swift @MainActor @Observable hub — poll / network / auto-connect
Services/ Shell · Reachability · Tailscale · VirtualDisplay ·
RemoteControl · Connector · LaunchAtLogin · Diagnostics
UI/ MenuView · PreferencesView · DeviceEditView
CLI/CLI.swift same-binary command line
Tests/ netstat · Tailscale · WoL · config · CLI
Scripts/build-app.sh bundle .app + install LaunchAgent
Swift 6 strict concurrency, SwiftPM. A @MainActor @Observable state layer over a stateless async service layer that wraps all system calls (netstat / nc / tailscale / betterdisplaycli / ssh / open) through Shell.
MIT © 2026 Leo Lin