Skip to content

About

A terminal client for MeshCore LoRa radios: chats, contacts, a braille map of the mesh, a packet inspector and repeater admin

Topics

Resources

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Repository files navigation

meshcore-tui

Latest release

A terminal client for MeshCore radios: chats, contacts, a map of the mesh drawn in braille, a live packet inspector, remote administration of repeaters and room servers, and chess with the people you message. It connects over USB serial, Bluetooth or WiFi, runs happily over SSH and in tmux, and ships as a single binary.

meshcore-tui is an independent project. It isn't affiliated with, or endorsed by, the MeshCore project or its developers; it talks to radios running MeshCore's companion firmware.

Chats, the map and packets split in one view as traffic arrives, then finding #hilltop with ctrl+k and switching themes

The recording and screenshots here all come from --demo, a simulated mesh with made-up nodes, so you can try the app without a radio. They use the ice theme.

Screens

1 Chats. Channels and direct messages, with unread counts, delivery state (sent, heard repeating, delivered), hops and signal on every message, and replies. Incoming DMs and mentions show as toasts, and can ring the bell or raise a desktop notification; m mutes a busy conversation. To join a channel, pick + add a channel under the channels (or press n): a #name joins a public hashtag channel, and a private one takes its secret or a shared link. Picking a message that mentions a #channel you're not in offers J to join it. Channel messages can be signed, so someone posting under another person's name stands out; this is experimental, as docs/signing.md explains.

Chats

Chess over the mesh. Press c in a direct conversation to play chess with that person. The board sits beside the conversation or on its own, and you move with the cursor, the mouse or by typing a move. Each move is one short message, so it gets the usual delivery receipt, and a checksum on every move notices if your two boards drift apart, and one key puts them back in step. It uses the same messages as meshcore-companion by edleeman17, so it's designed to play against that app too, and any other app that supports meshcore-companion's chess messages, though that hasn't been tried yet. In --demo the made-up people play back. docs/chess.md has the keys and how it works.

A game of chess with Dan beside your conversation

2 Contacts. Everyone your radio knows, sortable and filterable, with each contact's key, location, route and advert path. From here you can message, trace, discover or set a route, pin a signing key, share a contact as a QR code or link, and import one.

Contacts

3 Map. Nodes placed where they advertise, and the routes packets actually took, hop by hop. Traffic animates across the map as it's heard, and the busiest links stay drawn; f picks out one node's links at a time, and space switches kinds of node, routes and layers off when it gets busy. The world map is built in and works offline; street detail for your area can be downloaded from OpenFreeMap with one key press.

Map

4 Packets. What the radio hears on the open mesh, decoded: route, type, hops, path, signal and how many copies arrived. Select a packet to step through its fields, with each field's bytes highlighted in the hex dump. It shows adverts and messages on channels anyone can join (Public and hashtag channels); other people's direct messages and private channels are only counted, never shown.

Packets

5 Admin. Log in to repeaters and room servers over the mesh for status, health history, every setting, neighbours, access lists, regions, telemetry, the log and a raw console that completes commands as you type (the full list). A fleet view and a watch list keep an eye on several nodes at once. A repeater plugged in by USB opens straight onto its console with --repeater.

6 Device. Your own radio's settings, and backing it up to a file you can restore later, choosing what goes in: name and location, radio presets, TX power, tuning, telemetry sharing, BLE PIN, clock sync, key export and import, reboot and factory reset. Changes go to the radio as soon as you enter them. On companion firmware v1.18.0 and newer, a console (c on the Device screen, or :radio console) takes commands as you'd type them on the radio's serial console, such as set radio.fem.rxgain on, completing them as you type; docs/console.md lists them all. Frequency, bandwidth, TX power and duty cycle are limited by radio rules in most places, so check your local regulations before changing them.

7 Stats. Uptime, battery, noise floor, airtime and packet counters with sparklines, and an overview of the mesh from what you've heard: busiest repeaters, hop counts, signal spread and channel activity.

Stats

Several at once

