# meshing-around and the BBS bot for Meshtastic meshes

> meshing-around is a Python bot for Meshtastic mesh networks that answers text messages, runs games, posts mail between nodes, relays weather and emergency alerts, and monitors radio activity, all over the mesh's own messaging rather than any server. The interesting engineering is that the bot is a mesh citizen rather than a service, and the interesting constraint is that the richer features need an internet connection or a local model alongside the radio.

**SpudGunMan/meshing-around** — BBS Mesh Scripts for Meshtastic

- Repository: https://github.com/SpudGunMan/meshing-around
- Stars: 541 · Forks: 84
- Language: Python
- License: GPL-3.0
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/spudgunman-meshing-around

## A bot that lives on the mesh

The project describes itself as a feature-rich Python bot for Meshtastic, a mesh networking system, providing tools for network testing, messaging, games and more, all via text-based message delivery. The tag line is that whether you want to test your mesh, send messages or play games, the bot covers it.

What makes it different from a chat bot is the transport. A node in a Meshtastic mesh talks to other nodes over long-range radio, and the messages are short text packets delivered opportunistically. So a bot on the mesh is reachable by anyone within radio range, and its state is whatever the node it runs on can store.

The keyword responder is the simplest expression of that. It detects keywords like ping and replies with pong in direct messages or group channels, it can watch group channels for specific keywords and send custom responses, it watches for emergency-related keywords and alerts a wider audience, and it automatically welcomes new nodes joining the mesh.

The repository structure follows the feature list closely. There is mesh_bot.py as the main entry point and pong_bot.py as the minimal example, a modules/ directory holding the individual capabilities, a config.template that the container copies to config.ini, an install.sh, a launch.sh, a bootstrap.sh and an update.sh at the root, a compose.yaml and a Dockerfile, a Dockerfile-adjacent script/ directory, an etc/ directory, a data/ directory and a logs/ directory.

The primary language is Python, the licence is GPL-3.0, and the recent releases are 2.0.0.1 from 2026-10-17, v2.0.0.0 from 2026-09-02 and v1.9.9.9 from 2026-05-27. The last push was on 2026-10-17, and the version numbering itself is a tell, with the fourth component incrementing on every change rather than a semantic version.

The audience is an amateur radio operator or a community organiser running a Meshtastic node who wants the mesh to be useful to the people on it.

## Messaging on a network with no server in the middle

The messaging features are the part that reveals what a mesh makes possible, because several of them are things a client-server chat system cannot do.

Mail messaging lets a user leave a message for another device, and it is delivered as a direct message when that device is next seen. The commands are given in the form bbspost @nodeNumber #message and bbspost @nodeShortName #message, so you address a node either by its numeric identifier or by its short name. The store and forward feature retrieves missed messages with the messages command and can optionally log them to disk.

BBS linking connects multiple bots to expand coverage, which is the mesh equivalent of a distributed message bus. The E-Mail/SMS integration sends mesh messages to email or SMS for broader reach, which is the escape hatch for when the mesh's range is not enough.

A message scheduler automates messages such as weather updates or net reminders, and the multi-radio support means the bot can observe up to nine networks at once and send mail and messages between them.

The proximity alert system is the feature that turns a messaging bot into a location system. You configure a latitude and longitude and get notified when members arrive, with the option to trigger scripts, send emails, or automate actions such as changing node config, turning on lights, or dropping an alert.txt file to start a survey or game. The alert cycle is adjustable, which the documentation points out makes it usable for creative applications like a king of the hill or geocache game. There is also a high flying alert for nodes detected at high altitude, and voice or command triggers, with a Hey Chirpy! example of the wake phrase.

The asset tracking and check-in/check-out system is a step further into operations. It handles accountability, safety monitoring and logistics for people and equipment, with admin approval workflows, GPS location capture and overdue alerts, and it includes an integrated inventory and point-of-sale system for item management, sales tracking, cart-based transactions and daily reporting, aimed at swaps, emergency supply management and field operations.

## Radio monitoring and the decoding features

The features that reach beyond messaging all share one dependency: a radio and something to decode with.

Radio frequency monitoring alerts on high SNR activity, that is, signal-to-noise ratio, detected on the mesh. Hamlib integration uses rigctld to monitor the S meter on a connected radio. Speech-to-text broadcasting converts received audio to text using Vosk and broadcasts it to the mesh. WSJT-X integration monitors FT8, FT4 and WSPR decode messages and forwards them to the mesh network with optional callsign filtering, and JS8Call integration does the same for JS8Call messages.

