CHRP Mesh Messenger

Text, voice and photos across a 5-phone LoRa mesh at 20% packet loss, with a delivery status that never lies.

Track: CHRP — Off-Grid Everything

The problem

A LoRa packet holds 230 bytes. The link runs at 3.5 kilobits per second. A photo is 3 million bytes. Packets drop at every hop, and at 20% loss over three hops only about half survive one try. We wrote the software that gets media across anyway.

What we built

Five simulated phones on a map, using the published Meshtastic data rates and the Semtech time-on-air formula. An app that shows what arrived, what is still coming, the route it took and how long is left.

Each phone collects the full set of pieces, asks the phone before it for what it missed, and only passes on a complete set. Each hop fights its own 20% instead of the loss stacking across four. Kill a phone mid-transfer and the data reroutes from the last phone holding it.

We never send the photo. We send a caption in one packet, then the real image in layers: 32×32 at 400 bytes, then 64, then 128. A 2.4 MB photo costs 19,853 bytes on air including every resend. Voice runs through Codec2 at 700 bits per second — 82 kilobytes becomes 831, with the transcript sent first so the words are readable long before the audio lands.

Every loss rate from 0 to 40% delivered with a matching hash.

How it handles uncertainty

Every message carries a SHA-256 hash. The app shows the sent and received hashes side by side and only says Delivered when they match. Before that: Queued, Sending, At Phone C, Receiving 5 of 7, Checking. Time left is a range. The simulation speed is always on screen.

When a photo layer arrives we show three panels from the same bytes: what arrived, a plain upscale that invents nothing, and an AI reconstruction. The AI panel looks best and is least faithful — in testing it drew blue satin on white when the photo was a blue shape on grey-green. We kept that example rather than hiding it. It is the argument for sending real pixels instead of regenerating from text, and the panel is labelled as invented every time. The reconstruction function only ever receives bytes that crossed the mesh; the original is never passed to it, and the app asserts this on every call.

We rejected voice cloning. It would have cut 831 bytes to 50. A synthetic voice saying words a model thinks it heard is not a message from a person, and off-grid is where that error costs most. Our own test turned "North Gate" into "North Tee" — which is exactly why we send both the words and the voice.

Tools

NicrronNinoo runs every AI call: captioning and caption scoring with GPT-4o-mini, transcription with Whisper, image reconstruction with nano-banana. We found the gateway's image endpoint accepts no image input, confirmed it with their team, and built a two-step path instead — a vision model describes the received bytes, the image model draws from that description. That extra step is what makes the reconstruction's errors visible, which turned a limitation into the clearest part of the demo.

Block Convey PRISM traces every AI call from a background thread. A guardrail blocks prompt injection before text leaves the phone, and says so honestly when PRISM is unreachable rather than pretending a check happened. An evaluator scores the caption confidence against a rubric. The radio preset in the header is verified against a Knowledge Base document rather than a model's memory.

Python, FastAPI, one WebSocket, plain HTML and JS. The mesh, transport and compression are fully local — an offline toggle kills every network call and the app still works.

Built With

Share this project:

Updates

Submission history