Files
MeshTerm/docs/cookbook.md
T
Jean-Pierre MartineauandClaude Opus 5.5 b7a1ad47c2 The Oxford comma, always, the one-line description included
Every list of three or more takes the serial comma: the one-liner in
pyproject.toml, meshterm/__init__.py, and --help ("USB, Bluetooth, or TCP",
"Windows, macOS, and Linux"), the README, the changelog, the manuals, the
issue and PR templates, and six strings the app shows (the region-name
rule, a repeater setting's help, the diagnostics tool's description, and
the archive confirms). The Windows-console notice is rewrapped so its
comma keeps it inside 72 columns.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 21:28:00 -04:00

5.1 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 preferences set weekly_flood_advert on   # flood an advert once a week, when quiet

# Passive capture window (records to history; transmits nothing)
meshterm monitor --seconds 60

Global options — --profile/-p, --port, --ble, --ble-pin, --tcp, --spi, --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