# Reticulum MeshChat: a chat client that reaches you over LoRa, and the announce you must send

> MeshChat is an Electron and Python client for the Reticulum Network Stack that sends messages, files and audio calls to peers over any interface the stack supports, from Ethernet and WiFi to ISM band LoRa radio. It also speaks LXMF, so it can talk to Sideband and Nomadnet, and its first-run flow makes one thing non optional, you must send an announce or you are invisible.

**liamcottle/reticulum-meshchat** — A simple mesh network communications app powered by the Reticulum Network Stack.

- Repository: https://github.com/liamcottle/reticulum-meshchat
- Website: https://meshchat.app
- Stars: 1,310 · Forks: 169
- Language: JavaScript
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/liamcottle-reticulum-meshchat

## What the app does, and the four ways it can reach a peer

Reticulum MeshChat is a simple mesh network communications app powered by the Reticulum Network Stack, and the project homepage is meshchat.app.

The core capability list is short. It can send and receive messages, files and audio calls with peers, and it communicates securely, with the property that messages can only be decrypted by the intended destination.

What makes it interesting is the list of transports, and there are four. Over the local network through Ethernet and WiFi, completely automatically. Over the internet by connecting through a server hosted by yourself or by the community. Over low powered, license free, ISM band LoRa radio, with an RNode. And via any other interface supported by the Reticulum Network Stack.

The LoRa option is the one that changes the character of the application. An RNode is a firmware project that turns a LoRa radio into a Reticulum interface, and the topic tags list lora, rnode, radio, offgrid and mesh alongside the software ones. This is a tool for talking where there is no network, and the fact that the same app runs on Ethernet and on a LoRa radio link is the point rather than a gimmick. The author notes that two-way audio calls over LoRa with a single hop work well when a reasonable bitrate is configured on the RNode.

The interop story is the other half of the value. MeshChat can communicate with any other existing LXMF client, such as Sideband and Nomadnet, and it can download files and browse micron pages, the decentralised websites, hosted on Nomad Network nodes. The topics list lxmf, nomadnet, sideband, meshchat, webchat, p2p, encryption, x25519 and ed25519, which is a fair summary of the stack underneath.

The licence is MIT, the primary language is JavaScript, and the recent releases are v2.4.0 on 2026-07-06, v2.3.0 on 2025-11-11 and v2.2.1 on 2025-07-27. The repository is not archived with the last push on 2026-10-06.

## Identities, announces, and why an unsent announce means you are invisible

The getting started section is a five step list, and two of the steps are about identity and reachability rather than about sending messages.

Step one is create an Identity. On the Reticulum Network anyone can have any number of identities, and you may opt to use your real name or decide to be completely anonymous. A Reticulum identity is a public and private key pair, and the private key is what you use to generate destination addresses, to encrypt content, and to prove receipt of data with unforgeable delivery acknowledgements. Your public key is shared with the network when you send an announce, and it is what allows others to automatically discover a route to a destination you control.

The current limitation is stated plainly. Reticulum MeshChat generates a new identity the first time you launch it, and a future update will allow you to create and manage multiple identities. For now, if you want to change or reset your identity, you access the identity file at ~/.reticulum-meshchat/identity.

Step two is configure your display name, which is what everyone else sees when looking for someone in the peers list, set in the My Identity section in the bottom left corner, and saved with the Save button.

Step three is send an announce, and the explanation of why is the part that matters. In order to be contactable you need to send an announce, and you can send one as often or as infrequently as you like. Sending it allows other peers on the network to discover the next hop across the network their packets should take to arrive at a destination your identity controls.

Then the consequence, stated bluntly: if you never send an announce, you will be invisible and no one will ever be able to send anything to you.

The mechanics of moving are described too, and this is the part that trips people up. When you move across the network and change entrypoints, such as moving from your home WiFi network to plugging into an Ethernet port in a local library, or climbing a mountain and using an RNode over LoRa radio, other peers on the network will only know the previous path to your destinations. To let them discover the new path, you have to send another announce.

So a mesh client that is meant to be portable is not portable in the sense of just working. Its location on the network is a piece of state that has to be refreshed by hand, and a node that has changed networks silently becomes unreachable, which on a LoRa link in the field is the difference between a working radio and an expensive brick.

## The feature list, and what propagation nodes mean for you

