DAPPS (Distributed Asynchronous Packet Pub/Sub) is a store-and-forward messaging layer for packet radio networks. Applications send messages to app@CALLSIGN, and DAPPS finds a path, forwards, fragments, retries and acknowledges, and delivers when it can. Real-time connectivity is not a goal. Think of it as packet mail for application developers, with delivery guarantees and a modern interface. There is a project page at /projects/dapps/ and the code is at packet-net/dapps.

Why it exists

Anything that wants to move data across a network of nodes, with links coming and going, has to build queues, retries and deduplication. I wanted that done once, below the application, so that someone writing an app only has to publish a message and subscribe to replies.

I RFC’d the idea on OARC, wrote a first protocol and started a C# implementation, then left it alone for a long time. The last commit before the pause was in July 2025. I picked it up again in spring 2026, and the protocol has been pinned at v1 since.

What it does

A DAPPS node is a daemon that runs alongside your packet node. It connects to LinBPQ over AGW, to XRouter over RHPv2, or to a MeshCore radio. Other DAPPS nodes are reached through that same packet node, hop by hop, with a TTL.

Local applications talk to the daemon over MQTT or REST. They publish to app@CALLSIGN and subscribe to what arrives for them. DAPPS handles fragmenting, retries, acks, and discovery of neighbouring DAPPS nodes. Delivery is at-least-once, with duplicates removed using content-addressed message IDs. Ordering is an option, not a guarantee.

It has a web dashboard for the operator, with recent decisions, settings, and a notice when a new version is out. Every transmission is recorded in an audit log with the reason for it.

Installing it

On Debian, Ubuntu and Raspberry Pi OS it is installed from the packet-net apt repository (amd64, arm64 and armhf):

curl -fsSL https://packet-net.github.io/apt/pubkey.asc | sudo gpg --dearmor -o /usr/share/keyrings/packet-net.gpg
echo "deb [signed-by=/usr/share/keyrings/packet-net.gpg] https://packet-net.github.io/apt ./" | sudo tee /etc/apt/sources.list.d/packet-net.list
sudo apt update && sudo apt install dapps

Then open http://<host>:5000/ and the setup wizard walks through the rest. It does not update itself: you upgrade it with apt, and the dashboard tells you when there is something new. Other platforms are covered in the manual, which also has a section for app developers with a hello-world tutorial and a full reference.

Where it stands

It is running on a few real nodes now, and the latest release is v0.58.1. Since the first draft of this post most of the work has been on things that only show up on real networks. One example: LinBPQ resends a split NET/ROM frame 20 bytes short, which stalled DAPPS messages for three minutes. DAPPS now writes at most 236 bytes at a time so LinBPQ never has to split them, and the bug is logged against my LinBPQ fork.

Routing across a whole network is not solved, and I’m deliberately not pretending it is. Nodes discover their neighbours and can pass on route hints, but how a message should find its way across a large, patchy network needs proper design, and I’d rather get that right than add a quick fix. Feedback from the people running it is what I’m waiting on.

Things I built to test it

DAPPS has to be tested against real packet nodes, repeatedly, on clean machines. Most packet software assumes a sysop with a Pi, so I ended up building some supporting pieces. They are useful for testing other software too.

LinBPQ container

M0LTE/linbpq is my fork of John G8BPQ’s LinBPQ. It builds a small Debian-based Docker image, published to Docker Hub as m0lte/linbpq (amd64 only for now). The fork also carries some fixes that aren’t upstream yet. It is not the official source and John is the authority on LinBPQ.

XRouter container

packethacking/xrouter-container packages Paula G8PZT’s XRouter, unchanged, as ghcr.io/packethacking/xrouter. It is multi-arch (amd64, arm64, arm/v7), with every released version tagged. By default it forwards XRouter’s boot log to docker logs, so test tooling can wait for XRouter to be up. Set XROUTER_TUI=1 to get the normal text screen back.

More on both containers at /projects/linbpq-xrouter-containers/.

rhp2lib-net

packet-net/rhp2lib-net is a .NET client library for RHPv2, XRouter’s host protocol (specified in PWP-0222 and PWP-0245). DAPPS needed one for the XRouter side. It is on NuGet as RhpV2.Client, and includes a mock server for tests and an rhp command line tool.

net-sim

packet-net/net-sim simulates a packet network without radios. It runs a TNC per simulated port (samoyed, Dire Wolf or pdn-soundmodem), and joins them with a model of a 2 m FM channel: real frequency modulation, noise at each receiver, a limiter and discriminator, so that quieting, the threshold cliff, capture and collisions behave as on air. You describe the network in a YAML file, point your node software at the KISS ports, and there is a web UI. The radios are modelled on the Tait TM8100/TM8200 datasheets. SSB is not modelled.

The current release is v0.4.0, and a container is published at ghcr.io/packet-net/net-sim. DAPPS uses it to try BPQ and XRouter together over a simulated channel, including hidden nodes and multi-hop chains.

Thanks

Thanks to everyone who took part in the OARC RFC thread, to John G8BPQ and Paula G8PZT for the node software this builds on, and to the authors of samoyed and Dire Wolf. Much of the code was written with AI assistance, and the tests don’t catch everything, so issues are welcome. If you’d like to run a node or write an app against the API, the docs are at https://packet-net.github.io/dapps/.

73, Tom (M0LTE), GB7RDG.