Model or dataset
markqvist/LXMF avatar
markqvist/LXMF

LXMF: a small encrypted message format for Reticulum

A universal, distributed and secure messaging protocol for Reticulum

801 stars76 forksPythonNOASSERTION

At a glance

What is it?
LXMF is a messaging format and delivery protocol that sits on top of Reticulum, where a message is a destination hash, a source hash, an Ed25519 signature and a msgpack payload, which is small enough to travel over LoRa or as a printed QR code. The licence is a custom Reticulum License rather than an OSI one, and the README opens with a warning about lookalike projects.
Who is it for?
Adopt LXMF if you are building on the Reticulum network and want a message format that is small, signed and works over radio links, LoRa or printed QR codes. Do not adopt it if you need a licence your organisation already recognises, because the project uses a custom Reticulum License rather than a standard OSI licence.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 23 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A message format built to be small

LXMF stands for Lightweight Extensible Message Format, and the README describes it as a simple and flexible messaging format and delivery protocol that allows a wide variety of implementations while using as little bandwidth as possible.

It is built on top of Reticulum, and it offers zero-conf message routing, end-to-end encryption and Forward Secrecy, and it can be transported over any kind of medium that Reticulum supports. The practical claim follows from that: it is efficient enough to deliver messages over extremely low-bandwidth systems such as packet radio or LoRa, and encrypted LXMF messages can also be encoded as QR codes or text-based URIs, which allows completely analog paper message transport.

That last capability is unusual enough to be worth understanding. A message that fits in a QR code can be printed, carried and scanned, and the receiving end decrypts it. For a mesh network where some nodes are reachable only by radio, or where the point is to exchange something with no network at all, that is the whole use case.

The audience is therefore Reticulum developers rather than general application developers. The README lists the user-facing clients built on LXMF, which include Sideband, MeshChatX, Nomad Network and Columba, and then a separate set of community tools, among them LXMFy, LXMF-Bot, an LXMF messageboard, LXMEvent, RangeMap and LXMF Tools.

The primary language is Python, and the repository is a small package with a LICENSE file, a Makefile, a Dockerfile, a setup.py and the LXMF package directory itself.

One more thing has to be said up front, because the README puts it first. It carries a warning that several hastily launched, incorrect and in most cases entirely LLM-generated fakes of LXMF and associated tools are being circulated and marketed, that most of these projects violate the open source licence LXMF was published under while claiming independent ownership and licence grants, that such claims are not legally valid and are not recognized by the LXMF authors and copyright holders, and that the downstream users of such infringing derivatives are directly and personally liable. The README links to a chapter of the Reticulum Manual on void grants of licence for machine-generated code. It is an unusual thing to find at the top of a README, and it tells you something about how the project holders view the current state of the ecosystem.

The message structure, field by field

The format section is the specification, and it is short enough to read in full.

A message is stored in a simple and efficient format that is easy to parse and write, and it follows a general structure: a Destination, a Source, an Ed25519 Signature and a Payload. The Payload in turn contains a Timestamp, Content, Title and Fields.

Four rules govern it. A message is identified by its message-id, which is a SHA-256 hash of the Destination, Source and Payload, and the message-id is never included directly in the message since it can always be inferred from the message itself. The Destination, Source, Signature and Payload parts are mandatory, as is the Timestamp part of the payload. The Content, Title and Fields parts must be present in the structure but can be left empty. The Fields part can be left empty, or contain a dictionary of any structure or depth.

The field types are specified. Destination and Source are 16-byte Reticulum destination hashes. The Signature is a 64-byte Ed25519 signature of the Destination, Source, Payload and message-id, so the message-id is covered by the signature. The Payload is a msgpack list of four items, where the Timestamp is a double-precision floating point number of seconds since the UNIX epoch, the Content is the optional body, the Title is the optional title, and the Fields is the optional dictionary.

There is one exception to the message-id rule, and it is the interesting case. In some situations the actual message-id cannot be inferred, for example when a Propagation Node is storing an encrypted message for an offline user. In those cases a transient-id is used to identify the message while it is in storage or in transit. The distinction matters for anyone implementing a store, because the identifier you key on changes depending on where the message is.

