Repository navigation
service macos
LaunchDaemon (root, at boot) and LaunchAgent (per user) plists, with the launchctl commands to run them.
mbregistry install-service does not support macOS; it writes systemd
files. Use one of the plists below. No drivers or udev-style rules are
needed, because a normal user can open the micro:bit's serial and
CMSIS-DAP interfaces.
Pick one. Both use the label org.jointheleague.mbregistry, and only
one daemon may run per host.
| LaunchDaemon (root) | LaunchAgent (one user) | |
|---|---|---|
| Starts | at boot, no login | when that user logs in |
| Plist | /Library/LaunchDaemons/org.jointheleague.mbregistry.plist |
~/Library/LaunchAgents/org.jointheleague.mbregistry.plist |
| Install mbtools into | /opt/mbtools |
~/.local/share/mbtools |
| Database | /Library/Application Support/mbregistry/devices.db |
~/Library/Application Support/mbregistry/devices.db |
| Local API socket | /var/run/mbregistry/api.sock |
~/Library/Application Support/mbregistry/api.sock |
| Log | /Library/Logs/mbregistry.log |
~/Library/Logs/mbregistry.log |
| launchctl target | system/org.jointheleague.mbregistry |
gui/$(id -u)/org.jointheleague.mbregistry |
| Best for | an unattended board host | a workstation |
Clients (mbregistry list, mbdeploy, ...) try the user's own socket
first, then the root one, so either setup works with no flags.
Both plists run <venv>/bin/python -m mbtools.registry.cli run, the same
entry point as the Linux unit. KeepAlive → SuccessfulExit=false
restarts the daemon after a crash but not after a clean stop, like
systemd's Restart=on-failure. ThrottleInterval spaces restarts 10 s
apart.
Install into /opt/mbtools first (see
Installing mbtools).
sudo tee /Library/LaunchDaemons/org.jointheleague.mbregistry.plist >/dev/null <<'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.jointheleague.mbregistry</string>
<key>ProgramArguments</key>
<array>
<string>/opt/mbtools/bin/python</string>
<string>-m</string>
<string>mbtools.registry.cli</string>
<string>run</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>PYTHONUNBUFFERED</key>
<string>1</string>
</dict>
<key>WorkingDirectory</key>
<string>/</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false/>
</dict>
<key>ThrottleInterval</key>
<integer>10</integer>
<key>StandardOutPath</key>
<string>/Library/Logs/mbregistry.log</string>
<key>StandardErrorPath</key>
<string>/Library/Logs/mbregistry.log</string>
</dict>
</plist>
EOF
sudo chown root:wheel /Library/LaunchDaemons/org.jointheleague.mbregistry.plist
sudo chmod 644 /Library/LaunchDaemons/org.jointheleague.mbregistry.plist
plutil -lint /Library/LaunchDaemons/org.jointheleague.mbregistry.plist
sudo launchctl enable system/org.jointheleague.mbregistry
sudo launchctl bootstrap system /Library/LaunchDaemons/org.jointheleague.mbregistry.plist
sudo launchctl kickstart -k system/org.jointheleague.mbregistryA LaunchDaemon plist must be owned by root:wheel with mode 644.
Otherwise bootstrap refuses it.
Operate it:
sudo launchctl print system/org.jointheleague.mbregistry | head -30 # state, pid, last exit code
sudo launchctl kickstart -k system/org.jointheleague.mbregistry # restart
sudo launchctl bootout system/org.jointheleague.mbregistry # stop and unload
sudo launchctl disable system/org.jointheleague.mbregistry # keep it from loading at boot
tail -f /Library/Logs/mbregistry.logInstall into ~/.local/share/mbtools first. launchd doesn't expand ~,
so this heredoc writes absolute paths from $HOME:
mkdir -p ~/Library/LaunchAgents ~/Library/Logs
cat > ~/Library/LaunchAgents/org.jointheleague.mbregistry.plist <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.jointheleague.mbregistry</string>
<key>ProgramArguments</key>
<array>
<string>$HOME/.local/share/mbtools/bin/python</string>
<string>-m</string>
<string>mbtools.registry.cli</string>
<string>run</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>PYTHONUNBUFFERED</key>
<string>1</string>
</dict>
<key>WorkingDirectory</key>
<string>$HOME</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false/>
</dict>
<key>ThrottleInterval</key>
<integer>10</integer>
<key>StandardOutPath</key>
<string>$HOME/Library/Logs/mbregistry.log</string>
<key>StandardErrorPath</key>
<string>$HOME/Library/Logs/mbregistry.log</string>
</dict>
</plist>
EOF
plutil -lint ~/Library/LaunchAgents/org.jointheleague.mbregistry.plist
launchctl enable gui/$(id -u)/org.jointheleague.mbregistry
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/org.jointheleague.mbregistry.plist
launchctl kickstart -k gui/$(id -u)/org.jointheleague.mbregistryOperate it with the same verbs as the LaunchDaemon: print, kickstart -k, bootout, disable. Use target gui/$(id -u)/org.jointheleague.mbregistry
and no sudo. The log is at ~/Library/Logs/mbregistry.log.
If you installed with uv tool install, use that tool's interpreter as
the first ProgramArguments entry. head -1 "$(command -v mbregistry)"
prints it (the shebang line).
- Add flags as extra
<string>elements afterrun, e.g.<string>--no-relay-pool</string>or<string>--peer</string><string>host-a</string>. - Add env vars (e.g.
MBREGISTRY_TOKEN) underEnvironmentVariables. - After editing, run
bootout, thenbootstrapagain.
See Command reference for every flag and variable.
sudo /opt/mbtools/bin/pip install --upgrade "git+https://github.com/League-Microbit/mbtools.git"
sudo launchctl kickstart -k system/org.jointheleague.mbregistry
# LaunchAgent: ~/.local/share/mbtools/bin/pip install --upgrade ...; launchctl kickstart -k gui/$(id -u)/org.jointheleague.mbregistrysudo launchctl bootout system/org.jointheleague.mbregistry
sudo rm /Library/LaunchDaemons/org.jointheleague.mbregistry.plist
sudo rm -rf /opt/mbtools "/Library/Application Support/mbregistry" # optional- Local Network privacy (macOS 15+). Programs started as a user can be blocked from the LAN until allowed in System Settings → Privacy & Security → Local Network. If a LaunchAgent finds no peers but the same command run in Terminal does, check there. A root LaunchDaemon doesn't get this prompt.
- Application Firewall. If it is enabled, allow the interpreter. See Networking and peering.
-
The logs grow without limit. Truncate them occasionally
(
sudo truncate -s 0 /Library/Logs/mbregistry.log) or add anewsyslog.dentry. -
Foreground debugging. Stop the service first (one daemon per host).
Then run
mbregistry runfor the per-user paths, orsudo mbregistry runfor the root paths.