Thanks for considering a contribution. This is boot-critical firmware — a broken bootloader can leave a device needing a hardware programmer to recover — so a few things here are stricter than a typical repo.
- Read
AGENTS.mdfirst. It covers the board abstraction, the build system split (makevs. the incompleteCMakeLists.txt), the vendored submodules, and a list of known gotchas. This file covers process; that one covers the code. - New board support needs real hardware.
UF2_BOARD_ID, VID/PID, and pin definitions cannot be guessed from a datasheet alone — see Adding a new board below. - This repo is MIT-licensed (originally Adafruit Industries). By contributing, you agree your changes are under the same license.
You need arm-none-eabi-gcc and Python 3 installed.
git submodule update --init --recursive # lib/nrfx, lib/tinyusb, lib/uf2 — required, not vendored inline
python3 -m venv .venv && source .venv/bin/activate
pip install adafruit-nrfutil uritemplate requests intelhex setuptools
# ARM GCC 12.3.Rel1 is what CI pins (.github/workflows/githubci.yml).
# Newer versions (13.x verified working, 15.x does not) can hit a
# -Werror=array-bounds false positive in bootloader_settings.c — see
# AGENTS.md's Gotchas section before reaching for a newer toolchain.
make BOARD=wiscore_rak4631_board all
make BOARD=wiscore_rak4631_board copy-artifact # writes _bin/<board>/Board names are the directory names under src/boards/. tools/build_all.py
builds every board and prints a pass/fail + size table — run it before
opening a PR; it's the same check CI's board matrix does per-PR, just local.
Use make, not cmake. CMakeLists.txt only has a board.cmake for 2
of the 14 boards; cmake -DBOARD=<anything else> fails outright. Nobody
uses the CMake path in practice.
There is no lint or test suite — for a bootloader, "does it compile for every board" (CI's job) and real hardware testing are the correctness signals that exist.
The README's board list says to raise an issue for a board you'd like supported — that's still the right first step, and #4 and #5 are open examples. To actually submit the board yourself:
- You need the physical hardware to test on — a bootloader that compiles but was never flashed is not a contribution, it's a liability.
- Add
src/boards/<your-board>/board.handboard.mk, following an existing board (e.g.src/boards/wiscore_rak4631_board) as a template. UF2_BOARD_IDmust follow the format in the UF2 spec. If your board has an allocated VID/PID, link to it in the PR.- Confirm
make BOARD=<your-board> allsucceeds and the resulting UF2 actually boots the board correctly — not just compiles. - The PR template has a checklist for exactly this; fill it in.
- CI (
.github/workflows/githubci.yml) builds every board in the matrix on every PR. Branch protection onmasterrequires all of those checks to pass before merge. - Recent commit history is
Conventional Commits-style
(
docs:,ci:,chore:, etc.); older history (pre-fork) is looser — match the newer style going forward. - Keep PRs scoped to one change. A board addition, a docs fix, and a CI tweak are three PRs, not one.
This project follows the
Meshtastic Code of Conduct. Report security
vulnerabilities privately per SECURITY.md — not as a
public issue.