Sign inSign up

yusoltsev/magichop

By yusoltsev

•Updated 3 months ago

MagicHop coordinates Bluetooth handoff across your Macs using a small Go/NATS daemon

Image
0

1.7K

yusoltsev/magichop repository overview

⁠MagicHop

Build Status Codecov GitHub Release Docker Image (docker.io) Docker Image (ghcr.io) Docker Image Size

MagicHop lets several Macs share Apple Magic peripherals, such as Magic Keyboard, Magic Mouse, and Magic Trackpad, without talking to each other directly. A coordinator runs embedded NATS, each Mac runs a local daemon, and magichop claim asks another Mac to release a peripheral before acquiring it locally.

Release means unpairing the peripheral from the current Mac. Acquire means clearing stale local pairing state, pairing, connecting, and verifying the connected state.

⁠Usage

⁠Coordinator

Run the coordinator on an always-on host:

docker run -d \
  --name magichop \
  --restart unless-stopped \
  -e MAGICHOP_AUTH_TOKEN=<shared-token> \
  -e MAGICHOP_HOST=0.0.0.0 \
  -e MAGICHOP_PORT=4222 \
  -p 4222:4222 \
  ghcr.io/yegor-usoltsev/magichop:latest

Or run the binary directly:

magichop server --host 0.0.0.0 --port 4222 --auth-token <shared-token>
⁠Macs

Put the release binary somewhere stable:

mkdir -p ~/.local/bin
cp magichop ~/.local/bin/magichop

Install blueutil and find paired Bluetooth addresses:

brew install blueutil
blueutil --paired

Create ~/.config/magichop/config.json:

{
  "node_name": "macbook-a",
  "coordinator_url": "nats://coordinator.local:4222",
  "auth_token": "CHANGE_ME",
  "default_device": "trackpad",
  "devices": {
    "keyboard": "aa:bb:cc:dd:ee:01",
    "trackpad": "aa:bb:cc:dd:ee:02"
  }
}

The config file contains the shared token and should be owner-only:

chmod 600 ~/.config/magichop/config.json

Install and start the macOS LaunchAgent:

magichop install mac

Run a daemon manually during development:

magichop daemon --config ~/.config/magichop/config.json

Claim the default peripheral:

magichop claim

Claim an alias or a raw Bluetooth address:

magichop claim keyboard
magichop claim trackpad
magichop claim aa-bb-cc-dd-ee-ff

Release locally without telling another Mac to acquire:

magichop release trackpad

Inspect local state:

magichop status
magichop devices
magichop devices --scan
magichop doctor

JSON output is available for user-facing daemon commands:

magichop claim --json
magichop release trackpad --json
magichop status --json
magichop devices --json
magichop doctor --json

⁠Raycast

Generate Raycast Script Commands:

magichop install raycast

Add ~/.local/raycast-scripts in Raycast under Settings -> Extensions -> Script Commands -> Add Script Directory.

Generated scripts call magichop claim <device>. Raycast and other local clients never run blueutil directly.

⁠Environment Variables

Coordinator:

KeyTypeDefaultRequired
MAGICHOP_HOSTstring0.0.0.0No
MAGICHOP_PORTint4222No
MAGICHOP_AUTH_TOKENstringYes

Mac clients use MAGICHOP_CONFIG when it is set. Otherwise they read ~/.config/magichop/config.json.

⁠Commands

magichop server --host 0.0.0.0 --port 4222 --auth-token TOKEN
magichop daemon --config ~/.config/magichop/config.json
magichop claim [device-or-address] [--json] [--timeout 11s]
magichop release [device-or-address] [--json]
magichop status [device-or-address] [--json]
magichop devices [--scan] [--json]
magichop doctor [--json]
magichop install mac
magichop install raycast [--dir DIR]
magichop uninstall mac
magichop edit
magichop upgrade [--check] [--version VERSION] [--yes]
magichop version

⁠Files

PathPurpose
~/.config/magichop/config.jsonConfig and shared token
~/Library/Application Support/MagicHop/state.jsonlAccepted and final claim records
~/Library/Logs/MagicHop/daemon.jsonlDaemon logs
$TMPDIR/magichop-$UID/daemon.sockLocal CLI socket
~/Library/LaunchAgents/dev.magichop.daemon.plistmacOS LaunchAgent

⁠Upgrade

Check for the latest release:

magichop upgrade --check

Upgrade from GitHub Releases:

magichop upgrade --yes

MagicHop downloads the platform archive and checksums.sha256.txt, verifies SHA-256, replaces the current binary, and restarts the LaunchAgent when installed.

⁠Versioning

This project uses Semantic Versioning⁠.

⁠License

MIT⁠

Tag summary

Content type

Image

Digest

sha256:f84acb8c0…

Size

11.9 MB

Last updated

3 months ago

docker pull yusoltsev/magichop