That pattern of optional callsign filtering appears twice and it is the right design for it. A mesh in a region with several amateur operators will hear traffic from all of them, and forwarding all of it makes the mesh unusable as a conversation channel. Filtering by callsign turns a firehose into a feed.

The bot can also speak. Meshages TTS reads mesh messages aloud using KittenTTS, enabled so that important alerts and messages are read out loud on the device, which the documentation frames as ideal for hands-free operation or accessibility. There is also an offline Tone Out decoder for fire Tone Out and DTMF, and YOLOv5 alerts that use camera modules to detect objects or run OCR.

The file monitor features are the ones to think about carefully. The bot can watch a text file for changes and broadcast updates to the mesh channel, and it can retrieve the contents of a news file on request, supporting multiple news sources or files. It can also execute shell commands via direct message, with replay protection, admin only.

That last one is a remote command execution feature on a radio network, and it is the single most important thing to configure deliberately. The documentation marks it admin only and mentions replay protection, which is a mitigation, but the sensible reading is that the admin credential and the direct message channel deserve the same care as a root shell, because that is effectively what it is.

## Data lookups, LLM integration and the internet dependency

The lookup and AI features are the ones that need a network beyond the mesh, and it is worth being precise about which ones.

Weather, earthquake, river and tide data come from NOAA and USGS, with Open-Meteo used for areas outside NOAA coverage. Wikipedia search pulls summaries from Wikipedia and Kiwix. Satellite passes find upcoming passes for your location. RSS and news feeds deliver news and data from multiple sources directly on the mesh.

The AI piece is the most interesting. The bot can query the Ollama model for advanced responses, with support for RAG, retrieval augmented generation, using Wikipedia and Kiwix as context, and OpenWebUI integration for enhanced capabilities. The point of the RAG support is that the context comes from the same offline data sources, which is what makes an answer useful on a mesh with no internet.

The compose file shows how that dependency is wired. The bot service carries OLLAMA_API_URL pointing at the Ollama container, and both sit on a shared meshing-around-network. The Ollama service publishes 11434 and has a healthcheck that curls the tags endpoint every thirty seconds.

So the architecture is a hybrid, and the split is visible in the container set. The bot itself, the test bot and the debug console run the project image. A meshtasticd service runs the Meshtastic daemon and publishes 4403 for the Meshtastic TCP API, along with 443. The Ollama service is the local model server. None of that is needed for the mesh-native features.

The emergency alert features span that boundary in both directions. You can receive FEMA iPAWS and EAS alerts through an API on internet-connected nodes, NOAA EAS alerts the same way, and USGS volcano alerts. The Bund-Warnmeldung feed does the same for Germany. And the offline EAS alerts feature reports alerts over the mesh using external tools, even without internet, which is the point of running a mesh at all.

## Running it: the compose stack and the container image

The compose file is the clearest picture of the whole system, and it starts with the bot service:

```yaml
services:
  meshing-around:
    ports:
      - 8420:8420
    container_name: meshing-around
    restart: unless-stopped
    environment:
      - OLLAMA_API_URL=http://ollama:11434
```

The bot publishes 8420, which the Dockerfile comments identify as the Meshing Around web dashboard port, and the image is published as ghcr.io/spudgunman/meshing-around:main. There are commented-out device mappings for a serial radio at /dev/ttyUSB0 or /dev/ttyACM0, with the note to update config.ini to point at the right port, and commented-out user lines for running as a non-root uid.

The extra_hosts entry maps host.docker.internal to host-gateway, which is what lets the container reach services running on the host, including a radio attached to it.

The Dockerfile is where the Python version and the packaging decisions become concrete. It is built on python:3.14-slim with unbuffered output, an en_US.UTF-8 locale and the America/Los_Angeles timezone, and it installs build-essential, python3-dev, gettext, tzdata, locales and nano. The locale generation step matters more than it looks, because a bot whose output includes accented characters will produce mojibake in a container with the C locale, and the compose file sets the same locale variables on the service.

Dependencies are installed first for better caching:

```dockerfile
RUN pip install --no-cache-dir -r /app/requirements.txt
```

and the config template is copied to config.ini as part of the image build, which is why config.template sits at the repository root and why the container expects a config.ini to exist. The entrypoint is a shell script rather than a Python module, and the non-root user lines are present but commented out, so the container currently runs as root by default.

The Python dependency list itself is short and tells you what the core does: the meshtastic library for the radio protocol, PyPubSub for the event system, ephem for orbital calculations, requests for the HTTP calls, maidenhead for the locator maths, beautifulsoup4 for HTML parsing, dadjokes for the joke command, geopy for distance and midpoint calculations, and schedule for the message scheduler.