Any screens can share the view, split side by side or stacked as in tmux: ctrl+w then v or s, arrows to move between them, ctrl+w q to close one. Each keeps working while it's on show, so you can read a channel while its packets cross the map. The layout is remembered.

Chats above, with the map and packets below

Install

From a release

Each release has a single binary for each platform, with nothing else to install:

Platform File
macOS, Apple silicon meshcore-tui_macos_arm64.tar.gz
macOS, Intel meshcore-tui_macos_amd64.tar.gz
Linux, x86-64 meshcore-tui_linux_amd64.tar.gz
Linux, 64-bit ARM (Raspberry Pi 3 and later on a 64-bit OS) meshcore-tui_linux_arm64.tar.gz
Linux, 32-bit ARM (Raspberry Pi OS 32-bit) meshcore-tui_linux_armv7.tar.gz
Windows, x86-64 meshcore-tui_windows_amd64.zip
Windows, ARM meshcore-tui_windows_arm64.zip

On macOS or Linux, download and install one in a single go, picking your file from the table:

curl -fsSL https://github.com/verdantran/meshcore-tui/releases/latest/download/meshcore-tui_linux_amd64.tar.gz | tar -xz
sudo install meshcore-tui/meshcore-tui /usr/local/bin/

That always fetches the newest release; for a particular one, use releases/download/v0.1.0/… in place of releases/latest/download/…. Or put it in ~/.local/bin instead of /usr/local/bin to skip sudo. On Windows, unzip it and run meshcore-tui.exe from Windows Terminal.

To check a download before unpacking it, fetch the archive and SHA256SUMS from the release into one folder and run shasum -a 256 -c SHA256SUMS --ignore-missing.

The binaries aren't signed. macOS only objects to one downloaded through a browser; if it says the app can't be opened, run xattr -d com.apple.quarantine meshcore-tui once. Windows SmartScreen may warn the first time too: More info, then Run anyway.

On a Mac, the first launch asks for Bluetooth, even if you only connect over USB or WiFi: the Bluetooth library sets itself up as the app starts, and macOS asks then. Saying no only turns off Bluetooth radios; everything else works, and you can change your mind in System Settings → Privacy & Security → Bluetooth.

On Linux, serial ports belong to a group, usually dialout (uucp on Arch). If a radio on USB says permission denied, add yourself with sudo usermod -aG dialout $USER and log in again.

From source

You need Go 1.26.10 or later. On a Mac, the build needs cgo for listing serial ports and for Bluetooth, which works out of the box once the Xcode command line tools are installed.

go install github.com/verdantran/meshcore-tui/cmd/meshcore-tui@latest

Or from a checkout:

git clone https://github.com/verdantran/meshcore-tui
cd meshcore-tui
go build -trimpath -o meshcore-tui ./cmd/meshcore-tui

-trimpath keeps your own folder names out of the binary. Linux and Windows builds are fully static and can be cross-compiled from anywhere with CGO_ENABLED=0 GOOS=linux go build -trimpath ./cmd/meshcore-tui.

meshcore-tui --version says which release or commit a binary was built from; in the app it shows under the logo, in the help title and on :version.

Connecting

Run meshcore-tui on its own to open the connect screen. It lists your saved devices first, then likely radios among the serial ports. Press b to scan for Bluetooth radios, or enter a TCP address for a WiFi companion. Devices are saved once connected, and one can be set to connect automatically. A radio talks to one app at a time, so a second meshcore-tui window can't connect to a radio another window is using; to see several screens at once, use the panes (ctrl+w), or run the app in tmux and attach from more than one terminal.

You can also connect straight away:

meshcore-tui --serial /dev/cu.usbmodem1101    # or /dev/ttyACM0, or COM3
meshcore-tui --ble AA:BB:CC:DD:EE:FF          # as the connect screen's scan shows it; a UUID on macOS
meshcore-tui --tcp 192.168.1.40               # port 5000 unless you give one
meshcore-tui --serial /dev/ttyUSB0 --repeater # a repeater's own console
meshcore-tui --demo                           # a simulated mesh

Heltec V4 radios ship separate firmware for USB, Bluetooth and WiFi companions. If a connection fails in a way that suggests the wrong build, the app says so.

