installers.yml gains a cardputer-zero job: build-deb.sh in a Debian 13 container on an arm64 runner, the same system as the Cardputer. The release attaches the .deb with the other downloads and lists it in SHA256SUMS, and its notes say where Cardputer users get MeshTerm. github-release.yml gains a store job after the release. It runs scripts/cardputer-zero/store-publish.py, which calls czdev publish with two corrections: the manifest's email is johnputer@meshterm.net, not the GitHub profile's, and the branch name stays the same between czdev's two calls (for a fork, the second call named a branch that was never pushed, and GitHub refused the PR). It also sends czdev's git over HTTPS with the token, and it publishes nothing when the store has the version or a PR for it is open, so a rerun opens no second PR. AppBuilder is pinned to the commit whose functions it corrects. The job needs the CARDPUTER_STORE_TOKEN secret (public_repo scope). The release skill now checks the store PR and counts fifteen assets. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
MeshTerm
A full-featured TUI MeshCore client for your terminal. Use it to tune your radio, chat across the mesh, and watch the network live. It also keeps a long-term record of everything that you overhear. It works with a companion that is connected by serial, Bluetooth, or network (TCP).
MeshTerm is interactive by default. It is a modern TUI that you operate with the keyboard,
built on Rich and
prompt_toolkit. You can also
use it in scripts. Most screens have a mirror meshterm subcommand. Thus the same
functions work for an evening of exploration on the mesh and for a cron job. MeshTerm
stores each packet that the radio overhears in a local SQLite database. The longer you
run MeshTerm, the more the history of your mesh is worth.
MeshTerm is a side project, and one person runs it. We welcome bug reports. If you want to change something, first say hello on Discord. Read more about how the project is run.
https://github.com/user-attachments/assets/f91a6695-14d5-4ae0-8fdc-e65492d0955d
A video of less than two minutes, made on a real mesh.
The dashboard, the map, a trace, the paths of a message, and the whole app on a PicoCalc.
Why MeshTerm
- One tool, two faces. To open a full-screen menu, start
meshterm. To run one scripted task, give a subcommand. The same registry builds the menu and the CLI, so they do not become different from one another. - It remembers. A passive monitor stores each advert and each telemetry packet that it overhears. This includes the SNR, the RSSI, and the shared position. The monitor starts when the radio opens. The maps, the contact lists, the charts, and the Time Machine all read this history.
- It measures. It has a live trace with the reliability of each hop. It has a TX-power sweep that goes from coarse to fine and then verifies the result. It also has a graph that you can walk through, which shows how the mesh is really connected.
- It talks. You can send live messages on a channel and direct messages. You can use the
message boards of room servers. A courier stores messages and sends them when a contact
is not yet there. You can share a channel as a QR code or as a
meshcore://link. - It connects in the same way as your companion. It supports serial (USB), Bluetooth LE, and TCP (a Wi-Fi board or a network proxy). It finds the serial and Bluetooth devices automatically, and you select one from a list. You type the name of a network device. MeshTerm reconnects live when a link of any kind drops. On Windows and Linux, MeshTerm pairs with a Bluetooth companion that has a PIN. When a connection fails, MeshTerm says which step failed and what to do. If you have no radio, a built-in simulator is available for development.
- It works offline. The street map caches OpenStreetMap tiles on disk. When there is no network, it shows a blank grid. MeshTerm never needs the internet to run.
Install
Download a build
A build is one file. You do not need Python. Builds are available for Windows, macOS (Intel and Apple silicon), and Linux (x64 and ARM64, so the uConsole is included). Each command below gets the ⬇ latest release, whichever release that is. Thus the commands do not become old.
MeshTerm is a terminal program, so open a terminal and run it from there. You can double-click the file and it will work. But then your system selects the console, and you cannot choose it. If an error occurs at startup, the window closes before you can read the error.
macOS: download it with curl
Do not use your browser. A browser marks the file as downloaded, and then macOS does not
let you open it. On Sequoia and later, right-click → Open does not help. curl does not
mark the file, so the file runs. Open Terminal and paste:
curl -fL -o meshterm https://github.com/jpmartineau/MeshTerm/releases/latest/download/meshterm-macos-arm64
chmod +x meshterm
./meshterm
This is the build for Apple silicon Macs (M1 and later). On an Intel Mac, replace
arm64 with x64. If you already downloaded the file with a browser, you do not have to
start again. Run xattr -d com.apple.quarantine meshterm to clear the mark.
Linux: the same three lines
Use linux-x64 on a PC. Use linux-arm64 on a uConsole or another 64-bit ARM handheld.
curl -fL -o meshterm https://github.com/jpmartineau/MeshTerm/releases/latest/download/meshterm-linux-x64
chmod +x meshterm
./meshterm
Windows
Download
meshterm-windows-x64.exe.
Then open Windows Terminal or PowerShell, use cd to go to your downloads folder, and run
the file:
.\meshterm-windows-x64.exe
The first time, Windows says "Windows protected your PC". Click More info → Run anyway.
After these steps, you have one file: meshterm on macOS and Linux, or
meshterm-windows-x64.exe on Windows. Put the file in a folder that is in your PATH. On
Windows, rename it to meshterm.exe. Then you can run meshterm from any folder.
These builds are not code-signed yet. For this reason, macOS and Windows both show a warning the first time. Windows signing will come. MeshTerm applied to the SignPath Foundation, which signs open-source projects for free. After the setup is complete, each Windows download will be signed. The code signing policy below gives the details. The Mac builds will stay unsigned, because Apple charges a fee for signing and this is a free side project. Each release has a
SHA256SUMSfile. Use it to check the file that you got. Installing with pip or pipx avoids the problem, because you do not download a binary.The page of each release also has these commands, written for that exact version, next to its own downloads.
If your terminal draws empty boxes
MeshTerm draws emoji icons, braille charts, and powerline path chips. Your terminal decides if you see them, not your font. Windows Terminal, the terminal of VS Code, and each modern terminal on macOS and Linux draw them correctly.
The classic Windows console does not draw them. This is the black cmd.exe window that
opens when you double-click the file. When MeshTerm starts there, it moves to Windows
Terminal, tells you, and opens there. It does not install anything and does not change
anything. If Windows Terminal is not available, MeshTerm offers the charts and marks without
the icons. It also installs Microsoft's Cascadia Mono PL
for you. This needs no administrator rights, and it downloads nothing.
To stay in the same console, turn off these actions in Preferences → Display → Console setup. Terminals, icons, and the Windows console explains why they are necessary.
Try a build without a change to your real data. MeshTerm keeps all its data in
~/.meshterm. This includes your history database, your contacts, and your channel keys. Each copy of MeshTerm uses this same folder. To try a copy in isolation, setMESHTERM_HOME:MESHTERM_HOME=~/meshterm-test ./meshterm # macOS, Linux$env:MESHTERM_HOME = "$HOME\meshterm-test"; .\meshterm-windows-x64.exeUse the same variable if you run two radios and you want to keep them separate.
Or install with pip
You need Python 3.10 or newer. This is the only requirement. MeshTerm installs all other parts by itself.
pip install git+https://github.com/jpmartineau/MeshTerm
meshterm
meshterm opens the full-screen menu. This is the complete installation.
Do you not want to change your system Python? pipx puts the
app in its own private environment. It also gives you a normal meshterm command:
pipx install git+https://github.com/jpmartineau/MeshTerm
Do you not have a radio yet? meshterm --mock runs the complete app on a simulated
mesh. You can look at the app before you buy anything.
Coming
pip install mesh-term will work after the package is published. It is not published
yet, because the question of the name is not resolved
(read why).
To set up a development environment, refer to CONTRIBUTING.md.
Documentation
The documentation index lists all the documents. This includes the code survey, which we keep as a historical record. This table is a short version:
| Read | For |
|---|---|
| The command line | Each subcommand and option, what each prints on the plain face and on the JSON face, the exit statuses, and recipes. |
| What MeshTerm does | Each screen that the menu has, and the command that does the same job without the menu. |
| The CLI cookbook | Common one-line commands, in groups by the task that you want to do. |
| Configuring MeshTerm | The preferences, the device profiles, and all the files that MeshTerm keeps in ~/.meshterm. |
| When a companion does not connect | Bluetooth pairing on each system, how to find the PIN, USB permissions, and each connection error, with the action to take. |
| MeshTerm on hardware | Which handheld manual is the correct one for you: the PicoCalc build, or the uConsole, whose LoRa chip MeshTerm can control directly. The Cardputer Zero is not supported yet. |
| How the code is laid out | The layers of the code, and where to put a new feature. |
| CONTRIBUTING.md | The development setup and the house rules. |
| CHANGELOG.md | What changed, with the newest change first. |
Quick start
# Interactive full-screen menu (auto-discovers serial + Bluetooth companions)
meshterm
# Connect over Bluetooth (address from `meshterm devices`); add --ble-pin if it has a PIN
meshterm --ble AA:BB:CC:DD:EE:FF --ble-pin 123456 info
# Connect over the network to a TCP companion (host[:port], port defaults to 5000)
meshterm --tcp 192.168.1.50 info
# Drive a LoRa radio on this machine's own SPI bus (the uConsole AIO; Linux only)
meshterm --spi info
# No radio attached? Use the built-in simulator for development.
meshterm --mock
# On a ClockworkPi PicoCalc (Luckfox Lyra / Calculinux) the handheld flavour is
# auto-detected: a 53-column layout, a 16-slot palette, a compact glyph language on a
# custom console font, and an F-key hint lane. Preview it anywhere, or inspect it:
meshterm --mock --platform picocalc-lyra
meshterm specimen
MeshTerm has its own manuals for handhelds. MeshTerm on the
PicoCalc goes from the shopping list for a stock PicoCalc
to a Linux handheld that has a LoRa radio soldered inside. MeshTerm on the
uConsole shows how to control the SPI LoRa board of a uConsole
directly with --spi. It also shows how to use a small bridge, if you want the node to be
on the mesh at all times. M5Stack's Cardputer Zero also has a page, but it is not
supported yet. The scripts that the manuals run on the
device are in scripts/. If you do not know which manual is correct for you,
refer to docs/devices/README.md.
Does a companion not connect? When a companion does not
connect explains Bluetooth pairing on Windows, Linux, and
macOS. It also explains the dialout group and ModemManager for USB on Linux, and each
error message that MeshTerm gives.
What it does
The menu asks one question: what would you like to do? It gives the answer in two halves. Three sections name an activity. Message has chat, channels, the courier outbox, and contacts. Watch has the dashboard, the live feed, the watchtower, and the time machine. Explore has the map, the mesh walk, tracing, and the trophy case. The other three sections name the owner. This node is the radio in your hand. Other nodes is the someone else's radio, which you reach over the mesh. This app is MeshTerm itself, with the preferences, the diagnostics, and the written pages.
Almost all of these have a mirror meshterm subcommand. The same registry builds the menu
and the CLI, so they do not become different from one another. The live screens, such as the
map and the dashboard, are only in the menu.
What MeshTerm does is the complete catalogue. It shows each screen, what the screen does, and the scripted equivalent where there is one.
Scripting it
Almost every command accepts --json. The global options are --profile/-p, --port,
--ble, --ble-pin, --tcp, --spi, --mock, --db, --json, --absolute,
--quiet/-q, and --platform. You can type them before or after the subcommand.
# Every repeater's public key, for a script
meshterm contacts --json | jq -r '.[] | select(.node.type == "repeater") | .node.key'
# A trace transmits exactly once; run it again to sample more
meshterm trace --target Alice --profile yagi
# Messaging, and store-and-forward for a contact who isn't there yet
meshterm chat send --channel 0 "net in 5"
meshterm courier queue Alice "ping me when you're back" --at 18:30
# The radio's own settings, and a passive capture window
meshterm config set radio_sf 9
meshterm monitor --seconds 60
The command line is the manual. It shows each command and option, what each prints on both faces, and the exit statuses. The CLI cookbook has more one-line commands like these.
How this project is run
One person works on MeshTerm, in the evenings and at weekends. I want to tell you this at the start, so that you do not have to guess from the time that things take.
We welcome all issues. This includes bugs, questions, and "is this a fault or is it correct". The bug form asks for much information. This is intentional. The quality of the description of a problem decides if I can do something about it. If I can reproduce a problem, I will usually work on it. If I cannot reproduce it, I can only guess.
Ask before you write a pull request. Join the Discord
and say hello in #contributing. Tell us what you want to change. Then wait for a yes.
This applies to small corrections also. This is not because I am too careful. MeshTerm has
firm house rules for how to build screens (they are in CLAUDE.md). I do not
want you to spend a weekend on a change that I then ask you to write again. A short
conversation at the start saves time for both of us. You can use AI tools, but you must say
that you used them. CONTRIBUTING.md has the details.
I cannot promise a time. Some problems are corrected the same night. Some wait for a month, because I had other tasks in my life. If your issue is quiet for a long time, please remind me. This helps me.
Where to report a problem. You can use one of these two places:
- GitHub issues, if you have an account. We track and correct problems here, so this is the shortest path.
- Discord, if you do not have an account, or if you
are not sure that the problem is a bug. Ask in the support forum, or put defects that you
can reproduce in
#bugs. I move the real bugs to GitHub myself.
Do not worry about the choice of the wrong place. It is better that you tell us about a problem than that you file it in a tidy way.
More documents: CONTRIBUTING.md · SECURITY.md · CODE_OF_CONDUCT.md · CHANGELOG.md
Code signing policy
Free code signing provided by SignPath.io, certificate by SignPath Foundation.
This policy is for the Windows download. The setup is in progress, so the releases up to and including 0.10.2 are still unsigned.
How a build is signed. GitHub Actions makes each Windows build, directly from the public source code in this repository. SignPath signs only a file that it can trace to one of these builds, and only after the maintainer approves that release. This process cannot sign a file that was built on any person's own computer, and this includes the maintainer's computer.
Who does what. MeshTerm has one maintainer, Jean-Pierre Martineau, who has all three roles:
- Author: writes the code and commits it.
- Reviewer: reviews each change from anyone else before it goes in.
- Approver: approves each release before it is signed.
Privacy. This program will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it.
In practice, MeshTerm goes online for only one purpose: map tiles. It downloads them from OpenFreeMap when you open a screen that shows a map. The privacy policy of OpenFreeMap applies to these downloads. MeshTerm collects no information about you, and it does not check for updates. Over the radio, MeshTerm sends only what you tell it to send.
Acknowledgements & attribution
MeshTerm stands on the MeshCore project — its firmware and the
meshcore Python companion library are what make talking to the radio possible.
Map data
The street map is rendered from © OpenStreetMap contributors data, served as vector tiles by OpenFreeMap on the unmodified © OpenMapTiles schema. OpenStreetMap data is available under the Open Database License (ODbL). Tiles are decoded with a small built-in reader for the Mapbox Vector Tile format.
Both map surfaces carry the credit themselves. The full-screen map opens with
© OpenMapTiles · Data from OpenStreetMap in its bottom-right corner and collapses it to
© OpenStreetMap once you pan, zoom, or type — set into the panel's bottom border rule on
a desktop terminal, so the drawing itself keeps every cell, and on the map's own last row
on the PicoCalc, whose frame has no bottom rule. The node page's location preview shows the
short form throughout. The About page inside the app spells out the licence URL.
Bundled font
MeshTerm ships Cascadia Mono PL, © 2019–present Microsoft Corporation, redistributed unmodified under the SIL Open Font License 1.1. It's offered to Windows users whose console can't draw the charts — see Terminals, icons, and the Windows console. Microsoft doesn't endorse MeshTerm; the font is simply the right tool, being one of the very few monospace faces that carries the braille block the timelines are drawn from.
Open-source dependencies
MeshTerm is built with these libraries; each is used under its own license (see the respective project for the authoritative terms):
| Library | Role | License |
|---|---|---|
| meshcore | Companion-device protocol (serial / BLE / TCP) | MIT |
| pycryptodome | AES/HMAC for decrypting overheard channel packets | BSD-2-Clause / Public Domain |
| pyserial | Serial-port enumeration and I/O | BSD-3-Clause |
| bleak | Bluetooth LE scanning + connection | MIT |
| Typer | Scripted CLI (subcommands mirror the menu) | MIT |
| Rich | Console rendering | MIT |
| prompt_toolkit | Full-screen interactive TUI | BSD-3-Clause |
| markdown-it-py | CommonMark parser behind the written About pages | MIT |
| Segno | Pure-Python QR codes (channel share links) | BSD-3-Clause |
| tomli / tomli-w | TOML config, preferences, and device-config backups | MIT |
License
Copyright © 2026 Jean-Pierre Martineau.
MeshTerm is open source under the Apache License, Version 2.0 — free to use, modify, and redistribute, commercially or otherwise. The "MeshTerm" name and any associated logo are trademarks reserved by the author and aren't covered by the code license (see NOTICE); a redistributed fork should go by its own name. The donate link built into the app supports this project and its original author — forks that keep soliciting through it without redirecting it to themselves aren't affiliated with this project.
The bundled font is not covered by that license. meshterm/assets/fonts/CascadiaMonoPL.ttf
is Microsoft's Cascadia Mono PL, redistributed unmodified under the SIL Open Font License
1.1, which travels with it as
CascadiaMono-OFL.txt and stays its only
license.
Each standalone build is a single file with LICENSE, NOTICE, and a generated
THIRD-PARTY-NOTICES.txt (every dependency's own license text) bundled inside it. The same
three files are also attached to each release on the
releases page, so you can read them
without running anything.




