Connect or disconnect your iPad as a Sidecar display from the macOS command line — no menus, no clicking, works even when the Mac's own screen is dead.
sidecar-connect is a tiny Swift CLI that drives Apple's private SidecarCore
framework — the exact same code path Control Center uses when you pick a device under
Screen Mirroring. Because it talks to the framework directly (instead of scripting the
UI), it works headlessly: you can connect your iPad with a single keyboard shortcut even
when you can't see the Mac's built-in display at all.
If your MacBook's built-in screen dies, you're stuck in a catch-22: Sidecar would give you a working display on your iPad, but turning Sidecar on normally requires you to see the screen to click through Control Center. The usual workaround is to plug into an external monitor every time just to enable mirroring.
sidecar-connect breaks that loop. Bind it to a keyboard shortcut and you can bring up your
iPad display blind — the hardware keyboard still works fine without a screen.
It's also just a convenient way to script Sidecar for anyone who wants a hotkey instead of a menu.
connect/disconnect/togglea Sidecar device by name (or the first one found).watch [name]runs forever, auto-reconnecting whenever the device isn't connected — the basis for the always-on login agent.listnearby and currently-connected devices (--jsonfor scripting).statuswith a meaningful exit code (0 = connected, 3 = not) for scripts and menu-bar tools.--wait <seconds>polls for the device to appear before acting — makes login auto-connect reliable.--no-sidebar/--no-touchbarto connect without the on-screen sidebar / Touch Bar.- Headless — no UI scripting, no Accessibility permissions, no screen required.
- Single self-contained binary, no dependencies beyond the Swift toolchain to build.
- macOS with Sidecar support (Catalina 10.15 or later; built and tested on macOS 26).
- A Sidecar-capable iPad already paired to the same Apple Account / set up for Sidecar.
- Xcode Command Line Tools to build (
xcode-select --install) — providesswiftc.
⚠️ This tool relies on a private, undocumented Apple framework (SidecarCore). See Caveats.
git clone https://github.com/say-michael/sidecar-connect.git
cd sidecar-connect
make # builds ./sidecar-connect
sudo make install # installs to /usr/local/binPrefer a user-local install with no sudo:
make install PREFIX="$HOME/.local" # installs to ~/.local/bin (make sure it's on $PATH)To remove it later: make uninstall (use the same PREFIX you installed with).
swiftc -O src/main.swift -o sidecar-connect && cp sidecar-connect /usr/local/bin/sidecar-connect <command> [name] [options]
Commands:
list List nearby/connected Sidecar devices ( ● = connected )
connect [name] Connect to a device (name = case-insensitive substring)
disconnect [name] Disconnect from a device
toggle [name] Connect if not connected, otherwise disconnect
watch [name] Run forever, auto-reconnecting whenever disconnected
status [name] Print connection state; exit 0 if connected, 3 if not
help, --help, -h Show help
version, --version Show version
Options:
--wait <seconds> Poll for the device to appear before acting (default 0)
--json Machine-readable output (list, status)
--quiet, -q Suppress progress lines (errors still print)
--no-sidebar Connect without the on-screen sidebar
--no-touchbar Connect without the on-screen Touch Bar
name is an optional, case-insensitive substring of the device name. With no name, the
command acts on the first device it finds.
$ sidecar-connect list
○ Michael’s iPad
$ sidecar-connect connect iPad
Connecting to Michael’s iPad…
Connected.
$ sidecar-connect toggle iPad # now connected → this disconnects
Disconnecting from Michael’s iPad…
Disconnected.Use Shortcuts.app (built into macOS) to fire sidecar-connect from a global hotkey:
- Open Shortcuts.app → click + to create a new shortcut → name it e.g. Sidecar Toggle.
- Add the Run Shell Script action.
- Set Shell to
zshand enter the script (use the full install path):/usr/local/bin/sidecar-connect toggle iPad
- Open the shortcut's details panel (ⓘ) → Add Keyboard Shortcut → press your key combo (e.g. ⌃⌥⌘S).
Now that combo connects Sidecar when it's off and disconnects when it's on — even with the lid screen dead, as long as you're logged in.
Tip: Trigger it once while you can see the screen (e.g. connected to a monitor) so you can approve any first-run permission prompt. After that it runs silently.
Want Sidecar to come up at login and stay connected all session, automatically reconnecting any time it drops (iPad out of range, sleep/wake, etc.)? There's a make target for it:
make install-agent # installs to /usr/local — may need sudo
# or, user-local:
make install-agent PREFIX="$HOME/.local"This installs the binary, writes a LaunchAgent to
~/Library/LaunchAgents/com.user.sidecar-connect.plist (with the correct install path baked
in), and loads it for your session. The agent runs watch iPad --quiet, which loops for the
whole session: it checks every 60 seconds whether the device is connected and reconnects it if
not — at login, after the iPad drops out of range, after sleep/wake, or any other disconnect.
KeepAlive makes launchd relaunch the watcher itself if it ever exits unexpectedly.
If your device isn't called "iPad", edit the name in
~/Library/LaunchAgents/com.user.sidecar-connect.plist (or in
dist/com.user.sidecar-connect.plist before installing),
then re-run make install-agent.
Remove it later with:
make uninstall-agent| Symptom | Fix |
|---|---|
No Sidecar devices found |
Ensure the iPad is awake, nearby, on the same Apple Account, and Sidecar is enabled in System Settings → Displays. |
connect failed / timeout |
The iPad may be locked or already in use by another Mac. Unlock it and retry. |
SidecarDisplayManager class not found |
The private API changed in your macOS version — see Caveats and re-run the API dumper. |
A NSForwarding … __NSGenericDeallocHandler line prints to stderr |
Harmless noise emitted when the private framework loads. Ignore it. |
If a future macOS renames the private classes/selectors, rebuild your knowledge of the API:
make dump-api
./dump-api | lessThis prints every Sidecar* Objective-C class and its methods so you can spot the new names
for SidecarDisplayManager, connectToDevice:completion:, etc., and update src/main.swift.
sidecar-connect dlopens /System/Library/PrivateFrameworks/SidecarCore.framework, grabs
SidecarDisplayManager.sharedManager, and calls its -devices, -connectedDevices,
-connectToDevice:completion: and -disconnectFromDevice:completion: methods via the
Objective-C runtime. The private interfaces are declared as @objc protocols in src/main.swift
and resolved at runtime — nothing is linked against the private framework at build time.
Because SidecarCore is private and undocumented:
- Apple can change or remove it in any macOS update. It has been stable for years, but there's
no guarantee. The
dump-apihelper exists precisely so you can adapt quickly if it breaks. - This is not endorsed by or affiliated with Apple. Use at your own risk.
Issues and PRs welcome — especially confirmations of which macOS versions work, and selector updates if Apple changes the API. Please keep the tool dependency-free and single-file.
MIT © say-michael
This project uses a private Apple framework for personal/interoperability purposes. "Sidecar", "iPad", and "macOS" are trademarks of Apple Inc. This project is not affiliated with, endorsed by, or supported by Apple.