The features list is where the interoperability and the reliability work shows up, and two items deserve more attention than the rest.

The first is auto resending undelivered messages when an announce is received from the recipient. That is a small feature with a large meaning. Because a message that could not be delivered is held and retried the moment the network tells the client a route to the destination exists, the announce becomes a trigger for delivery, not just for discovery. It is the mechanism that makes messaging over a slow, intermittent link work at all.

The second is the propagation node support, in both directions. You can send messages to and sync messages from LXMF propagation nodes, and you can run a local LXMF propagation node so other users can use your device for message storage and retrieval.

Running a propagation node is the feature that most affects a user's obligations to others. A propagation node stores messages for destinations it cannot reach directly and hands them over when those destinations next appear. If you run one, you are holding other people's messages on your own hardware, and the stored data is theirs. That is a reasonable thing to do for a community, and it is also a reason to think about what you are agreeing to store and for how long, particularly on a shared or portable device.

The rest of the list covers the everyday surface. Sending and receiving messages between MeshChat, Sideband and Nomadnet. Receiving and saving images and attachments sent from Sideband. Sending images, voice recordings and file attachments. Saving inbound and outbound messages to a local database. Setting a custom display name to send in your announce. Viewing and searching peers discovered from announces. And browsing pages and downloading files hosted on Nomad Network nodes.

The beta section is where the author is most candid, and it is about audio calls. Audio is encoded with codec2 to support low bandwidth links, which is the right codec choice for the medium, since it is designed to work at very low bitrates at the cost of fidelity. Using a microphone requires the web UI over localhost or https, because AudioWorklet requires a secure context. And the author says plainly that some browsers such as Firefox do not work as expected, and suggests trying a Chromium based browser if running via the command line.

That last point is a real limitation for a desktop app that is nominally cross platform, since the app itself is Electron, which is Chromium. The browser caveat applies to the web interface path rather than to the packaged app, but it is worth knowing if you plan to run the web UI directly.

## The two build systems: Vite and Electron for the shell, cx_Freeze for the server

The repository contains two applications built two different ways, and the package.json scripts show it clearly.

The frontend is Vite. The build-frontend script is vite build, and there is a watch variant that passes --watch through. The backend is Python, and build-backend is python setup.py build, with the full build being the two in sequence.

The Python side is packaged with cx_Freeze, and the setup.py shows how carefully that is configured. The Executable runs meshchat.py as a console application rather than a GUI, targeting ReticulumMeshChat.exe with the matching shortcut name and a ProgramMenuFolder shortcut directory on Windows and the icon at logo/icon.ico.

Two options in the cx_Freeze configuration are worth reading because they explain real problems. The packages list includes RNS, with a comment that it is required for a dynamic import fix and a link to the cx_Freeze discussions and issues about it. And the excludes list contains PIL, with the comment that it saves around 200MB, which tells you the Pillow dependency is pulled in transitively and is not actually needed.

The optimize setting is 2, and the comment explains the three effects, that it has the same effect as the -O command line option, that it prevents assert statements from executing, and that it removes docstrings and sets __debug__ to False.

The Electron configuration in package.json is the desktop shell. The appId is com.liamcottle.reticulummeshchat, the product name is Reticulum MeshChat, asar is set to false so the packaged output is not inside an archive, and the files list is the whole electron directory with the build resources in electron/build. The extraFiles entry copies the frozen Python build into the app's Resources directory as Resources/app/electron/build/exe, which is how the Electron front end finds the Python backend it launches.

The macOS configuration has identity set to null, which is what produces an unsigned build, and it declares the microphone entitlements explicitly, with NSMicrophoneUsageDescription set to Microphone access is only needed for Audio Calls and com.apple.security.device.audio-input set to true. That is the macOS equivalent of the AudioWorklet secure context requirement, handled at the packaging layer.

The Windows targets are portable and nsis, with an artefact name of ReticulumMeshChat-v${version}-${os}.${ext}, and the mac artefact name includes the arch, ReticulumMeshChat-v${version}-${os}-${arch}.${ext}. The engines field requires Node 18 or newer, and the only dev dependencies are electron and electron-builder.

## Running it elsewhere: Docker, Raspberry Pi and Termux

Beyond the downloaded Windows, Mac and Linux builds, the repository ships three other deployment routes as documentation, and the Docker one is the most complete.

