Headless boards
Install, configure, update, and supervise a dartpilot board with no screen, on a Raspberry Pi, a small server, or a Mac.
A headless board runs the same camera and detection engine as the desktop app but has no window. It serves the Board Console over HTTP so you configure and calibrate it from any browser on the same network: a phone, a TV, or a laptop. This is the recommended setup for venues and for machines with no display attached: a Raspberry Pi, a small Linux server, or a Mac.
Install
curl -fsSL https://get.dartpilot.app/headless.sh | sh
This downloads the latest build for your platform to ~/.local/share/dartpilot
and symlinks ~/.local/bin/dartpilot. It also installs a service that starts on
boot and restarts on failure:
| Platform | Service |
|---|---|
| Linux | systemd user unit dartpilot. Camera access is granted to the service automatically (SupplementaryGroups=video). |
| macOS | LaunchAgent com.dartpilot.board in ~/Library/LaunchAgents. No sudo, and no camera-group setup. |
If you are unsure whether the machine is a desktop or a board, run the installer with no flags; it detects a graphical session and asks if it cannot.
First start and pairing
On first start the board prints a sign-in code to its logs:
# Linux
journalctl --user -u dartpilot -f
# macOS
tail -f ~/Library/Logs/dartpilot/dartpilot.out.log
Enter the code at play.dartpilot.app/device to approve it. The board then stays connected. On macOS, allow camera access when macOS asks. Until you do, it cannot see the board.
The same log prints the Board Console URL:
Board Console: http://192.168.1.42:3000/#key=…
Open that URL (including the #key=… fragment) in a browser on the same network.
The fragment key is exchanged for a cookie, so MJPEG and event streams authenticate
too. The key lives at ~/.local/share/com.dartpilot.desktop/console_key on Linux
and ~/Library/Application Support/com.dartpilot.desktop/console_key on macOS;
delete it to rotate.
Board Console
From the console you can:
- select cameras and resolution, and set the frame rate;
- run calibration and watch the live camera feeds;
- pair/re-pair the board and reset its identity;
- start/stop detection and preview;
- export a board image for the web scoreboard.
Configuration
Everything is set with CLI flags or environment variables. There is no config file to edit.
| Flag | Env var | Default | Purpose |
|---|---|---|---|
--bind <ADDR> |
DARTPILOT_BIND_ADDR |
0.0.0.0:3000 |
Address the local API/console listens on. |
--log-level <LEVEL> |
DARTPILOT_LOG |
info |
trace/debug/info/warn/error. |
--log-format <FMT> |
DARTPILOT_LOG_FORMAT |
text |
text or json (structured logs). |
--check-update |
– | – | Print whether a newer release is available, then exit. |
--update |
– | – | Download, verify, and install the latest release, then exit. |
-V, --version |
– | – | Print the version and exit. |
-h, --help |
– | – | Print usage and exit. |
Updating
Update in place:
dartpilot --update
The board does not leave a stopped or broken build behind. --update stops the
service, swaps in the new build, checks that it actually runs, and starts the
service again, restoring the previous version if the check fails. It reads
https://get.dartpilot.app/headless.json and verifies the archive SHA-256 first.
If the restart fails it prints the command to run yourself:
systemctl --user restart dartpilot # Linux
launchctl kickstart -k gui/$(id -u)/com.dartpilot.board # macOS
A venue can roll a fleet by issuing the update command from the dashboard; the
board updates and restarts itself.
Operations
# Linux
systemctl --user status dartpilot # service state
systemctl --user restart dartpilot # restart the board
journalctl --user -u dartpilot -f # follow logs
journalctl --user -u dartpilot | jq # parse JSON logs (--log-format json)
# macOS
launchctl print gui/$(id -u)/com.dartpilot.board # service state
launchctl kickstart -k gui/$(id -u)/com.dartpilot.board # restart the board
tail -f ~/Library/Logs/dartpilot/dartpilot.out.log # follow logs
Readiness is exposed at GET http://<board>:3000/api/health (no key required) for
the service manager and LAN dashboards. It reports ready, phase
(starting/calibrating/ready/error), board_state, per-camera calibration,
detection status, and the version. See the
health contract
for every field.
Recipes
Raspberry Pi with no display (venue rack)
- Flash Raspberry Pi OS, boot it, and join the venue network.
- Run the headless installer and approve the sign-in code.
- Open the printed Board Console URL on your phone with the board’s cameras mounted, select them, and calibrate.
- Point a TV or tablet at the scoreboard; the board itself needs no screen.
Small server / NUC
The same installer works on x86_64 Linux. Bind to a specific interface and use
JSON logs if you ship them to a log collector:
DARTPILOT_BIND_ADDR=0.0.0.0:3000 DARTPILOT_LOG_FORMAT=json dartpilot
Mac
The installer works on Apple Silicon and Intel Macs. A LaunchAgent starts when the user logs in rather than at boot, so keep the board’s user logged in (enable automatic login if the Mac reboots unattended). Everything else is the same as Linux.
Troubleshooting
- No cameras in the Console. Confirm they are UVC USB cameras. On Linux, check
the service has the
videogroup (systemctl --user show dartpilot -p SupplementaryGroups). On macOS, open System Settings → Privacy & Security → Camera and allow dartpilot. Then read the logs (see Operations). - Console asks for an access key. Open the full URL printed at boot, including
the
#key=…fragment. If you lost it, read theconsole_keyfile listed above. ready: falsein/api/health. Readphaseandcameras.items[].calibration. The board stays up and explains the failure rather than exiting.