docs/cli.md documents every command and option, what each one prints, and what it returns -- with the output conventions and the exit-status table up front, since those are the two things a script is written against. Every command, option and flag in it was checked against the running app; the sample output is captured from the simulator rather than typed out. Writing it turned up two places the CLI still did the thing the last commit was about. A destructive command refused for want of --yes printed its refusal in red on *stdout* and exited 1: a colour and a sentence that is not the command's answer, in whatever was reading the command's answer. A missing confirmation is a bad invocation, so it now goes through the parser like any other -- nothing on stdout, the reason on stderr, exit 2. The README keeps its cookbook and its summary of the conventions, and points at the manual for the rest. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
30 KiB
The MeshTerm command line
MeshTerm has two front ends over one codebase. The menu — what you get by running
meshterm with no arguments — is a full-screen session meant to be read by a person. The
CLI is meant to be read by awk.
This is the manual for the second one: what it prints, what it returns, and every command it answers to.
Running it
meshterm [GLOBAL OPTIONS] COMMAND [ARGS]
With no command, MeshTerm launches the interactive menu instead. Global options go before the command:
| Option | What it does |
|---|---|
-p, --profile NAME |
Use a named device profile from config.toml. |
--port PORT |
Serial port to connect to (COM5, /dev/ttyACM0), overriding the profile. |
--ble ADDRESS |
Bluetooth address of a companion; selects the BLE transport. |
--ble-pin PIN |
Pairing PIN, if the Bluetooth companion asks for one. |
--tcp HOST[:PORT] |
Network address of a TCP companion; selects the TCP transport. Default port 5000. |
--mock |
Use the built-in simulator instead of real hardware. Nothing transmits. |
--db PATH |
Use this SQLite database instead of ~/.meshterm/meshterm.db. |
--json |
Machine-readable output. Only devices and tx-optimize honour it; everything else is already parseable as plain text. |
-q, --quiet |
Suppress console logging entirely (the log file still records). |
--platform NAME |
Force the UI flavour (regular|picocalc) instead of detecting it. |
Commands that need a radio open one, do their work, and close it. Commands that only read
stored history (records) or MeshTerm's own state (preferences, about) need no device
at all and work with nothing attached.
One transmission per invocation. A trace transmits exactly once — repeaters penalise, and can blacklist, nodes that burst traffic. To sample more, run the command again with your own pacing between runs.
Output conventions
The CLI prints like a standard Unix utility, and every rule below exists so its output can be piped somewhere without being cleaned up first.
No colour. Not a hue, not a bold, not a dim — stdout carries no escape sequence at all, whether or not it is a terminal. A colour that survives into a file is noise in it.
No wrapping. A record is a line. Wrapping would put half a record's fields under the
wrong headings, so nothing folds: a long line runs off the right and your terminal (or
less -S, or your pipe) decides what to do about it.
No frames. No borders, no boxes, no rules, no titles, no legends. The command you typed is the title.
Listings are an uppercase header line followed by space-aligned records, the shape ps
and df print. Numeric columns right-align.
$ meshterm contacts
NAME TYPE HEARD PKTS KEY
"Alice" node 2026-09-07T19:58:54-04:00 12 d4e5f6a700000000000000000000000000000000000000000000000000000000
"Yagi-Repeater" repeater 2026-09-07T19:58:53-04:00 97 a1b2c3d400000000000000000000000000000000000000000000000000000000
Node names are quoted. A name can hold a space, a comma, even a quote, so a bare name
is not one field — it is however many fields the name happens to split into. Quotes and
backslashes inside a name are escaped the ordinary way ("He said \"hi\""), so a quoted
value reads back unambiguously.
Key/value blocks are a key, the gutter, and the rest of the line as its value — the
shape sysctl -a prints. There is no header, and the value is not quoted: a line has
exactly two fields, so the value is whatever follows the key.
$ meshterm info
name MockCompanion
public_key 0000000000000000000000000000000000000000000000000000000000000000
role companion
battery_v 4.10
uptime_s 93784
noise_floor_dbm -110
A get prints the bare value alone, ready for $(...):
$ meshterm config get tx_power
20
Paths are quoted node names, each with its hash in parentheses outside the quotes,
joined by a bare comma — the same comma --path takes:
"MockCompanion" (00),"Yagi-Repeater" (a1),"Alice" (d4),"Yagi-Repeater" (a1),"MockCompanion" (00)
Your own node is a hop like any other, named and hashed — never a ★. The hash is there
because the CLI has no colour: on screen a route's hops are told apart by their key-derived
hues, and in plain text the hash is what carries that identity. It is also what joins a
route line to the per-hop table underneath it.
Times are absolute local ISO-8601 to the second — 2026-09-07T18:22:41-04:00 — never
3h ago. A relative age is for someone watching a screen; a script wants something it can
sort and subtract.
- is the one token for nothing — absent, unknown, or not applicable. You learn it
once; there is no —, no n/a, no never, no empty cell.
stdout is the answer; everything else is stderr. Errors print as
meshterm: what went wrong. Progress bars draw on stderr too, and draw nothing at all when
stderr is not a terminal. So meshterm contacts > contacts.txt puts contacts in the file
and any complaint on your screen.
Exit status
The return value is half the report.
| Code | Meaning |
|---|---|
0 |
Success. |
1 |
Failure with no more specific code — a bad value, an unreadable file, an unhandled fault. |
2 |
Usage error: an unknown flag, a missing argument, a value the parser rejected. |
3 |
No companion device could be selected: none attached, none matching the connection flags, or the choice was ambiguous. Nothing was transmitted. |
4 |
A device was reached but the operation failed — a command error, a timeout, a link lost mid-run. Retrying is reasonable. |
5 |
The command completed and there was nothing to report: an empty list, a target that never answered, a conversation with no messages. stdout is empty. This is not an error. |
The table is printed under meshterm --help as well.
5 is the one worth building on. grep conflates "found nothing" with "worked", and a
caller that has to count output lines to tell an empty mesh from a full one is parsing when
it could be branching:
if meshterm contacts > contacts.txt; then
echo "$(($(wc -l < contacts.txt) - 1)) contacts" # minus the header
elif [ $? -eq 5 ]; then
echo "no contacts yet"
else
echo "could not reach the radio" >&2
fi
3 and 4 split the failures a retry might fix from the ones it never will:
meshterm trace --target Alice
case $? in
0) echo "reachable" ;;
5) echo "no reply — the walk ran, nothing came home" ;;
3) echo "no radio attached" >&2; exit 1 ;;
4) echo "radio trouble — worth retrying" >&2; exit 1 ;;
*) echo "failed" >&2; exit 1 ;;
esac
Command reference
Finding a device
meshterm devices
List every attached serial device and in-range Bluetooth companion. Opens no radio — it only enumerates what is attached or advertising.
| Option | What it does |
|---|---|
--ble / --no-ble |
Include a Bluetooth LE scan. On by default; skipping it saves a few seconds. |
$ meshterm devices --no-ble
TARGET TRANSPORT NAME HARDWARE MESHCORE SERIAL ACTIVE
COM12 serial "USB Serial Device (COM12)" "Adafruit" maybe D030D2CCD00F08EB no
COM16 serial "USB Serial Device (COM16)" "Adafruit" maybe D8D7D4BB5E4546E0 no
COM1 serial "Communications Port (COM1)" "(Standard port types)" no - no
TARGET is what --port and --ble take, verbatim. MESHCORE is three-valued and stays
that way: yes only once a connection has proved the device speaks the protocol, maybe
for a USB vendor ID that suggests a LoRa board or a bridge chip, no for anything else — a
vendor ID is a hint, and the column would be lying if it rounded one up.
Returns 5 when nothing is found.
This node
meshterm info
The connected companion's live status: which radio this is, and how it is doing.
$ meshterm info
name MockCompanion
public_key 0000000000000000000000000000000000000000000000000000000000000000
role companion
model MeshCore Simulator
firmware mock mock
battery_v 4.10
storage_used_kb 128
storage_total_kb 1024
clock 2026-09-08T01:05:09-04:00
clock_drift_s -125
uptime_s 93784
noise_floor_dbm -110
last_rssi_dbm -62
last_snr_db +9.5
tx_air_s 42
rx_air_s 360
packets_sent 210
packets_received 1234
receive_errors 3
The unit is in the key, so nothing has to be pulled back out of prose. A reading the
firmware does not answer for is absent rather than -: a missing key says "this device
does not report it", where a dash would claim it reported nothing.
What the radio is set to is config show's answer, not this one.
meshterm config
View and change every device setting. With no subcommand it runs show.
| Subcommand | What it does |
|---|---|
show |
Print every setting as key value. |
get KEY |
Print one setting's value, bare. |
set KEY VALUE |
Change one setting. |
backup PATH |
Write every setting to a TOML file. |
restore PATH [--dry-run] |
Apply settings from a TOML backup. --dry-run prints the plan and changes nothing. |
custom KEY VALUE |
Set an experimental custom variable. |
channel INDEX NAME [--secret HEX] |
Configure a channel slot (see also the channels group). |
advert [--flood] |
Broadcast an advertisement. Zero-hop unless --flood. |
advert-cadence HOURS [--flood] |
How often to auto-advertise in the background. 0 disables. |
share |
Print this node's contact card as a meshcore:// URI. |
sync-clock |
Set the device clock from this computer. |
export-key [--out PATH] |
Export the private key. Sensitive. |
import-key KEY_HEX --yes |
Import a private key, overwriting this node's identity. |
reboot --yes |
Reboot the device. |
factory-reset --yes |
Erase all data and reset to defaults. |
$ meshterm config show
name MockCompanion
adv_lat 0.0
adv_lon 0.0
device_pin ••••••
radio_freq 869.618
radio_bw 62.5
radio_sf 8
radio_cr 5
tx_power 20
manual_add_contacts false
flood_scope ""
adv_loc_policy 0
show names each setting by the key get and set take, and prints a value they will
take back — an enum's number, not the reader's label; "" for an empty string; - for
something the firmware never reported. So a line read out of show can be typed straight
back in:
$ meshterm config set radio_sf 9
$ meshterm config get radio_sf
9
The pairing PIN stays masked here, because this is the whole-device dump — the thing that
gets redirected into a file and pasted into a bug report. Name it deliberately with
meshterm config get device_pin.
Custom variables are namespaced custom.* in the output, since they have no spec and
config set will not take them (use config custom).
Destructive operations are gated behind --yes rather than a prompt, so nothing surprising
happens in a script. Without it the command is refused as a usage error — nothing on
stdout, the reason on stderr, exit 2.
The mesh around you
meshterm contacts
The contacts your device knows.
| Option | What it does |
|---|---|
-s, --sort ORDER |
heard (default), name, or packets. |
$ meshterm contacts --sort name
NAME TYPE HEARD PKTS KEY
"Alice" node 2026-09-07T19:58:54-04:00 12 d4e5f6a700000000000000000000000000000000000000000000000000000000
"Local-Repeater" repeater 2026-09-07T19:58:53-04:00 48 b2c3d4e500000000000000000000000000000000000000000000000000000000
TYPE is the node's advertised role in words — node, repeater, room, sensor, or
unknown. PKTS is how many packets passive monitoring has overheard from it. KEY is
the full public key, never elided: a truncated key is not something you can hand back to
--to or --path.
This lists contacts only. Your own node is not a contact — meshterm info reports it, in
far more detail than a row could hold.
Returns 5 when the device knows no contacts yet.
meshterm monitor
Capture overheard packets in the foreground for a bounded window, then summarise it. Transmits nothing; it only listens. Recording to history is always on anyway — this adds the live view.
| Option | What it does |
|---|---|
-s, --seconds N |
How long to capture. 0 (the default) runs until Ctrl-C. |
$ meshterm monitor --seconds 3
TIME NODE NAME SNR_DB RSSI_DBM LAT LON
2026-09-08T01:07:25-04:00 a1b2c3d4 "Yagi-Repeater" +7.0 -101 45.50190 -73.56740
2026-09-08T01:07:25-04:00 c3d4e5f6 "Observer-Bot" +4.9 -93 - -
NODE NAME PKTS MEDIAN_SNR_DB BEST_SNR_DB RSSI_DBM LAST_HEARD
c3d4e5f6 "Observer-Bot" 54 +5.2 +12.4 -108 2026-09-08T01:07:33-04:00
a1b2c3d4 "Yagi-Repeater" 48 +5.1 +12.8 -100 2026-09-08T01:07:33-04:00
Two blocks, separated by a blank line. The stream is a header and then a record per packet as it arrives; it cannot be column-aligned, because the widths are not known until it ends, so its fields are gutter-separated and the name carries its quotes. The summary is the aggregate the stream cannot give — a count, a median, a best per node — most recently heard first.
Returns 5 when the window heard nothing.
meshterm records
The record-setting walks every trace has been scored against. Reads the database; needs no device and never transmits.
| Option | What it does |
|---|---|
-c, --category ID |
One discipline: long_haul, far_point, long_leg, grand_tour, clean_trail, thin_thread, big_loop. |
-w, --width N |
Only records set at this per-hop hash width (1, 2, or 4). |
$ meshterm records --category long_haul --width 2
CATEGORY WIDTH SCORE UNIT RECORDED VERSION ROUTE
long_haul 2 273.0 km 2026-08-17T18:14:28-04:00 0.2.8 "Yagi-Repeater" (a1b2),"Alice" (d4e5),"Yagi-Repeater" (a1b2)
long_haul 2 112.0 km 2026-09-03T17:46:10-04:00 0.2.8 "Local-Repeater" (b2c3),"Alice" (d4e5),"Local-Repeater" (b2c3)
SCORE is a bare number and UNIT is its own column, so the scores in a column are
comparable. A Longest-distance score prefixed >= is a lower bound: some hop on that
walk has no known position, so the distance is a floor rather than a measurement.
Records are kept per hash width, because the width bounds both a walk's maximum length and its collision odds — boards at different widths are measuring different games.
Returns 5 when no records match.
Messaging
meshterm chat
| Subcommand | What it does |
|---|---|
send TEXT --to NAME |
Send a direct message. |
send TEXT --channel N |
Broadcast on a channel slot. |
history [--to NAME | --channel N] [--limit N] |
Print a conversation's stored transcript. Default limit 50. |
list |
Every channel and contact with its unread count and last message. |
listen [-s SECONDS] [--debug] |
Tail inbound messages live. |
Exactly one of --to and --channel is required on send and history.
$ meshterm chat send "on my way" --to Alice
acked yes
A direct message prints its acked state, which is the one thing the send does not already
tell you — the radio accepted it either way, and whether the peer answered is a separate
fact. A channel broadcast prints nothing: there is no acknowledgement on a channel, so
the exit status is the whole answer.
$ meshterm chat history --to Alice
TIME DIRECTION PEER SNR_DB TEXT
2026-09-08T01:07:41-04:00 out "Alice" - on my way
2026-09-08T01:09:02-04:00 in "Alice" +6.4 see you there
DIRECTION is in or out; PEER is always the other party. TEXT is last and
unquoted — it is the rest of the line, and a message body is the one field that can hold
absolutely anything.
$ meshterm chat list
CONVERSATION KIND UNREAD LAST_TIME LAST_TEXT
"Public" channel 0 - -
"Alice" direct 2 2026-09-07T19:58:54-04:00 see you there
listen prints a header and then a record per message as it arrives, the same shape
monitor's stream takes. --debug routes the message-pull logging to stderr, for working
out whether messages are being pulled from the companion at all.
history, list and listen return 5 when there is nothing to report.
meshterm channels
| Subcommand | What it does |
|---|---|
list |
The configured channel slots. |
add INDEX NAME [--secret HEX] |
Add a channel. A leading # makes it public (the firmware derives the key from the name); otherwise it is private, with a random key unless you give one. |
join INDEX NAME SECRET |
Join a channel from its name and 32-hex-character key. |
import INDEX URL |
Import a meshcore://channel/add link. |
share INDEX |
Print a slot's share link. |
clear INDEX --yes |
Clear a slot, removing the channel from the device. |
$ meshterm channels list
SLOT NAME TYPE HASH
0 "Public" public 8f
1 "brigade" private 2c
share prints the meshcore:// URI alone. (The menu draws a QR code beside it; redirected
into a file that is a block of block characters wrapped around the one thing that is
actually the answer.)
clear is gated behind --yes because a private channel's key is lost with the slot unless
it is saved elsewhere.
list returns 5 when no slots are configured.
meshterm courier
A store-and-forward outbox: queue a message for a contact that is not reachable right now, and it goes out the moment the contact is next heard — or at a time you name.
| Subcommand | What it does |
|---|---|
queue CONTACT TEXT… [--at HH:MM] |
Queue a message. --at holds it until the next occurrence of that local time. |
list |
The outbox: waiting entries then finished ones. |
send ID |
Force one delivery attempt now, skipping the "wait until heard" check. |
cancel ID |
Remove a waiting entry. |
clear |
Drop every finished (delivered / given-up) entry. |
$ meshterm courier queue Alice "ping me when you are back" --at 18:30
id 10
$ meshterm courier list
ID STATE NODE SCHEDULED FINISHED TEXT
10 waiting "Alice" 2026-09-08T18:30:00-04:00 - ping me when you are back
8 delivered "Bob" - 2026-08-11T18:10:17-04:00 Courier test!
queue prints the entry's id, which is the one fact you have to keep: it is what send
and cancel take. An entry with no SCHEDULED time goes as soon as the contact is heard.
$ meshterm courier send 10
outcome delivered
outcome is one of delivered, no ack, gave up, unknown contact, busy, gone.
The sending is done by a running interactive session's courier; a queued message sits in the outbox until one runs.
list returns 5 on an empty outbox; cancel and clear return 5 when there was
nothing to act on.
Tracing
meshterm trace
Walk the path to a target once and report what came back.
| Option | What it does |
|---|---|
-t, --target NAME |
Required. Target node name or key prefix. |
-p, --path SPEC |
Force a route: comma-separated contact names and/or hex key prefixes, mixed freely (3d,f2,3d). Omit it and the device routes. |
$ meshterm trace --target Alice
target Alice
path auto
success yes
hops 3
min_snr_db +2.6
rtt_ms 459
route "MockCompanion" (00),"Yagi-Repeater" (a1),"Alice" (d4),"MockCompanion" (00)
HOP FROM TO SNR_DB
0 00 a1 +6.0
1 a1 d4 +2.6
2 d4 00 +5.1
Two blocks. The first is what the walk did, route among the facts. The second is a record
per hop, naming its two ends by the hash rather than repeating the names: the route line
above is where the names are, and the hash is what joins the two blocks. path reads auto
when the device routed it — every real value there is comma-separated hex.
A trace that never came home is not a failure of the command: the radio transmitted and
the walk ran. It reports success no and returns 5.
meshterm trace-path
The other half of tracing: no target, just a route you compose by hand — out and back whichever way you choose. It only has to end within earshot of this node.
| Option | What it does |
|---|---|
-p, --path SPEC |
Required. The whole walk, comma-separated. |
$ meshterm trace-path --path "a1,d4,a1"
target -
path a1,d4,a1
success yes
hops 4
min_snr_db +2.0
rtt_ms 458
route "MockCompanion" (00),"Yagi-Repeater" (a1),"Alice" (d4),"Yagi-Repeater" (a1),"MockCompanion" (00)
HOP FROM TO SNR_DB
0 00 a1 +6.0
1 a1 d4 +2.0
2 d4 a1 +2.4
3 a1 00 +6.0
target is - because a path walk has none. Walks record under a sentinel so they stay out
of the target picker's history.
meshterm tx-optimize
Sweep a remote node's transmit power against a target and pick the lowest level that still gets through reliably.
| Option | What it does |
|---|---|
-p, --path SPEC |
Required. Forced path ending at the target (Repeater,Target, or 3d,f2). The hop before the target is the node being tuned. |
-n, --samples N |
Traces per TX level. Default 3. |
--step N |
Coarse sweep step. Default 3. |
--min N / --max N |
Bound the sweep (else the tx_opt_min / tx_opt_max preferences). |
--password TEXT |
Admin password for the tuned node; else the remembered one, else prompted. |
--apply / --no-apply |
Set the winner on the node. On by default. |
$ meshterm tx-optimize --path "Yagi-Repeater,Alice" --samples 5
tuning_node Yagi-Repeater
target Alice
path a1,d4
optimal_tx_dbm 22
target_snr_db +4.1
reliability 1.00
previous_tx_dbm 27
applied yes
TX_DBM TARGET_SNR_DB SUCCESSES SAMPLES
18 -1.2 2 5
21 +2.8 5 5
22 +4.1 5 5
The winner comes first because it is what you asked for; the per-level records follow so the
choice can be checked against the measurements it was made from. This transmits many times
(paced by the trace_cooldown_s preference) — it is the one command that is not a single
transmission.
Returns 5 when no trace reached the target at any level: nothing was measured, and the
node was left at its original power.
Other nodes
meshterm repeater-admin
Send one command to a remote repeater or room server over the mesh and print its reply.
meshterm repeater-admin NODE COMMAND... [--password TEXT]
| Argument / option | What it does |
|---|---|
NODE |
The remote contact's name. |
COMMAND... |
The text command to send, as the node's own CLI spells it. |
--password TEXT |
Admin password; else the one remembered from an interactive login. |
$ meshterm repeater-admin Yagi-Repeater get name
Yagi-Repeater
The reply is printed as the node sent it — its own text, and the whole answer. A node that
does not answer is not a failure (the command may well have landed), but there is nothing to
report, so it returns 5.
Logging in happens automatically from the remembered password; run the interactive flow once
to store one, or pass --password. A refused login clears the saved password and fails with
4.
MeshTerm itself
meshterm preferences
How MeshTerm behaves, as opposed to how the radio is configured. Reads nothing from the companion, transmits nothing, and works with no device attached.
| Subcommand | What it does |
|---|---|
show |
Every preference, its value, and its built-in default. |
get KEY |
One preference's value, bare. |
set KEY VALUE |
Change one preference. |
reset --yes |
Return every preference to its default. |
$ meshterm preferences show
PREFERENCE VALUE DEFAULT
trace_cooldown_s 5 5
flood_advert_cooldown_s 5 60
map_view_fraction 0.5 0.5
history_days 365 365
Values print in the form preferences set accepts back — no unit suffix on a number,
on/off for a boolean. Where VALUE differs from DEFAULT, this install has an override.
Overrides live in ~/.meshterm/preferences.yaml, which lists only what you have changed;
delete a line and the default takes over again.
meshterm about, about-author, discord, support
The four written pages, printed as plain text. about is what MeshTerm is and the terms it
ships under; about-author is who wrote it; discord is the community invite; support is
what keeps it going.
$ meshterm discord
Join the Discord
Questions, ideas, bug reports, and mesh talk.
• https://discord.gg/AZwe5Uvb3S
The menu draws a QR code beside each link; the scripted face prints the link alone.
meshterm platform
A diagnostic for which UI flavour a given invocation resolves to, and why.
$ meshterm platform
platform regular
platform_source default
flag -
env -
device_tree_model -
icons yes
icons_source no-console
icons is a separate question from the flavour, and the usual reason a Windows session looks
plainer than the screenshots.
meshterm specimen
Print the visual-language specimen — every mark, icon, colour scale and fold on one card.
This is the one command that keeps its colour, and it builds its own themed console to do
it. That is deliberate: the colour is the output. It is the font-and-palette acceptance
card on the PicoCalc console, and with --platform picocalc it previews that flavour from a
desktop. A monochrome specimen would test nothing.
Recipes
Watch a node and shout if it goes quiet. trace returning 5 means the walk ran and
nothing came home.
#!/usr/bin/env bash
target=${1:?usage: watch NODE}
meshterm trace --target "$target" > /dev/null
status=$? # capture it first: `if ! cmd` would have reset $? to 0
if [ "$status" -eq 5 ]; then
echo "$target did not answer" | mail -s "mesh alert" me@example.com
fi
Nightly config archive, keeping the path the command actually wrote:
out=$(meshterm config backup "$HOME/mesh/$(date +%F).toml") && echo "archived $out"
config backup prints the file it wrote, bare and one per line, so the path comes back to
the caller.
Fields out of a listing. Names are quoted, so a CSV-aware reader is the safe way in;
awk works when you split on the quotes rather than on spaces.
# every repeater's key
meshterm contacts | awk 'NR > 1 && $0 ~ /repeater/ { print $NF }'
# names alone, quotes stripped
meshterm contacts | awk -F'"' 'NR > 1 { print $2 }'
One value into a variable:
sf=$(meshterm config get radio_sf)
[ "$sf" -lt 9 ] && meshterm config set radio_sf 9
Capture a window of traffic to a file, with the progress noise left on the terminal:
meshterm monitor --seconds 300 > /var/log/mesh-$(date +%s).tsv
Sample a trace politely. A trace transmits exactly once per invocation by design; pace the repeats yourself:
for i in $(seq 5); do
meshterm trace --target Alice --path "3d,f2,3d"
sleep "$(meshterm preferences get trace_cooldown_s)"
done
Queue for someone who is offline, then chase it later:
id=$(meshterm courier queue Alice "call me" | awk '{print $2}')
# ... later ...
meshterm courier send "$id"
Cron-friendly quiet: --quiet suppresses console logging entirely, leaving only the
command's own output and any error line.
*/30 * * * * meshterm --quiet --profile yagi config advert --flood
What has no command
Some features have no scripted face, and that is the honest answer rather than a degraded one. Each of these is a live picture — its meaning is where things sit on a grid, how they move, and what colour they are — and none of that survives being turned into records.
| Feature | Why not, and what to use instead |
|---|---|
| Map | A drawing of braille cells whose nodes are told apart by colour. Stripped of colour to match the rest of the CLI it would be unreadable; left coloured it could not be piped anywhere useful. meshterm contacts lists the same nodes, coordinates and all. |
| Dashboard | A live overview that repaints every second. meshterm monitor captures the same traffic as records. |
| Live feed | Every packet as it arrives, newest first, with a viewer behind each row. meshterm monitor is the scripted tail. |
| Watchtower | A background sentinel over starred nodes; it exists to interrupt a session. Build the same alarm from meshterm trace's exit status (see Recipes). |
| Time machine | Braille charts over a switchable window. The underlying history is in the database --db points at. |
| Mesh walk | An evidence graph walked one node at a time. meshterm records and meshterm trace cover the walks it is built from. |
Everything else in the menu has a command, listed above.