An on-device botfor the Colorado mesh.
Companion-radio firmware built on top of MeshCore — pair the radio with the MeshCore app once, then the on-device bot answers ping, path, trace, status, neighbors, magic8, and more without the phone in the loop. No app bridge, no internet, no cloud.
A focused patch queue on top of upstream MeshCore.
The release-built firmware applies an ordered patch queue on top of a pinned MeshCore commit, so reviewers can see exactly what deviates from upstream. The patches stay small and behavioral — they don't fork the radio stack.
Bot command registry
Adds ping, hello, path, trace, status, channels, version, stats, magic8, prefix, time, lora, id, neighbors, and more — all answered on-device.
Channel-aware response policy
Replies only on #bot and #testing for normal commands. #emergency messages are forwarded to Public. All other channels are silent.
Multi-bot response coordinator
Hop-aware delay (~3 s per hop, capped at 15 s) on top of a ~1.5 s base + 2.2 s jitter, bounded by a 75 s TTL. Each reply carries a 4-hex request token so peer bots can correlate and suppress duplicates — even when reply text differs (hop count, SNR, recv time).
Prefixless commands everywhere
No `!` or `bot ` prefix needed — send the command name on its own, whether you're on #bot, #testing, or DMing the bot directly. Two-byte path hash by default for compact trace results.
Plug-and-play discovery
Sends its first flood advert ~5 s after boot so the rest of the mesh learns the bot is up almost immediately, and auto-overwrites the oldest contact when the table fills. Channel-side coordination is token-based, so dropping a second bot in the area needs no peer config.
Tunable host-side prefs
CLI-tunable channels, response delay, advert intervals, and known-bot list. Private-key import/export is disabled in release builds.
Send these on #bot, or DM the bot directly.
Prefixless on both channels and DMs — just send the command name, no ! or bot prefix. In any channel besides #bot, #testing, and #emergency, the bot stays silent.
| Command | Response |
|---|---|
| ping | Pong |
| hello | Hello @[<your-name>], from <bot-name> |
| path | Compact route summary back to you, e.g. Path 3h@2B SNR -6.25 | 2751 → ea4d → 430d |
| trace | Active trace request along your reverse path |
| status | Bot uptime, battery, storage, send counters |
| neighbors | Nodes heard directly within the last hour |
| version | Firmware version + build date |
| magic8 <question> | Classic 8-ball answer |
| help | List all commands |
Why nearby bots don't spam the channel
When several Colorado bots hear the same command, the response coordinator adds a hop-aware delay (~3 s per hop, capped at 15 s) on top of a ~1.5 s base + ~2.2 s jitter, bounded by a 75 s pending TTL. Each queued reply is prefixed with a 4-hex request token derived from the request fingerprint. Peer bots see the token go by, mark that request handled, and drop their pending reply. The closest bot wins the race; everyone else stays quiet — so #bot stays readable even with dense bot coverage.
Firmware releases
Published builds from the meshcore-bot-firmware repo.
Checking GitHub for the latest release…
133 board variants build on every release
ESP32: 57 · nRF52: 68 · RP2040: 4 · STM32: 4. Each board ships in USB and BLE variants where supported.
133 of 133 shown
| Board | Platform | Variant |
|---|---|---|
| Ebyte EoRa-S3 | ESP32 | BLE |
| Ebyte EoRa-S3 | ESP32 | USB |
| GAT562 30S Mesh Kit | nRF52 | BLE |
| GAT562 30S Mesh Kit | nRF52 | USB |
| GAT562 Mesh Tracker Pro | nRF52 | BLE |
| GAT562 Mesh Tracker Pro | nRF52 | USB |
| GAT562 Mesh Watch13 | nRF52 | BLE |
| Heltec E213 | ESP32 | BLE |
| Heltec E213 | ESP32 | USB |
| Heltec WSL3 | ESP32 | BLE |
| Heltec WSL3 | ESP32 | USB |
| Heltec Wireless Paper | ESP32 | BLE |
| Heltec Wireless Paper | ESP32 | USB |
| Heltec Wireless Tracker | ESP32 | BLE |
| Heltec Wireless Tracker | ESP32 | USB |
| Heltec ct62 | ESP32 | BLE |
| Heltec ct62 | ESP32 | USB |
| Heltec mesh solar | nRF52 | BLE |
| Heltec mesh solar | nRF52 | USB |
| Heltec t096 | nRF52 | BLE |
| Heltec t096 | nRF52 | USB |
| Heltec t114 | nRF52 | BLE |
| Heltec t114 | nRF52 | USB |
| Heltec t114 without display | nRF52 | BLE |
| Heltec t114 without display | nRF52 | USB |
| Heltec v2 | ESP32 | BLE |
| Heltec v2 | ESP32 | USB |
| Heltec v3 | ESP32 | BLE |
| Heltec v3 | ESP32 | USB |
| KeepteenLT1 | nRF52 | BLE |
| KeepteenLT1 | nRF52 | USB |
| LilyGo T-Echo-Lite | nRF52 | BLE |
| LilyGo T-Echo | nRF52 | BLE |
| LilyGo T-Echo | nRF52 | USB |
| LilyGo T3S3 sx1262 | ESP32 | BLE |
| LilyGo T3S3 sx1262 | ESP32 | USB |
| LilyGo T3S3 sx1276 | ESP32 | BLE |
| LilyGo T3S3 sx1276 | ESP32 | USB |
| LilyGo TBeam 1W | ESP32 | BLE |
| LilyGo TBeam 1W | ESP32 | USB |
| LilyGo TDeck | ESP32 | BLE |
| LilyGo TDeck | ESP32 | USB |
| LilyGo TETH Elite sx1262 | ESP32 | BLE |
| LilyGo TETH Elite sx1262 | ESP32 | USB |
| LilyGo TLora V2 1 1 6 | ESP32 | BLE |
| LilyGo TLora V2 1 1 6 | ESP32 | USB |
| M5Stack Unit C6L | ESP32 | BLE |
| M5Stack Unit C6L | ESP32 | USB |
| Mesh pocket | nRF52 | BLE |
| Mesh pocket | nRF52 | USB |
| Meshadventurer sx1262 | ESP32 | BLE |
| Meshadventurer sx1262 | ESP32 | USB |
| Meshadventurer sx1268 | ESP32 | BLE |
| Meshadventurer sx1268 | ESP32 | USB |
| Meshtiny | nRF52 | BLE |
| Meshtiny | nRF52 | USB |
| Minewsemi me25ls01 | nRF52 | BLE |
| Minewsemi me25ls01 | nRF52 | USB |
| Nano G2 Ultra | nRF52 | BLE |
| Nano G2 Ultra | nRF52 | USB |
| PicoW | RP2040 | USB |
| ProMicro | nRF52 | BLE |
| ProMicro | nRF52 | USB |
| R1Neo | nRF52 | BLE |
| R1Neo | nRF52 | USB |
| RAK 11310 | RP2040 | USB |
| RAK 3112 | ESP32 | BLE |
| RAK 3112 | ESP32 | USB |
| RAK 3401 | nRF52 | BLE |
| RAK 3401 | nRF52 | USB |
| RAK 3x72 | STM32 | USB |
| RAK 4631 | nRF52 | BLE |
| RAK 4631 | nRF52 | USB |
| RAK WisMesh Tag | nRF52 | BLE |
| RAK WisMesh Tag | nRF52 | USB |
| SenseCap Solar | nRF52 | BLE |
| SenseCap Solar | nRF52 | USB |
| Station G2 | ESP32 | BLE |
| Station G2 | ESP32 | USB |
| T Beam S3 Supreme SX1262 | ESP32 | BLE |
| Tbeam SX1262 | ESP32 | BLE |
| Tbeam SX1276 | ESP32 | BLE |
| ThinkNode M1 | nRF52 | BLE |
| ThinkNode M1 | nRF52 | USB |
| ThinkNode M2 | ESP32 | BLE |
| ThinkNode M2 | ESP32 | USB |
| ThinkNode M3 | nRF52 | BLE |
| ThinkNode M3 | nRF52 | USB |
| ThinkNode M5 | ESP32 | BLE |
| ThinkNode M5 | ESP32 | USB |
| ThinkNode M6 | nRF52 | BLE |
| ThinkNode M6 | nRF52 | USB |
| Tiny Relay | STM32 | USB |
| WioTrackerL1Eink | nRF52 | BLE |
| WioTrackerL1 | nRF52 | BLE |
| WioTrackerL1 | nRF52 | USB |
| Xiao C3 | ESP32 | BLE |
| Xiao C3 | ESP32 | USB |
| Xiao S3 WIO | ESP32 | BLE |
| Xiao S3 WIO | ESP32 | USB |
| Xiao nrf52 | nRF52 | BLE |
| Xiao nrf52 | nRF52 | USB |
| Xiao rp2040 | RP2040 | USB |
| heltec tracker v2 | ESP32 | BLE |
| heltec tracker v2 | ESP32 | USB |
| heltec v4 | ESP32 | BLE |
| heltec v4 | ESP32 | USB |
| heltec v4 tft | ESP32 | BLE |
| heltec v4 tft | ESP32 | USB |
| ikoka handheld nrf e22 30dbm 096 | nRF52 | BLE |
| ikoka handheld nrf e22 30dbm 096 | nRF52 | USB |
| ikoka handheld nrf e22 30dbm 096 rotated | nRF52 | BLE |
| ikoka handheld nrf e22 30dbm 096 rotated | nRF52 | USB |
| ikoka nano nrf 22dbm | nRF52 | BLE |
| ikoka nano nrf 22dbm | nRF52 | USB |
| ikoka nano nrf 30dbm | nRF52 | BLE |
| ikoka nano nrf 30dbm | nRF52 | USB |
| ikoka nano nrf 33dbm | nRF52 | BLE |
| ikoka nano nrf 33dbm | nRF52 | USB |
| ikoka stick nrf 22dbm | nRF52 | BLE |
| ikoka stick nrf 22dbm | nRF52 | USB |
| ikoka stick nrf 30dbm | nRF52 | BLE |
| ikoka stick nrf 30dbm | nRF52 | USB |
| ikoka stick nrf 33dbm | nRF52 | BLE |
| ikoka stick nrf 33dbm | nRF52 | USB |
| nibble screen connect | ESP32 | BLE |
| nibble screen connect | ESP32 | USB |
| t1000e | nRF52 | BLE |
| t1000e | nRF52 | USB |
| waveshare rp2040 lora | RP2040 | USB |
| wio-e5-mini | STM32 | USB |
| wio-e5 | STM32 | USB |
| wio wm1110 | nRF52 | BLE |
Three paths from download to flashed bot.
The web flasher is the fastest path for most operators. PlatformIO is for anyone building from source or running a custom patch. Manual esptool / nrfutil is the fallback when the browser-based path isn't an option.
MeshCore web flasher
Open flasher.meshcore.io in Chrome or Edge, pick "Custom firmware," drag in the right file for your board (merged.bin / uf2 / zip), and click Connect → Flash.
Open flasher.meshcore.io →PlatformIO from source
Clone the repo with --recurse-submodules, apply patches, then pio run -e <board>_companion_radio_usb -t upload. Swap the env for your specific board.
Open guide →esptool / nrfutil
ESP32: esptool.py write_flash 0x0 <board>-merged.bin. nRF52: drag the .uf2 onto the bootloader drive, or use adafruit-nrfutil with the .zip.
Open guide →First-time setup — four things, in order.
Because this is a companion-radio firmware, the radio still needs a one-time hand-off from a phone before the bot can do its job. Skipping this is the most common reason a freshly-flashed bot looks dead — the firmware is fine; it just has no clock and no channels yet.
- STEP 1
Pair the radio with the MeshCore app
This is a companion-radio firmware — the bot lives on the radio, but the radio still needs a one-time setup from a phone. After flashing, open the MeshCore companion app, pair over BLE (or USB if your board is USB-only), and complete the welcome flow.
- STEP 2
Sync the clock
The app pushes the phone's time to the radio on connect. Without this, timestamps in `time`, received-at fields, and the coordinator's TTL window all drift. Re-pair after any long power-off so the clock catches up.
- STEP 3
Add #bot, #testing, and #emergency
In the app's Channels screen, add the three community channels by name (the bot defaults to listening on these plus Public). Without the channels present in the radio's table, the bot has nothing to answer on — even though the firmware is configured to use them.
- STEP 4
Wait for the advert
The bot self-adverts ~5 s after boot and again on its scheduled interval. Once your other contacts see the advert, the bot will appear in their contact list and any nearby bot will auto-add it. From there, send `ping` on `#bot` to confirm it's alive.
The bot listens on #bot, #testing, #emergency, and Public
Those four are the bot's entire universe. #bot and #testing are where normal commands work. #emergency messages get re-broadcast on Public. Every other channel is silent — even DMs work, but the channel set is what the bot uses to scope replies.
Flash, drop into #bot, and say ping.
Found a bug, want a new command, or curious how the patch queue works? File an issue or jump in the Discord — both are open.