The empty-fields rule is what makes the format extensible. Because Fields is a dictionary of any structure or depth, a protocol built on LXMF does not need a new message type, it needs a new key. The usage examples in the README make the range explicit: a short messaging system like SMS uses only the Content field with everything else empty, an email-like system uses Title and Content for subject and body with Fields optionally carrying attachments or other metadata, machine control and sensor readings embed command structures in the Fields dictionary, and distributed discussion or newsgroup systems, along with broadcast bulletins, use the relevant fields together with LXMF Propagation Nodes.

Propagation nodes and the router

Two pieces of infrastructure carry the delivery model, and they are described in separate sections.

LXM Propagation Nodes offer a way to store and forward messages to users or endpoints that are not directly reachable at the time of message emission, and they can also provide infrastructure for distributed bulletin, news or discussion boards. When Propagation Nodes exist on a Reticulum network, they will by default peer with each other and synchronise messages, automatically creating an encrypted, distributed message store, and users and other endpoints can retrieve messages destined for them from any available Propagation Node on the network.

That is the difference between a direct-delivery protocol and a store-and-forward one, and it has a security consequence worth naming. A message that reaches a Propagation Node is stored there, and the node synchronises with its peers, which means the message exists in several places rather than travelling on one path from sender to recipient. The README describes the store as encrypted, and the transport encryption is provided by Reticulum, but a store that persists messages for offline recipients is a different exposure profile from a protocol where a message exists only in transit.

The LXM Router is the other half. It handles transporting messages over a Reticulum network, manages delivery receipts, outbound and inbound queues, and is the point of API interaction for client programs. It also implements the functionality for acting as an LXMF Propagation Node, so a single daemon can serve both roles.

Programmatically, sending a message through the router is four lines:

python
import LXMF

lxm_router = LXMF.LXMRouter()

message = LXMF.LXMessage(destination, source, "This is a short, simple message.")

lxm_router.handle_outbound(message)

The router then handles the heavy lifting, such as message packing, encryption, delivery confirmation, path lookup, routing, retries and failure notifications. The split is sensible. The client constructs a message with a destination, a source and content, and everything that requires knowing about the network, the links, the retries and the receipts stays in the router, which is the component that has to survive a network where nodes come and go.

The repository also ships a console entry point, lxmd, registered in setup.py as LXMF.Utilities.lxmd:main, so the daemon is a supported way to run the router rather than something you write yourself.

Encryption comes from the layer below

LXMF uses encryption provided by Reticulum, and thus uses end-to-end encryption by default. The delivery method of a message influences which transport encryption scheme is used.

The first case is the default one. If a message is delivered over a Reticulum link, the message is encrypted with ephemeral AES-128 keys derived with ECDH on Curve25519, and this mode offers forward secrecy. The important word in that sentence is ephemeral: the key is derived for that link and then discarded, so a later compromise of a long-term key does not expose the message contents that were sent earlier.

The alternatives depend on the transport. A message that travels over a different kind of medium, such as one of the low bandwidth or analog ones, uses a different scheme, because the constraint is what the medium can carry. The README section on transport encryption is cut off in the documentation available here, so the specific mapping for the non-link cases is something to read in the full text rather than infer.

What the layering buys you is that the message format stays the same regardless of transport. The Destination and Source hashes, the signature and the msgpack payload are identical whether the message went over a TCP link, a LoRa radio hop or a printed QR code. That is what makes a paper message possible, and it is why the format is called extensible rather than just small.

The security properties you can rely on from the specification are these: the payload is covered by an Ed25519 signature over the destination, source, payload and message-id, so a middlebox cannot alter a message without invalidating it, and the message-id is a hash of the same parts, so it is verifiable rather than asserted. What you cannot infer is the delivery guarantee, because LXMF is a store-and-forward protocol over an intermittently connected network and the timing of delivery is not under the sender's control.

Installing, licensing and the state of the project

