Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Invoking the CLI

Selecting JSON

--output human|json is a global option. It defaults to human, is case-sensitive, and may appear at any depth of the command path, with a space or =:

mostro-cli --output json order list
mostro-cli order --output=json list
mostro-cli order list --output json

All three are equivalent. Rules a wrapper must respect:

SituationResult
Exactly one --output jsonJSON mode
No --output, or one --output humanHuman mode
--output given twice, even with the same valueExit 2, empty stdout, one line on stderr
--output with no value or an unknown valueExit 2, empty stdout, one line on stderr
--output json appears inside another option’s value (--currency=--output=json)Not an output selection
--output after --Not an output selection; an earlier --output json still holds
--help / --versionConventional text and exit 0, even with --output json

So: put --output json exactly once, first, and never pass user-controlled text where an option is expected. Build argv as an array, never by string concatenation through a shell.

Confirmation: --yes

Commands that publish a request which changes something (order new, order take-sell, order take-buy, order add-invoice, bond add-invoice, order fiat-sent, order release, order cancel, dispute open, order rate) ask for confirmation in human mode. In JSON mode there is no prompt; instead --yes is mandatory:

mostro-cli --output json order cancel --order 00000000-0000-0000-0000-000000000001
# exit 2, invalid_arguments: nothing was done

mostro-cli --output json order cancel --order 00000000-0000-0000-0000-000000000001 --yes

--yes is the caller’s statement that the user consented. An agent should only add it after it has obtained that consent (see Guide for AI agents).

order sync writes only local rows and publishes nothing; it does not take --yes. Neither do the local commands identity init, identity show and order mine.

Invoice on standard input

The four commands that take an invoice (order new, order take-sell, order add-invoice, bond add-invoice) also accept --invoice - (or --invoice=-): the invoice is then read from standard input instead of the command line, where other local users could see it in the process list.

printf '%s\n' "$INVOICE" | mostro-cli --output json order add-invoice \
  --order 00000000-0000-0000-0000-000000000001 --invoice - --yes
RuleOtherwise
--yes is giveninvalid_arguments, exit 2, stdin not read
stdin is not a terminalinvalid_arguments, exit 2, stdin not read
At most 8192 bytes of UTF-8 holding exactly one non-empty line (ASCII whitespace around it is trimmed), then end of input: close stdin after the lineinvalid_arguments with reason: invalid_invoice, exit 2, before any effect

The line is then validated like a literal --invoice value. The error message is fixed text and never contains what was read. mostro-cli schema marks these properties with "x-stdin": "-".

Streams

With JSON selected, a controlled outcome is:

  • stdout: exactly one UTF-8 JSON object followed by \n. No banner, progress, colour or table before or after it.
  • stderr: optional diagnostics in fixed English prose. With --verbose (-v, a root option) a command adds one line such as verbose: order.take-sell ok or verbose: order.release reply_timeout. Diagnostics never contain keys, invoices, relay URLs or argument values. Do not parse stderr.
  • stdin: read only for --invoice - (above); otherwise never read.

Exit codes

ExitMeaningStdout
0status is okEnvelope
2error.code is invalid_arguments or output_not_supportedEnvelope (when JSON intent was unambiguous)
2Bad or duplicate --outputEmpty; stderr line
1Any other error, and every uncertainEnvelope
1Serialization or write failureAn internal_error envelope if possible, otherwise empty
otherCrash or killedNo guarantee

The exit code is a summary. The envelope is the detail: uncertain exits 1 like an error, but it does not mean “nothing happened”. Always read status.

If stdout is empty or not one JSON object, treat the run as unknown: for a read, retrying is fine; for a write, check before retrying (see Recovering from uncertain outcomes).

Argument errors are still JSON

Once --output json was selected unambiguously, an argument error is reported as an envelope, even if the command itself cannot be recognised:

mostro-cli --output json unknowncmd
{
  "schema_version": "1",
  "command": null,
  "status": "error",
  "data": null,
  "error": {
    "code": "invalid_arguments",
    "message": "The command arguments are invalid."
  },
  "warnings": [],
  "meta": {
    "publication": "not_attempted",
    "daemon_acceptance": "unknown",
    "persistence": "not_attempted",
    "snapshot": null
  }
}

File: examples/general/unknown_command.json · exit 2 · captured

command is null because the command could not be resolved. A recognised command keeps its name even when its arguments are wrong:

mostro-cli --output json order list --side invalid
{
  "schema_version": "1",
  "command": "order.list",
  "status": "error",
  "data": null,
  "error": {
    "code": "invalid_arguments",
    "message": "The command arguments are invalid."
  },
  "warnings": [],
  "meta": {
    "publication": "not_applicable",
    "daemon_acceptance": "not_applicable",
    "persistence": "not_applicable",
    "snapshot": null
  }
}

File: examples/order.list/invalid_side.json · exit 2 · fixture

The error never echoes the offending value; your wrapper knows what it passed.

Removed spellings

The JSON-capable commands replaced old spellings (listorders, neworder, takesell, getdm…). The old names are gone without aliases and fail as an unknown command (command: null, invalid_arguments). See Migration.

Timeouts you should allow for

PhaseBudget
Connect to relays10 s
Node-info probe (protocol version, PoW)3 s, best effort
Public read until every relay sent EOSE15 s
Wait for the node’s reply to a request--reply-timeout, 15 s by default
Relay cleanup1 s (overrun is only a warning)

With the default reply deadline, a wrapper timeout of 45 seconds per run is comfortably above the worst case; add whatever you add to --reply-timeout. If you kill the process earlier, treat a write as uncertain.

--reply-timeout SECONDS

A global option like --output, accepted at any depth: 5 to 300 seconds, default 15. It is the deadline from publishing the request to the node’s reply for the commands that wait for one: order new, order take-sell, order take-buy, order add-invoice, order fiat-sent, order release, order cancel, order info, dispute open, order rate and bond add-invoice. Other commands accept it and ignore it; the public reads keep their own limits.

mostro-cli --output json --reply-timeout 60 order take-buy \
  --order 00000000-0000-0000-0000-000000000001 --yes

A reply after the deadline is reply_timeout as before (uncertain for the writes, error for order info), and the CLI never retries. A value outside the range is invalid_arguments, exit 2. mostro-cli schema lists both global options with their range, default and the commands they apply to (data.global_options).

Running several commands

The CLI makes no promise about two write commands running at the same time against one data directory (both may reserve trade indexes and update rows). Run write commands one at a time per data directory; queue them in your wrapper. order list and schema never touch the data directory; order info, message list, order mine and identity show only read it. identity init creates it.