Repository navigation
Releases: OwlShack/OwlBot
Release list
v1.3.0
v1.3.0 - 2026-10-09
Warning
meshcore-bot is now OwlBot. Updating needs a manual step, or you stay on v1.2.0.
- Docker:
ghcr.io/meshcore-go/meshcore-botgets no more updates. Pulling it keeps you on
v1.2.0 with no error. Switch toghcr.io/owlshack/owlbot. - Downloads: release files are now
OwlBot-<os>-<arch>. A script that fetches the latest
meshcore-bot-*file gets a 404. - The program is
OwlBot. Update service files, scripts andpgreplines that name
meshcore-bot, and a Docker command that runs it by name. - MQTT:
modelandclient_versionnow sayOwlBot. Update any dashboard or filter that
matches onmeshcore-bot. - The repository moved to OwlShack/OwlBot. Old links
redirect.
Your config file, mqtt_identity.key, bot identities and MQTT topics carry over unchanged. See
Upgrading below.
Baseline v1.2.0. The bot is renamed OwlBot, templates can print dates and times, and it is
built on meshcore-go v1.7.0.
Added
- Templates can print dates and times.
{{date now "15:04"}}gives the current time, and
{{date .Timestamp "15:04"}}when a channel message was sent. An optional zone such as
"Pacific/Auckland"sets the time zone, and works the same on every platform. - Posts can be scoped to a MeshCore region.
floodScope = "region:nz"on a bot or a trigger
sends its posts so only repeaters that allow#nzpass them on. Unset stays unscoped, as before. - Each MQTT broker can set its own topics.
packetTopicandstatusTopictake{iata},
{pubkey}and{name}, for brokers that expect a different layout. Unset keeps the current
topics. - Choose how path hashes are joined.
{{formatPathBytes .PathHashes " > "}}gives
A1 > B2 > C3instead of the defaultA1, B2, C3.
Changed
- meshcore-bot is renamed OwlBot. The binary, release downloads and Docker image carry the
new name. Your config file andmqtt_identity.keycarry over as they are, so every bot keeps
its mesh identity and the MQTT observer keeps its public key. - MQTT status reports
modelasOwlBot.client_versionis nowOwlBot/<version>. - Built on meshcore-go v1.7.0. The bot's own messages go out at firmware transmit priorities
rather than queuing behind relayed traffic, and it ignores packets firmware discards, such as
encrypted payloads that are not whole AES blocks.
Fixed
- The MQTT status says online again as soon as a broker reconnects. When the link drops, the
broker publishes the bot as offline. It used to stay that way until the next status, up to 5
minutes later, even though the bot was back. - Packets dropped while a broker is down are now logged. They are still not buffered, but a
warning says when a broker starts dropping them, and the count is logged when it reconnects.
Before, they went missing without a word, including any heard in the moment before the first
connection.
Upgrading
- Docker: switch the image to
ghcr.io/owlshack/owlbot.ghcr.io/meshcore-go/meshcore-bot
stays at v1.2.0. If you mounted onlyconfig.toml, copymqtt_identity.keyout of the old
container first, or the observer starts with a new identity. The README has the command. - Binary: replace it with an
OwlBot-*download and change any service file or script that
runsmeshcore-bot. Run it from the same directory as before.
What's Changed
- Rename to OwlBot and move to meshcore-go v1.7.0 by @tuzzmaniandevil in #26
- Template functions for dates and times by @tuzzmaniandevil in #27
- Optional separator for formatPathBytes by @tuzzmaniandevil in #28
- Optional separator for formatPathBytes (reland #28) by @tuzzmaniandevil in #29
- Changelog: warn about the rename by @tuzzmaniandevil in #30
- Log MQTT packets dropped while a broker is down by @tuzzmaniandevil in #31
- Scope posts to a MeshCore region (floodScope) by @tuzzmaniandevil in #32
- Per-broker MQTT topic templates by @tuzzmaniandevil in #33
- Publish online again when a broker reconnects by @tuzzmaniandevil in #34
- Release v1.3.0 by @tuzzmaniandevil in #35
- v1.3.0 by @tuzzmaniandevil in #36
Full Changelog: v1.2.0...v1.3.0
v1.2.0
v1.2.0 - 2026-09-30
Baseline v1.0.6. openHop Modems and SPI radio hats join KISS firmware, the MQTT status now uses
the firmware's own names and meanings, and brokers stay connected through outages and token
refreshes.
Config adds the openhop:// and spi:// connections and the spiBoard, modemToken and
dutyCycle settings. nodeType is no longer needed.
Added
- openHop Modems. Connect with
openhop:///dev/ttyUSB0over USB, oropenhop://host:port
over the network withmodemTokenas its password. The modem's radio is set to MeshCore's
settings on every connect, and a dropped link reconnects on its own. - SPI radio hats on a Raspberry Pi. Connect with
spi://and choose the hat by name with
spiBoard, from 15 SX1262 hats, the same list OwlShack has. Atxabove the hat's rating is
refused rather than turned down. To add a hat or correct one, put aboards.jsonin the
directory the bot runs from. - Packets the bot sends appear on MQTT. Each one is published with
"direction": "tx", as
firmware nodes publish theirs. Signal fields are left off, since there is no received signal to
report. - Received packets carry
score,durationandpath.scoreanddurationmatch the
firmware's packet log.pathis the source and destination prefixes, as the firmware prints them,
not the route. - The status reports more of what the firmware does.
mcu_temp_c,last_snr,last_rssi,
rx_air_secs,tx_air_secs,flood_txanddirect_txare new instats, andrepeatis new
at the top level.mcu_temp_cis left out on a board without a temperature sensor. - The status reports transmit and receive faults. New counters in
statsshow packets
retried, dropped or failed, and whether the channel was busy or the bot sent faster than the radio
could keep up. They count everything this process sends and receives, not one bot. - SPI hats and openHop Modems report chip-level errors.
crc_errors,driver_errorsand
recv_recoveriesappear instatswhere the radio can measure them, and are left out on KISS. dutyCyclelimits how much of the time the radio transmits. It is a percentage, like the
firmware'sset dutycycle, and takes fractions such as0.1for EU868 sub-bands. The default is
unchanged, and the duty cycle in use is logged at startup.- Slow message handling is logged and counted. One slow reply holds up every bot's receiving,
so any that takes over half a second is logged and counted instats.handler_slow. - The bot reconnects a radio that is lost. An unplugged modem, a dropped link, or a radio that
stops answering for about 90 seconds is reconnected on its own, with retries up to every 30
seconds, and the bots and MQTT status come back with it. Before, the bot kept running but heard
and sent nothing until it was restarted.
Changed
recv_errorsnow means what it means on a firmware node. It counts packets the radio
failed to receive. It used to count packets that arrived intact but did not decode, which is now
packet_parse_errors. Firmware nodes publishrecv_errorsto the same brokers, so the two now
agree.battery_percentis replaced bystats.battery_mv. The firmware reports millivolts, and the
old percentage showed 100% on boards with no battery.battery_mvis left out when the board has
no battery or has stopped answering.noise_floormoved intostats. It sits with the other radio readings, as the firmware
reports it.stats.packets_receivedis nowstats.recv, withstats.packets_recvbeside it. These are
the names the firmware and CoreScope use.stats.sentis published alongside
stats.packets_sent.SNRandRSSIare left out when a packet arrives without them. They used to read 0, which
looked like a real measurement.- The connection chooses the radio.
nodeTypeis ignored, so an existing config still loads
and it can be deleted.
Fixed
- A broker that is down at startup is retried. It used to be dropped until the bot was
restarted or reloaded. It is now retried with a growing delay, up to 5 minutes. - Startup no longer waits for brokers. Each unreachable broker could hold up startup for 10
seconds. The bot now starts at once and connects in the background. - Shutdown and reload no longer hang on an unresponsive broker. The last status sent on the way
down now gives up after 5 seconds rather than waiting forever. - A failed token refresh no longer leaves a broker disconnected. The broker used to stay
down for 6 minutes or more. It now reconnects straight away. - Refreshing a token no longer makes the connection flap. The old connection is closed before
it can push the new one off. packets_sentandqueue_lenreport real values. Both read 0 on every status since v1.0.6.- Every counter in a status is taken at the same moment. A packet arriving mid-report could
showrecv: 2beside alast_rssiof 0. - Sends that meet a busy radio are retried again. They had been given up on at the first try.
- Long packets at slow radio settings are no longer counted as failed. The bot now waits as
long as the packet takes on air, rather than a fixed time that the largest packets could outlast. - A modem that stops answering no longer shows its last battery and temperature. They are left
out once it has been silent for 45 seconds. - A packet that failed to send no longer appears on MQTT as sent.
- A config mistake on reload keeps the running config. An unknown connection used to stop the
bot. It is now refused when the config loads, as isspi://withoutspiBoard.
Upgrading
- If you read this node's MQTT status, check
recv_errorsfirst. It keeps its name but changes
meaning, and nothing on the wire marks the change. A rate or delta over it will jump at the
upgrade. Usepacket_parse_errorsif you wanted the old count. - Other MQTT fields to check:
battery_percentis gone,noise_floorhas moved intostats,
stats.packets_receivedis nowstats.recv, andSNR,RSSI,battery_mvandmcu_temp_c
can be absent. - Building from source needs Go 1.26.7.
What's Changed
- feat: openHop and SPI radios, firmware-named MQTT status, broker resilience by @tuzzmaniandevil in #20
- chore: CI on PRs into dev, rc tags as pre-releases, maxRetries wording by @tuzzmaniandevil in #21
- feat: reconnect a radio that is lost by @tuzzmaniandevil in #22
- Release v1.2.0 by @tuzzmaniandevil in #23
- v1.2.0 by @tuzzmaniandevil in #24
Full Changelog: v1.0.6...v1.2.0
v1.1.0-alpha.4
Highlights
- Map: neighbor-link SNR topology overlay — draw repeater-to-repeater links colored by signal strength (#13)
- Monitoring: poll retries are now bounded (configurable max attempts + delay) and fall back to the normal interval instead of re-polling an unreachable node forever (#14)
- Packets: server-side type filter + hash/path search (#12); Peers: search by pubkey (#11)
- Internal: context propagation, error hardening, package splits, chat delta-paging, first unit tests (#9, #10)
What's Changed
- Store context propagation, error hardening, file splits, chat paging + first tests by @tuzzmaniandevil in #9
- Fix standalone channel validation and direct-neighbour OutPath persistence by @tuzzmaniandevil in #10
- Search peers by pubkey instead of type by @tuzzmaniandevil in #11
- Packets: server-side type filter and hash/path search by @tuzzmaniandevil in #12
- feat(Map): added neighbor link strength to map page by @ModerateWinGuy in #13
- feat(monitor): bound poll retries instead of retrying forever by @tuzzmaniandevil in #14
New Contributors
- @ModerateWinGuy made their first contribution in #13
Full Changelog: v1.1.0-alpha.3...v1.1.0-alpha.4
v1.1.0-alpha.3
Offline-first hardening on top of alpha.2.
Pre-release. Not promoted to
latest, and the stablev1.0.xline is unaffected.
Offline-first fonts
- No more Google Fonts CDN. Inter and JetBrains Mono are now self-hosted: the latin variable-weight woff2 files are vendored and embedded directly in the binary, served same-origin via
@font-face. The app no longer fetches anything from the internet, which matters for air-gapped / LAN deployments and behind locked-down proxies. A single variable file per family covers every weight the app uses. (Also removed two dead, unreferenced font files.)
PWA installable behind an auth proxy
- Works through SSO / auth gateways (e.g. Pangolin). Browsers fetch the web app manifest without the session cookie by default, so an auth proxy returned a login redirect and the manifest failed to parse, leaving the console marked "not installable." The manifest link now requests with credentials (
crossorigin="use-credentials"), so it authenticates like the rest of the app and the Install button appears as expected. The self-hosted fonts help here too: they are now same-origin assets that pass the proxy with the page's cookie.
Full changelog: v1.1.0-alpha.2...v1.1.0-alpha.3
v1.1.0-alpha.2
Second alpha in the v1.1 line. Headline: richer in-app chat, on-demand companion adverts, and the web console is now installable as a PWA.
Pre-release. Not promoted to
latest, and the stablev1.0.xline is unaffected.
Chat
- @-mention autocomplete. Typing
@in a channel or room composer pops up name suggestions drawn from that conversation's participants (not your whole contact list), like emoji autocomplete. - #hashtag channel chips. Hashtags in messages (e.g.
#weather) now render as clickable chips that either offer to add the channel or jump straight to it if you already have it. Adding a channel from a message now selects the newly added thread instead of dropping you on an empty chat screen.
Companions
- Advert triggers. Send a Flood or Zero-hop advert for a companion on demand. Surfaced as header chips on desktop and folded into a single overflow menu on mobile so the header stays tidy on small screens.
- Sidebar sub-navigation. The sidebar now lists your companions, so jumping between chats is one click on both desktop and mobile.
Monitoring
- POLL on the node detail page. The on-demand poll button now lives on the individual node view, not just the monitoring list.
PWA (Phase 1: installability)
- The web console is now an installable app via a hand-rolled service worker and web app manifest (no Workbox). An Install button appears in the sidebar when the browser offers it. Navigations are network-first and content-hashed assets are cache-first, so it never serves a stale build. No push notifications yet.
Fixes
- Never flood a node we can reach directly. A peer reachable directly is stored as a 0-hop path, which the send paths previously treated the same as an unknown route and flooded, needlessly rebroadcasting across the whole mesh. Direct neighbours (0-hop) and known multi-hop paths now route direct; only a genuinely unknown route floods. Covers monitoring polls (status/telemetry/neighbours), repeater login and CLI, and companion ACKs. (DMs still flood 0-hop neighbours pending a meshcore-go library release.)
Under the hood
- CLI command / config-key catalogue extracted to a JSON data file for easier reuse and maintenance.
- Shared
AddChannelDialogplus channel/node API helpers extracted to cut duplication. - Tailwind arbitrary-value classes canonicalized, with the convention documented for future contributors.
Full changelog: v1.1.0-alpha.1...v1.1.0-alpha.2
v1.1.0-alpha.1
First pre-release of the 1.1 line — a near-complete rewrite. The bot gains a
full web UI, moves all configuration into SQLite, and is now distributed under
the OwlShack name. This is an alpha: expect rough edges and please
report issues.
Highlights
- New web UI (React SPA at
:8080). Operator-console aesthetic over a
single embedded static binary — no separate frontend to host. - Configuration lives in SQLite, not files. A first-run setup wizard
bootstraps a node; config files become one-time imports. Per-resource config
screens (Radio, MQTT, Companions, Bots/triggers) edit one thing at a time and
reload in place — most changes apply with no restart and no dropped sessions. - Rebrand to OwlShack.
Web UI
- Overview / Peers / Map — live peer count and type spectrum, searchable
peer table, Leaflet map of geolocated peers with type filters and GPS
track visualization (altitude-colored). - Packets — live stream grouped by hash with a detail panel (route, hops,
signal, observation timeline, raw hex). - Trace — interactive path builder + result timeline.
- Companions → chat — channels and DMs per companion, with delivery status,
retry, and reply/quote affordances. - Contacts / Channels / Repeaters — per-companion management.
- Repeater Detail — login, status telemetry, CLI terminal with
autocomplete, neighbours, and a full settings panel (radio, position map
picker, advert intervals, routing, owner info, security/ACL).
Node monitoring
- Type-agnostic background poller writing time-series metrics + latest-snapshot
state, with per-node intervals, on-demand polls, and UI staleness indicators. - Telemetry decoding (battery, MCU temp, external sensors) gated by the remote
node's sharing prefs.
Contacts & peers (this release)
- Contacts are now self-contained address-book records — each caches its own
name, type, location, routing path, feature flags and last-seen, refreshed
from adverts and path learning. Deleting a discovered peer no longer touches a
saved contact. - Per-companion routing — DMs route from the contact's own learned path;
companions never share a route to a peer. - Discovered-peer deletion — individual and bulk, from the Peers and Map
pages. - Cross-linking + self-add prevention — every entity is reachable to its
detail view from anywhere it's shown; you can't add your own node as a contact.
MQTT observer
- Configurable broker presets (LetsMesh, Waev, MeshMapper, …), templated
packet/status topics, and per-broker auth (Ed25519 JWT or basic). - Fixes: UTC zone-aware timestamps in payloads; shutdown is panic-safe against
in-flight deliveries.
Other
- Room-server chat (login, post, ACK-gated push), repeater ACL surface, and
unified first-heard reception with a total-heard count. - CI guards
:latestand the GitHub release flag for pre-release tags.
Upgrade notes
- Config moves into the database. On first run, point the binary at your
existing config file once (-config path) to import it; after that the DB is
the source of truth and the file is no longer read. The legacy
nodeType/[[bot]]/[[observer]]format imports cleanly. - The schema is created/migrated automatically on startup.
Full changelog: v1.0.6...v1.1.0-alpha.1
v1.0.6
What's Changed
- Update bot configuration options and enhance README by @tuzzmaniandevil in #7
Full Changelog: v1.0.5...v1.0.6
v1.0.5
What's Changed
- Update meshcore-go to v1.0.5 and enable TxAirTime Estimator by @tuzzmaniandevil in #6
Full Changelog: v1.0.4...v1.0.5
v1.0.4
v1.0.3
What's Changed
- Improve Dockerfile and release workflow for build process by @tuzzmaniandevil in #4
Full Changelog: v1.0.2...v1.0.3