Every manual was read against the code, the scripts and the upstream sources, and the samples in docs/cli.md were recaptured under --mock where they had drifted. The one a newcomer would hit first: config.example.toml set default_profile to a COM5 profile. Copied verbatim, as configuration.md says to, it broke every device command on a machine with no COM5. default_profile is commented out now, so the copied file leaves discovery working. default_tx_power goes from both, because nothing reads it. docs/cli.md: config show has 22 settings and preferences show 21, not 20 and 8; monitor's blocks have no blank line between them; the diagnostics sample is labelled as a real-radio example with absolute instants and every table; an unknown key exits 1; devices, role and records describe the values they really produce; no maintainer paths; and the "used to" passages describe the present, since a first-time reader never saw the past. picocalc.md: the Calculinux image carries a build stamp, so the gunzip and dd lines take a wildcard; the front SD slot stays empty on first boot; masking wifi-kick is what stops it, and time-sync is disabled with it; updates run the scripts from the pulled checkout with TMPDIR set; the tested list names only what a test checks; git ships in the base image; a bare meshterm shows the splash, and -p picocalc skips it. uconsole.md: an AIO v2 needs MESHCORE_EN_PINS=27 whichever runtime is installed; the bookworm paragraph states what upstream actually ships; the bridge shares the key but keeps its own contacts and radio settings; the defaults are the US/Canada preset; Step 7 downloads what it installs; updating ends with a restart; no claim of test coverage the suite does not have. terminals.md, features.md, hardware.md, cookbook.md, configuration.md and the scripts READMEs get the smaller corrections their audits found. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
5.2 KiB
The CLI cookbook
Common one-liners, by the thing you are trying to do. The command line is the
full manual — every command, every option, both output faces, the exit statuses — and its
own Recipes section goes further than this one, into jq pipelines and
shell loops.
Nearly every menu option is also a subcommand — ideal for scripting, cron, and bots. The
live pictures stay in the menu, where their meaning is (the map, dashboard, live feed,
watchtower and mesh walk); everything else has a command, and every command speaks
--json. docs/cli.md is the full manual: every command and option,
what each one prints on both faces, and the exit statuses. A taste:
# Trace — a trace transmits exactly once; run it again to sample more.
meshterm trace --target Alice --profile yagi
# Force a route through specific repeaters (MeshCore-app style): comma-separated
# contact names and/or hex key prefixes, mixed freely. Blank lets the device route.
meshterm trace --target Alice --path "3d,f2,3d"
meshterm trace --target Alice --path "3d,Bravo-Repeater,f2"
# Walk a composed circuit with no target at all — out and back your own way
meshterm trace-path --path "3d,f2,3d"
# Sweep and apply a remote node's TX power
meshterm tx-optimize --path "Bravo-Repeater,Alice" --samples 6 --step 3 --apply
# Messaging: the live transcript is a menu screen; the CLI takes a subcommand
meshterm chat send --to Alice "on my way" # direct message
meshterm chat send --channel 0 "net in 5" # channel broadcast
meshterm chat history --to Alice
meshterm chat list
# Store-and-forward: queue for a contact that's offline right now
meshterm courier queue Alice "ping me when you're back" --at 18:30
meshterm courier list # the outbox — waiting and finished
meshterm courier send 3 # force one delivery attempt now
# Remote repeater admin (one transmission per invocation). --password is needed
# until an interactive login has stored one.
meshterm repeater-admin Bravo-Repeater "get name" --password YOUR-ADMIN-PASSWORD
# Device configuration: view, set, back up, restore
meshterm config # show all current settings, one `key value` per line
meshterm config get name # just the value, ready for $(...)
meshterm config set radio_sf 9 # change one setting
meshterm config backup node.toml # archive every setting to TOML
meshterm config restore node.toml --dry-run
meshterm config advert-cadence 2 # auto-advert to neighbours every 2 h (0 = off)
meshterm config advert-cadence 24 --flood # flood the wider mesh daily
# Passive capture window (records to history; transmits nothing)
meshterm monitor --seconds 60
Global options — --profile/-p, --port, --ble, --ble-pin, --tcp, --mock,
--db, --json, --absolute, --quiet/-q, --platform — may be typed before or
after the subcommand: meshterm contacts --json and meshterm --json contacts are the
same run.
Two output faces
(The short version — docs/cli.md has the whole of it.)
The plain face is for a person at a prompt. It prints like a standard Unix utility —
no colour, no borders, one record per line, nothing wrapped except the four written
pages (about, about-author, discord, support), which wrap at 72 cells — and it is
allowed to be comfortable about it: listings are ps-style aligned records with bare names
(alignment is the delimiter), times are relative ages (now, 5m, never), and a
route is drawn with arrows — MockCompanion (00) → Yagi-Repeater (a1) → Alice (d4).
--absolute swaps every age back for an ISO-8601 instant. A path, the spec --path
takes back, stays comma-separated hex. - is the one token for absent. Errors,
acknowledgements and progress all go to stderr, so a redirect catches only the answer.
The JSON face is the machine contract, and --json works on every command:
$ meshterm contacts --json | jq -r '.[] | select(.node.type == "repeater") | .node.key'
b2c3d4e500000000000000000000000000000000000000000000000000000000
a1b2c3d400000000000000000000000000000000000000000000000000000000
No envelope — an array for a listing, an object for a set of facts. One compact line;
monitor and chat listen stream one document per record. Values are typed, absent is
null and never an omitted key, and timestamps are always UTC to the second regardless of
--absolute. --json changes the rendering, never the report: same records, same exit
status.
Anything structural should go through --json and jq. The plain face is for looking at.
Exit status
0 success · 1 failure · 2 usage error · 3 no device found (nothing was
transmitted) · 4 the device was reached but the operation failed · 5 nothing to
report. The table with its full wording is printed under meshterm --help and explained
in docs/cli.md.
5 is the one worth knowing about: it lets a script tell "found nothing" from "worked"
without counting output lines.
if meshterm contacts > contacts.txt; then
echo "$(($(wc -l < contacts.txt) - 1)) contacts" # minus the header
elif [ $? -eq 5 ]; then
echo "no contacts yet"
fi