Over Bluetooth, the radio must be paired before it takes commands, with the PIN on its screen, or 123456 if it has no screen, unless you've set your own. On Linux, BlueZ has no agent to ask for it, so pair once with bluetoothctl first; on Windows, pair once in Windows Settings (Win+I) → Bluetooth & devices → Add device.

Getting around

Key Does
1–7 Switch screens (tab and shift+tab too)
j k, arrows, g G Move in lists, and jump to the top or bottom
enter, esc Act on the selected row, and back out one level
/ Filter
: or ctrl+k Go anywhere: type part of any screen, chat, contact, repeater, command or theme and press enter. Commands run as typed: :msg Bob hello, :trace Dundry, :mute 8h
ctrl+f Search messages
ctrl+w then v or s Split the screen side by side or stacked, as in tmux
T Cycle themes
v Cycle motion: full, reduced, off
? Every key on the current screen
q Quit

Letters keep their meaning from screen to screen: y copies, e shares, x removes (after asking), u refreshes, n adds, o sorts, F cycles a quick filter, M shows something on the map and L logs in or out. Anything that deletes data or changes another node asks for y first, and rebooting or replacing an identity has you type a word.

The mouse works too: click a screen's name to go to it, or a pane to focus it, and the wheel scrolls.

Any key can be rebound in keys.toml, apart from ctrl+c and what you type into a text field; see Configuration.

Looks

The default theme is neon. There are twelve others: dusk, vapor, ice, midnight, ember, amber, toxic, phosphor, light, paper, high-contrast, and mono, which is used automatically when NO_COLOR is set. Choose one with --theme, in the config file, or with T as you go.

Each theme is the same thirteen colours, so every screen works in all of them:

neon

dusk

vapor

ice

midnight

ember

amber

toxic

phosphor

light

paper

high-contrast

mono

go run ./scripts/swatches redraws these from the themes themselves.

The app animates every event the radio reports. Motion drops to reduced over SSH or mosh, tmux attached over SSH included, and --motion off stills it entirely. For terminals without braille or box drawing, --ascii redraws everything in plain ASCII and keeps the colours.

A truecolor terminal looks best. Ghostty, iTerm2, kitty, WezTerm, Alacritty and Windows Terminal all work. On Windows, the old console host can't draw braille or some symbols, so use Windows Terminal.

Configuration

Settings live in ~/.config/meshcore-tui/config.toml, and data (message history, contacts, watched nodes' status, map detail and exports) in ~/.local/share/meshcore-tui/, readable only by you. On Windows they're in %APPDATA%\meshcore-tui\ and %LOCALAPPDATA%\meshcore-tui\. Repeater passwords go in the OS keychain, or in passwords.json beside the config where there isn't one, and are only ever sent to a radio that has proved it's yours. docs/privacy.md says what's kept and for how long.

The file is optional; everything has a default. docs/configuration.md covers every setting.

Built with AI

Nearly all of meshcore-tui was written with Claude, Anthropic's AI model. It's had security and performance reviews, but not an independent audit, so do your own due diligence before relying on it; AI_DISCLOSURE.md says what was checked and what wasn't.

Thanks

meshcore-tui stands on meshcore-go, OwlShack's Go port of MeshCore. It does the hard part, from the companion protocol and packet decoding to the cryptography, and without all that careful work this app wouldn't exist. Thank you.

Chess over the mesh comes from edleeman17's meshcore-companion: its message format, and the way a game is rebuilt from those messages, are followed here so the two apps can play each other. Thank you, edleeman17.

Thanks also to the MeshCore project and everyone running nodes on the mesh.

Licence

MIT; see LICENSE. The app is built on meshcore-go and Charm's Bubble Tea and Lip Gloss. THIRD_PARTY_NOTICES lists the licences of everything compiled in, and the map data's sources: Natural Earth for the built-in world map, and OpenFreeMap, OpenMapTiles and OpenStreetMap for downloaded street detail.

About

A terminal client for MeshCore LoRa radios: chats, contacts, a braille map of the mesh, a packet inspector and repeater admin

Topics

Resources

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages