Files
MeshTerm/docs/cookbook.md
T
Jean-Pierre MartineauandClaude Opus 5 5fbba275f6 The manuals describe what the code and scripts do today
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>
2026-09-21 11:28:24 -04:00

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