## Games, tests and the limits of a mesh bot

The fun half of the project is not incidental. There are built-in games playable directly by direct message, including DopeWars, Lemonade Stand, BlackJack and Video Poker, and a command-based gameplay mode where the games command lists what is available and starts a session. There is also an FCC ARRL QuizBot for practising the ham radio exam, and a telemetry leaderboard.

A mesh with games on it is a different proposition from a mesh with a ping responder on it. The games need multiple people and a shared session, which is exactly the shape of a radio network where not everyone is in range of everyone else.

The testing story is also unusually complete for a hobby project. The compose file defines a test-bot service that runs modules/test_bot.py, tees the output to a temporary file, and copies the result to /app/test_results.txt if the output contains a failures or errors marker, so a CI run can pick the result up. A debug-console service gives an interactive shell into the same image, with stdin and a tty enabled. There is a GitHub Actions code scanning badge for CodeQL, and a SECURITY.md at the root.

The real limits come from the medium. A Meshtastic packet is short, the delivery is opportunistic, and the topology is a mesh rather than a star, so anything the bot does has to be expressible in a few lines of text and safe to repeat. That rules out a lot of what a server-based assistant does well, and it is why the features here are mostly small, discrete and tolerant of failure.

The second limit is the dependency on external services for the parts that are not mesh-native. A node in a field with no internet still gets the emergency alerts and the games and the store and forward, which is the resilient subset. The Wikipedia, weather, satellite and LLM features are conveniences layered on top of a connectivity assumption.

The third is the remote command execution surface. It is admin only and has replay protection, which is a reasonable starting position, but on a radio network the reachability of the bot is not limited by network topology, so the configuration of that one feature carries more weight than its position in the feature list suggests.

## Conclusion

meshing-around is a good fit for a Meshtastic operator who wants a shared text service on the mesh itself, because the bot talks to nodes over the mesh protocol with no central server, and the mail, store and forward, games and keyword responder work on a local radio link alone. It is a poor fit if you expect a general-purpose assistant, since the LLM, Wikipedia, weather and satellite features all depend on an internet connection or a local Ollama instance, and a poor fit for a security-sensitive deployment because the bot accepts shell commands over direct message with admin-only replay protection. Before deploying, read the config.template and the modules README, and decide which internet-backed modules you enable, because the OLLAMA_API_URL variable in the compose file points at a model server that the bot expects to find.

## FAQ

### What is meshing-around?

It is a Python bot for Meshtastic mesh networks that delivers its features as text messages, covering network testing, mail between nodes, store and forward, games, proximity alerts, radio monitoring and data lookups.

### How does the mesh mail feature work?

You leave a message for another device with bbspost @nodeNumber #message or bbspost @nodeShortName #message, and it is delivered as a direct message when that device is next seen. The messages command retrieves missed messages, with optional logging to disk.

### Which features need an internet connection?

The weather, earthquake, river and tide data, Wikipedia search, satellite passes, RSS and news feeds, the FEMA and NOAA and USGS alert feeds, and the Ollama LLM integration all reach outside the mesh. The emergency alert reporting over the mesh, the games, the mail and the store and forward features work locally.

### What Python libraries does the bot depend on?

The requirements list is meshtastic, PyPubSub, ephem, requests, maidenhead, beautifulsoup4, dadjokes, geopy and schedule. The container image is built on python:3.14-slim and installs them with pip from a copied requirements.txt.

### How is the bot tested?

The compose file defines a test-bot service that runs modules/test_bot.py, tees the output to a temporary file and copies it to /app/test_results.txt when the output contains a failures or errors marker, so a CI run can collect the result. There is also a debug-console service giving an interactive shell in the same image.

### Can the bot run shell commands remotely?

Yes, shell command access via direct message is a documented feature, marked as admin only and with replay protection. There is also a file monitor that broadcasts text file changes to the mesh channel, and a news file feature that returns file contents on request.

## Sources

- [Issues](https://github.com/SpudGunMan/meshing-around/issues)
- [License: GPL-3.0](https://github.com/SpudGunMan/meshing-around/blob/main/LICENSE)
- [README](https://github.com/SpudGunMan/meshing-around/blob/main/README.md)
- [Releases](https://github.com/SpudGunMan/meshing-around/releases)
- [SpudGunMan/meshing-around on GitHub](https://github.com/SpudGunMan/meshing-around)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/spudgunman-meshing-around
