Repository navigation
start here
What mbdeploy is, where the machines are documented, and what is still missing.
mbdeploy builds micro:bit firmware and flashes it to a board over USB with
pyOCD, addressing boards by a short, stable, human-readable
name instead of a 48-character hardware UID. It keeps a small JSON registry so a
board keeps that identity across replugs, and it refuses by default to reflash a
radio relay. Run as a daemon (mbdeploy serve) it advertises each board it can
see over mDNS, so list, connect, and deploy can reach that board from
another machine on the LAN with --remote.
Source: https://github.com/Busboombot/mbdeploy
The machines are documented elsewhere. This site deliberately contains no hostnames, IP addresses, SSH details, or per-node install paths. The machine list, SSH access, per-node state, and current deployment status live on the internal Robot Garage wiki at http://robot-garage.home/doku.php?id=mbdeploy, reachable only from the garage LAN. See Deploying the daemon.
- Overview and installation — what problems the tool solves, what it depends on, and how to install it on macOS and on Linux/aarch64 (all wheels, no compilation, ~83 MB venv).
- The device model — the conceptual heart: two chips and two identities, why a board's five-letter name cannot be computed from its UID, what the registry stores and guarantees, and how a target string is resolved.
- Command reference — every subcommand and flag, the exit-code contract, and the stdout/stderr split scripts depend on.
-
Building and flashing — what
deployactually runs, automatic recovery of a locked/APPROTECT part, and why pyOCD's output is streamed line by line. -
The fleet daemon —
serve, its two mDNS services, both wire protocols verbatim, board exclusivity, and the rule that a flash preempts a live serial session. -
The remote client —
--remoteonlist,connect, anddeploy, and which flags it ignores. - Deploying the daemon — systemd units, tokens, group membership, and the pointer to the internal wiki where the actual machines are recorded.
- Troubleshooting — the failures that look like bugs and are not, and the ones that are.
The tool also carries its own copy of most of this: mbdeploy --agent prints a
complete manual to stdout, written for an agent driving the tool
non-interactively.
Read this before trusting any security property, and before filing a bug for something already known.
1. --remote clients cannot authenticate to a serve --token daemon.
The server implements AUTH <token> on both services, with a constant-time
comparison, and rejects anything else with ERR auth required. No client sends
it: there is no --token flag on list, connect, or deploy, and the client
code never writes an AUTH line. A token-protected daemon is therefore
currently unreachable by connect --remote and deploy --remote — they
fail immediately with auth required. list --remote is unaffected, because it
never opens a socket; it reads mDNS TXT records only, which the token does not
gate. Fixing this means adding --token/--token-file to the three client
subcommands and sending the handshake before the socket is handed to the console
or the FLASH header is written.
2. The relay guard is inert on any board that never announced.
Both the local guard and the daemon's guard read the registry's role field,
which is populated only from a board's serial announcement. On a board that has
never announced, role is empty, is_relay() returns False, and no FLASH
is ever refused for being a relay — --force-relay or not. On a fleet of silent
boards the relay tag has nothing to read. Do not assume the relay guard is doing
any work there: --no-flash is the access control that actually functions
today, and the token would be the other one if a client could send it (gap 1).
3. macOS only: serve can throw at process exit.
With hardware attached, mbdeploy serve on macOS can hit an
NSInvalidArgumentException inside hidapi's hid_exit() during interpreter
shutdown. This is a pre-existing hidapi/IOKit thread-safety bug, not an mbdeploy
defect, and it happens after the daemon has already unregistered its mDNS
advertisements and closed its sockets. It was explicitly verified not to
reproduce on Linux/aarch64 (47 consecutive clean process exits with real
hardware attached).
4. The mb-<uid8> mDNS fallback name is the same for every board.
When the daemon can name a board neither by its SWD read nor by an
announcement, it advertises it as mb-<last 8 of uid>. Every micro:bit UID ends
in the same eight hex characters (a DAPLink product/firmware suffix), so every
board in that state gets an identical name: they collide, zeroconf renames one
to mb-… (2), and across hosts they cannot be told apart — which matters
precisely because the advertised name is the network address. The per-board
entropy is in the middle of the UID; a fix should use a slice that actually
varies, or a short digest of the whole UID, and should log a warning when the
fallback fires at all. Boards in this state have already been observed on real
hardware.
-
The code is normative. Where a document and the source disagree, the source
wins — check
--helpoutput and the implementation before repeating a claim from any doc, including this one. - No machine specifics here, ever. Hostnames, IPs, SSH keys or usernames, and per-node install paths belong on the internal Robot Garage wiki, which is on the garage LAN. This site is world-readable.
-
docs/design/in the repo has stale spots.specification.md§11.1 andoverview.mdstill describeport_serial_map()as macOS-only andioreg-based; it has been a cross-platformpyserialVID:PID scan since the Linux support work, and everything those sections derive from that limitation (no ports, no announcements, no roles off macOS) no longer holds. Do not carry those claims into this site. -
Two announcement dialects exist, and only one was parsed before 2026-08-27.
A registry written by an older build can still hold a stale
role— see Troubleshooting.