The docker-compose file pulls the published image and runs it with a persistent volume:

```yaml
services:
  reticulum-meshchat:
    container_name: reticulum-meshchat
    image: ghcr.io/liamcottle/reticulum-meshchat:latest
    pull_policy: always
    restart: unless-stopped
    # Make the meshchat web interface accessible from the host on port 8000
    ports:
      - 0.0.0.0:8000:8000
    volumes:
      - meshchat-config:/config
    # Uncomment if you have a USB device connected, such as an RNode
    # devices:
    #   - /dev/ttyUSB0:/dev/ttyUSB0

volumes:
    meshchat-config:
```

The commented devices section is the detail that matters for anyone actually planning to use LoRa. A RNode is a USB device, so the container needs the serial device passed in, and the commented mapping of /dev/ttyUSB0 is the line you uncomment. Without it the container runs fine and simply has no radio. The named volume meshchat-config keeps the identity file and the message database across container restarts, which is the difference between a persistent identity and losing your identity every time you redeploy.

The other two routes are documented separately. There is a guide for running MeshChat on a Raspberry Pi, and one for running it on Android with Termux. The Termux route is the interesting one because it puts the whole thing on a phone, which is a natural pairing with a portable RNode, and it is also the closest thing to a purely off-grid setup where the only network is the radio link itself.

The Python dependencies behind all of this are in requirements.txt and they are minimal and readable. aiohttp for the web server, cx_freeze for the packaging, lxmf for the messaging protocol, peewee for the database, rns for the Reticulum stack itself, and websockets for the real time channel.

Peewee is the notable one, because it is a small, deliberately simple ORM, and it is a good match for an app whose data model is a message table and a peer table. And the repository has a database.py at the top level, so the schema is one file you can read.

The overall picture is a two part application: a Python backend that speaks Reticulum and serves the web interface, and a Vite built front end that Electron wraps for the desktop build. The Docker image runs the web interface on port 8000, the desktop app runs the same backend locally, and the requirement that the microphone only works over localhost or https is a consequence of that split, since the web interface in the browser and the web interface in the Electron app are the same code.

## Conclusion

MeshChat fits a user with a Reticulum node, whether that is a laptop on a normal network or a handheld with an RNode on LoRa, who wants a chat client that works whether or not the internet is there. It is the wrong tool if you want a hosted chat service, since there is no server to sign up for unless you run one yourself, and it is the wrong tool if you need a mature, audited client, since the audio call feature is explicitly beta and the author notes that some browsers do not behave as expected. Before deploying, send an announce and confirm you can be discovered, set a display name before you expect anyone to find you, and if you intend to run a propagation node, remember that you are then storing other people's messages on your own device.

## FAQ

### What is Reticulum MeshChat and what can it do?

It is a mesh network communications app powered by the Reticulum Network Stack. It sends and receives messages, files and audio calls with peers over local Ethernet and WiFi, over the internet through a self hosted or community server, over low powered license free ISM band LoRa radio with an RNode, or via any other interface the stack supports.

### Why can nobody message me until I send an announce?

Sending an announce lets other peers discover the next hop their packets should take to reach a destination your identity controls. If you never send one you are invisible and no one can send you anything, and when you change networks, such as moving from WiFi to an RNode on LoRa, peers only know the previous path until you announce again.

### Can MeshChat talk to other messaging clients?

Yes. It supports sending and receiving messages between Reticulum MeshChat, Sideband and Nomadnet, since they all speak LXMF. It can also receive and save images and attachments sent from Sideband, and browse and download files hosted on Nomad Network nodes.

### What are the limits of the audio call feature?

It is listed as a beta feature. Audio is encoded with codec2 for low bandwidth links, using a microphone requires the web interface over localhost or https because AudioWorklet needs a secure context, and the author notes that some browsers such as Firefox do not work as expected, so a Chromium based browser is suggested when running from the command line.

## Sources

- [liamcottle/reticulum-meshchat on GitHub](https://github.com/liamcottle/reticulum-meshchat)
- [License: MIT](https://github.com/liamcottle/reticulum-meshchat/blob/master/LICENSE)
- [Project website](https://meshchat.app)
- [README](https://github.com/liamcottle/reticulum-meshchat/blob/master/README.md)
- [Releases](https://github.com/liamcottle/reticulum-meshchat/releases)

---

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