The package is called lxmf on PyPI, with setup.py declaring the name, the author Mark Qvist, the description Lightweight Extensible Message Format for Reticulum, the packages LXMF and LXMF.Utilities, a Python requirement of 3.7 or newer, and an install_requires of rns at 1.5.5 or newer. The requirements.txt file lists qrcode at 7.4.2 or newer and rns at 1.0.0 or newer, and the qrcode dependency is the hint about the printed paper message feature.

The licence is the thing to read first. The setup.py declares license as Reticulum License with the LICENSE file as the licence file, and the repository licence is recorded as a custom one that GitHub cannot categorize. This is not an OSI licence, and for an organisation whose legal process expects MIT or Apache, that is a procurement conversation rather than a technical detail. The README links to a chapter of the Reticulum Manual on licence terms, and there is a Zen of Reticulum document in the repository root alongside a FUNDING.yml and a MIRROR.md, which tells you the project treats the licensing question as central rather than incidental.

The build is a Makefile with a release target that removes symlinks, builds a wheel and a source distribution, then restores the symlinks. The upload target is the notable one: it publishes the release over Reticulum itself, using rngit release with an rns:// address, which is a self-hosted package distribution mechanism rather than PyPI. A separate upload-pip target pushes to PyPI with twine.

There is a Dockerfile for the packaging, based on python:alpine, which installs the system libraries needed for Reticulum, creates a non-root user, sets up a virtualenv and runs make all. There is also a Dockerfile.howto in the root, which is presumably the guide to building it yourself.

On maintenance, the repository is not archived and the last push was on 2026-09-30, with release 1.2.0 dated the same day. Before that the listed releases are 0.9.6 and 0.9.5, both marked as beta in April 2026, so the jump to 1.2.0 is recent and the 0.9.x line was still marked beta, which suggests the project spent a while stabilising before declaring 1.x.

One practical note for anyone planning a deployment: the protocol is stable enough for a 1.0 and the client ecosystem is real, but the licence is unusual and the reference to LLM generated fakes in the README tells you the project has been actively fighting for control of its own ecosystem. Both of those matter more than the feature list when you are choosing a dependency.

Editorial conclusion

Adopt LXMF if you are building on the Reticulum network and want a message format that is small, signed and works over radio links, LoRa or printed QR codes. Do not adopt it if you need a licence your organisation already recognises, because the project uses a custom Reticulum License rather than a standard OSI licence. Verify first that the Reticulum stack you are running is compatible with this release, that the lxmd daemon matches the library version, and that you understand the message delivery model, since a Propagation Node store and forward changes the privacy properties compared with direct delivery.

Frequently asked questions

What is LXMF?

It is the Lightweight Extensible Message Format, a simple and flexible messaging format and delivery protocol built on top of Reticulum. It offers zero-conf message routing, end-to-end encryption and forward secrecy, and can travel over any medium Reticulum supports, including packet radio, LoRa and printed QR codes.

What is in an LXMF message?

A Destination, a Source, an Ed25519 Signature and a Payload, where the Payload is a msgpack list of a Timestamp, an optional Content, an optional Title and an optional Fields dictionary. Destination and Source are 16-byte Reticulum destination hashes, and the signature is 64 bytes over the destination, source, payload and message-id.

What do LXMF Propagation Nodes do?

They store and forward messages for users or endpoints that are not directly reachable at the time of sending, and they can carry bulletin or discussion board infrastructure. By default they peer with each other and synchronise messages, which creates an encrypted distributed message store users can retrieve from.

How do I send a message with the LXM Router?

Create an LXMF.LXMRouter, construct an LXMF.LXMessage with a destination, source and content, and pass it to handle_outbound. The router then handles message packing, encryption, delivery confirmation, path lookup, routing, retries and failure notifications.

What license is LXMF released under?

The Reticulum License, a custom licence declared in setup.py with the LICENSE file in the repository root, rather than a standard OSI licence. The README also warns about LLM-generated lookalike projects claiming their own ownership and licence grants, which it says are void.

Official sources

  1. Issues
  2. markqvist/LXMF on GitHub
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/markqvist-lxmf.svg)](https://hysenlabs.com/projects/markqvist-lxmf)

Was this useful?