From dff8edf476c6f2dbf1d41f21cf5b0d3a3b812895 Mon Sep 17 00:00:00 2001 From: grunch Date: Thu, 20 Aug 2026 16:11:58 -0300 Subject: [PATCH 1/2] docs(readme): fix instructions that block a first-time user Verified the README against the code and the running binary (v0.16.0). Three of the documented flows do not work as written, plus several statements no longer match the implementation. Blocking fixes: - Remove the hard-coded example Mostro pubkey. It pointed at an instance that publishes nothing, so a new user following the Quick start saw an empty orderbook and no way to tell why. Mostro is a federation and any single pubkey can go dead, so the README now explains how to obtain one instead of shipping one: ask the operator, discover instances via their kind-38385 info event, or run your own daemon (MostroP2P/mostro). - Rewrite "Restoring on a new machine". The old flow had the user hand-create ~/.mcli/mcli.db with only a `users` table, but db::connect creates the schema only when the file is absent, so `orders` was never created and the first trade command died with `no such table: orders`. The DB is now created by the CLI and the mnemonic overwritten afterwards. The trade-index sync is also promoted from "optional" to required, since a restored DB restarts at index 1 and Mostro rejects a replayed index. - Document that global flags must precede the subcommand. They are not `global = true` in clap, so the FAQ's advice to "pass -m " failed with `error: unexpected argument '-m' found`. Accuracy fixes: - Rust 1.74 -> 1.89, matching rust-toolchain.toml. - Drop the stale "Directory ... created." line from the first-run output. - RUST_LOG only takes effect together with -v; the logger is initialised nowhere else. - sendadmindmattach is not in is_admin_command and needs no ADMIN_NSEC; the command reference claimed otherwise, contradicting its own Setup section. - --secret has a -s short form. New explanations: - The CLI polls and exits; it does not stay connected waiting for the counterpart. Added a Quick start section and a FAQ entry. - Pending orders expire (expiration_hours on the node's info event). - FAQ entries for `no such table: orders`, rejected orders after a restore, and an expanded "listorders returns nothing" checklist. --- README.md | 136 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 101 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 3a3708f..4ba89a3 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,8 @@ A command-line client for [Mostro](https://github.com/MostroP2P/mostro), the P2P ## Requirements -- **Rust** 1.74 or higher (recommended — anything newer than 1.64 should compile). +- **Rust** 1.89 or higher. The repository pins this in `rust-toolchain.toml`, so a `rustup` install picks it up automatically when you build from source. +- **A Mostro node to connect to** — its pubkey is mandatory configuration. See [Choosing a Mostro instance](#choosing-a-mostro-instance). - A **Lightning wallet** to pay/receive hold invoices and regular invoices. - Network access to public Nostr relays. @@ -130,10 +131,22 @@ The mnemonic-based user and the admin key are completely independent. You can ru | Variable | CLI flag | Description | |---|---|---| | `POW` | `-p, --pow` | Proof-of-work difficulty (bits) required by the Mostro instance for incoming events. Set this if the daemon enforces PoW. | -| `SECRET` | `--secret` | Use secret/anonymous mode for the inner event tuple (advanced, hides trade index from gift-wrap inner). | +| `SECRET` | `-s, --secret` | Use secret/anonymous mode for the inner event tuple (advanced, hides trade index from gift-wrap inner). | | `TRANSPORT` | `-t, --transport` | Wire transport: `gift-wrap` (protocol v1) or `nip44` (protocol v2). Leave unset to auto-detect from the instance's info event. | | `ADMIN_NSEC` | — | Admin/solver private key in `nsec1...` or hex format. Only read when an `adm*` command is invoked. | -| `RUST_LOG` | `-v, --verbose` | Verbose logging. The `-v` flag sets `RUST_LOG=info` for you. | +| `RUST_LOG` | `-v, --verbose` | Log level. **Only takes effect together with `-v`** — the logger is initialised solely when `-v` is passed, so exporting `RUST_LOG` on its own produces no output. `-v` sets `RUST_LOG=info` for you. | + +### Choosing a Mostro instance + +`mostro-cli` is only a client: it does not ship with a default node, and this README deliberately does not hard-code one. Mostro is a federation of independently operated daemons — any given instance can go offline, change its pubkey, or stop serving your currency at any time, so a pubkey pasted here would eventually send you to a dead node. + +**Use the pubkey of the Mostro node you trust.** Ways to get one: + +- **Ask the operator.** If you already trade on a given instance (through a mobile client, a community, or a friend), ask for its `npub` and the relays it publishes to. +- **Discover instances on Nostr.** Every running daemon publishes an addressable info event of **kind `38385`**, tagged with its `mostro_version`, `protocol_version`, `fee`, `pow` and `max_order_amount`. Querying a relay for that kind lists the instances it knows about, and the event's author pubkey is the value you need for `MOSTRO_PUBKEY`. Orders themselves are kind `38383` events authored by the same pubkey. Any Nostr client or CLI that can filter by kind will do. +- **Run your own.** The daemon is open source: [github.com/MostroP2P/mostro](https://github.com/MostroP2P/mostro). Running it yourself is also the recommended way to test the whole flow (including on testnet) without touching a stranger's node — its config file holds the pubkey and relays you then feed to `mostro-cli`. + +Whichever you pick, `RELAYS` must include at least one relay that the instance actually publishes to, otherwise the CLI connects successfully and simply sees nothing. ### Suggested setup @@ -141,9 +154,9 @@ Create a small env file you `source` before using the CLI: ```bash # ~/.config/mostro/env.sh (chmod 600) -export MOSTRO_PUBKEY="npub1ykvsmrmw2hk7jgxgy64zr8tfkx4nnjhq9eyfxdlg3caha3ph0skq6jr3z0" -export RELAYS="wss://relay.mostro.network,wss://relay.damus.io" -# export POW=10 +export MOSTRO_PUBKEY="" +export RELAYS="wss://,wss://" +# export POW=10 # only if the node enforces proof of work # export ADMIN_NSEC=nsec1... # only if you're an admin/solver ``` @@ -152,7 +165,7 @@ source ~/.config/mostro/env.sh mostro-cli listorders ``` -> Pubkeys above are illustrative — replace them with the actual Mostro instance and relays you want to trade on. +> Replace both placeholders with the real values of the instance you want to trade on — see [Choosing a Mostro instance](#choosing-a-mostro-instance). Nothing works until `MOSTRO_PUBKEY` points at a live node. ### About `.env` files @@ -162,8 +175,8 @@ If you prefer keeping settings in a `.env`-style file, export them yourself befo ```bash # ~/.config/mostro/.env (chmod 600) -MOSTRO_PUBKEY=npub1ykvsmrmw2hk7jgxgy64zr8tfkx4nnjhq9eyfxdlg3caha3ph0skq6jr3z0 -RELAYS=wss://relay.mostro.network,wss://relay.damus.io +MOSTRO_PUBKEY= +RELAYS=wss:// POW=0 ``` @@ -178,6 +191,13 @@ mostro-cli listorders ## Quick start +Export your configuration first — every command below fails immediately without it: + +```bash +export MOSTRO_PUBKEY="" +export RELAYS="wss://" +``` + ```bash # 1. List open orders mostro-cli listorders @@ -189,7 +209,7 @@ mostro-cli listorders -k buy -c ves -s pending # 3. Inspect details for specific orders mostro-cli ordersinfo -o -o -# 4. Create your own order (sell 1000 ARS, range allowed) +# 4. Create your own order (sell 1000-10000 ARS at market price) mostro-cli neworder -k sell -c ars -f 1000-10000 -m "face to face" # 5. Take someone else's sell order @@ -202,12 +222,25 @@ mostro-cli getdm --since 60 On the very first run you will see something like: ``` -Directory /home/user/.mcli created. Creating database file with orders table... User created with pubkey: ``` -Write down or back up the database / mnemonic before doing anything else. +Write down or back up the mnemonic before doing anything else — see [Backup, recovery and multi-device](#backup-recovery-and-multi-device). + +### The CLI does not stay connected — you poll + +This is the biggest difference from a mobile Mostro client. Each `mostro-cli` invocation connects to the relays, sends (or reads) what you asked for, prints the result and exits. It does **not** keep running to notify you when your counterpart acts. + +So a trade is driven by you re-running `getdm`: + +```bash +mostro-cli getdm --since 60 # everything Mostro sent you in the last 60 minutes +``` + +Run it after every step where you are waiting on the other side — an order being taken, an invoice arriving, fiat being marked as sent, sats being released. `--since` defaults to 30 minutes; widen it if you have been away. + +Pending orders also expire (24 hours on a typical instance — the exact value is the `expiration_hours` tag of the node's info event). If nobody takes your order before then, it disappears from the orderbook and any locked sats are returned; you can pass `--expiration-days N` to `neworder` to request a different window. --- @@ -380,7 +413,7 @@ You can be a regular user and a solver on the same machine; just keep both walle - `admaddsolver`, `admtakedispute` - `admsenddm`, `getadmindm` - For non-admin commands, `ADMIN_NSEC` is ignored. + For every other command, `ADMIN_NSEC` is ignored. Note that `sendadmindmattach` is **not** on this list despite its name: it signs with the trade key of the order you pass in, so it works without `ADMIN_NSEC` set. ### Admin commands @@ -435,32 +468,41 @@ Store the 12 words offline (paper, metal, encrypted vault). Do **not** commit th ### Restoring on a new machine +> **Let the CLI create the database — do not hand-craft it.** `mostro-cli` only creates its tables when `~/.mcli/mcli.db` does not yet exist. If you pre-create that file yourself with just a `users` table, the `orders` table is never created, `listorders` still appears to work, and the first command that touches an order fails with `no such table: orders`. Always run the CLI once first, then overwrite the mnemonic. + 1. Install `mostro-cli` on the new machine. -2. **Before running any command**, create `~/.mcli/mcli.db` with your mnemonic pre-inserted, or stop after the first auto-init and manually overwrite the row in `users`. A simple way using sqlite3: + +2. **Run any command once** so the CLI builds a complete, correctly-permissioned database. It will generate a throwaway mnemonic that you are about to replace: ```bash - mkdir -p ~/.mcli - sqlite3 ~/.mcli/mcli.db <<'SQL' - CREATE TABLE IF NOT EXISTS users ( - i0_pubkey char(64) PRIMARY KEY, - mnemonic TEXT, - last_trade_index INTEGER, - created_at INTEGER - ); - SQL - # Then insert your mnemonic (replace the values): - sqlite3 ~/.mcli/mcli.db "INSERT INTO users (i0_pubkey, mnemonic, created_at) VALUES ('', '', strftime('%s','now'));" + mostro-cli listorders ``` -3. Run `mostro-cli restore`. This asks Mostro to resend the state of all your active orders and disputes so the new machine can rejoin the conversations. +3. **Overwrite the mnemonic** with your backed-up 12 words and clear the trade index that belonged to the throwaway user: -4. (Optional) sync the trade index: + ```bash + sqlite3 ~/.mcli/mcli.db "UPDATE users SET mnemonic = '', last_trade_index = NULL;" + ``` + + The `i0_pubkey` column is only a primary key for display — every identity and trade key is derived from the `mnemonic` column at runtime, so a stale value there is harmless. + +4. **Sync the trade index. This step is required, not optional:** ```bash mostro-cli getlasttradeindex ``` -> A friendlier `import-mnemonic` subcommand may land in the future. Until then, the manual flow above is the supported path. + Trade keys are derived from an incrementing index, and the daemon rejects an index it has already seen. A freshly restored database starts back at index 1, so without this sync your next order is refused. The command asks Mostro for your real last index and writes it back to the local database. + +5. **Recover your open trades:** + + ```bash + mostro-cli restore + ``` + + This asks Mostro to resend the state of all your active orders and disputes so the new machine can rejoin the conversations. + +> A friendlier `import-mnemonic` subcommand may land in the future. Until then, the flow above is the supported path. ### Backing up the whole DB @@ -506,22 +548,31 @@ Every command supports `-h, --help`. The list below is a one-line summary; run ` - `admtakedispute -d ` - `admaddsolver -n ` - `admsenddm -p -m ` -- `sendadmindmattach -p -o -f ` - `getadmindm [--since ] [--from-user]` +### Solver tooling (no `ADMIN_NSEC` needed) +- `sendadmindmattach -p -o -f ` — send an encrypted file attachment (uploaded to a Blossom server) over the order's trade key. + ### Identity / recovery - `restore` — re-sync active orders and disputes from Mostro. - `getlasttradeindex` — fetch your last known trade index from Mostro. - `getlasttradeprivkey` — show the private key for the last trade index (advanced). ### Global flags -- `-v, --verbose` — enable info logging. + +> **These must come *before* the subcommand.** They are parsed on the top-level command, so `mostro-cli listorders -m ` fails with `error: unexpected argument '-m' found`. Write `mostro-cli -m listorders` instead. This also avoids clashing with subcommand flags that reuse the same letters (`-m` is `--payment-method` on `neworder` and `--message` on `senddm`, `-p` is `--premium` on `neworder` and `--pubkey` on the DM commands). + +- `-v, --verbose` — enable info logging (also the only way to make `RUST_LOG` take effect). - `-m, --mostropubkey ` — overrides `MOSTRO_PUBKEY`. - `-r, --relays ` — overrides `RELAYS`. - `-p, --pow ` — overrides `POW`. -- `--secret` — secret mode for inner event tuple. +- `-s, --secret` — secret mode for inner event tuple. - `-t, --transport ` — overrides `TRANSPORT` (auto-detected when unset). +```bash +mostro-cli -m -r wss:// listorders -k sell -c usd +``` + --- ## Files, environment and where things live @@ -541,7 +592,7 @@ Environment variables read by the CLI: | `SECRET` | Optional — `true` enables secret-mode inner tuple. | | `TRANSPORT` | Optional — `gift-wrap` or `nip44`; auto-detected when unset. | | `ADMIN_NSEC` | Optional — only used by admin commands. | -| `RUST_LOG` | Optional — verbose logging level. | +| `RUST_LOG` | Optional — log level, but only honoured when `-v` is also passed (the logger is initialised only by `-v`). | The database stores **secret material** (your mnemonic). Treat `~/.mcli/mcli.db` like a wallet seed file: @@ -557,18 +608,33 @@ The database stores **secret material** (your mnemonic). Treat `~/.mcli/mcli.db` **"How do I generate my keys?"** — You don't. There is no key-generation step and no need for tools like `rana`. The first command you run creates `~/.mcli/mcli.db` with a fresh BIP39 mnemonic; every identity and trade key is derived from it (NIP-06). Back the mnemonic up — see [Backup, recovery and multi-device](#backup-recovery-and-multi-device). -**`MOSTRO_PUBKEY not set`** — Export it or pass `-m `. Mind the underscore: only `MOSTRO_PUBKEY` is read, `MOSTROPUBKEY` is not. +**`MOSTRO_PUBKEY not set`** — Export it, or pass `-m ` **before** the subcommand (`mostro-cli -m listorders`, not `mostro-cli listorders -m ` — see [Global flags](#global-flags)). Mind the underscore: only `MOSTRO_PUBKEY` is read, `MOSTROPUBKEY` is not. If you don't have a node pubkey yet, see [Choosing a Mostro instance](#choosing-a-mostro-instance). + +**`RELAYS not set`** — `RELAYS` is required too, and that exact name is the one the CLI reads. Export it (comma-separated `wss://` URLs) or pass `-r ` before the subcommand. -**`RELAYS not set`** — `RELAYS` is required too, and that exact name is the one the CLI reads. Export it (comma-separated `wss://` URLs) or pass `-r `. +**`error: unexpected argument '-m' found`** (or `-r`, `-p`, `-t`, `-v`) — Global flags belong before the subcommand: `mostro-cli -m listorders`. Placed after it, clap parses them against the subcommand, which either rejects them or silently means something else. See [Global flags](#global-flags). **My `.env` file is ignored** — It is not loaded automatically; the CLI has no dotenv support. Use `set -a; source .env; set +a` first — see [About `.env` files](#about-env-files). **`ADMIN_NSEC not set (required for admin commands)`** — Only admin subcommands need it. Export it in the same shell, or prefix the command: `ADMIN_NSEC=nsec1... mostro-cli admsettle ...`. -**`listorders` returns nothing** — Check `RELAYS` connectivity (`websocat wss://relay.mostro.network`), confirm `MOSTRO_PUBKEY` matches the instance you actually want to trade on, and try `--verbose` for relay logs. +**`listorders` returns nothing** — Almost always a configuration problem rather than an empty orderbook. In order: + +1. **Is `MOSTRO_PUBKEY` a live instance?** A node that has been shut down, or a pubkey copied from an outdated guide, produces exactly this: a clean connection and zero orders. Confirm the pubkey with its operator, or look for its kind-`38385` info event on the relay — see [Choosing a Mostro instance](#choosing-a-mostro-instance). +2. **Do your relays carry that instance?** The node only publishes to the relays it is configured with. A perfectly healthy relay that the node never writes to will show nothing. +3. **Is the relay reachable?** Test with e.g. `websocat wss://`. +4. **Are your filters too narrow?** `-k`, `-c` and `-s` combine; drop them and retry. + +Run with `-v` (before the subcommand) for relay-level logs. **Mostro rejects events / no reply** — The instance may require `POW`. Ask the operator what difficulty is enforced and export `POW=`. +**`no such table: orders`** — Your `~/.mcli/mcli.db` was created by something other than the CLI (usually by hand-crafting it while restoring a mnemonic). The CLI only creates its tables when that file does not exist, so a pre-made database is missing `orders`. Delete it and follow [Restoring on a new machine](#restoring-on-a-new-machine) — but back up the mnemonic first: `sqlite3 ~/.mcli/mcli.db "SELECT mnemonic FROM users;"`. + +**Mostro rejects my order after restoring on a new machine** — You very likely skipped the trade-index sync. Run `mostro-cli getlasttradeindex`; see [Restoring on a new machine](#restoring-on-a-new-machine). + +**Nothing happens / I'm waiting for my counterpart** — The CLI does not stay connected. Re-run `mostro-cli getdm --since ` to pull new messages; see [The CLI does not stay connected — you poll](#the-cli-does-not-stay-connected--you-poll). + **Lost the database / changed machine** — See [Backup, recovery and multi-device](#backup-recovery-and-multi-device). Without the mnemonic, active orders/disputes cannot be recovered. **Multiple orders in flight** — Each gets its own derived trade key. The DB tracks them; just keep using order IDs. From c43cb053a5309634243b0979f3b21f913404e91b Mon Sep 17 00:00:00 2001 From: grunch Date: Thu, 20 Aug 2026 16:33:08 -0300 Subject: [PATCH 2/2] docs(readme): address Codex and CodeRabbit review findings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All seven findings verified against the code before applying. Codex P1 — `restore` does not persist orders. `Action::RestoreSession` in src/parser/dms.rs only prints the IDs, trade indexes and statuses Mostro returns; nothing is written to the local `orders` table, so release/cancel/addinvoice/senddm still fail at `Order::get_by_id`. The previous wording promised the new machine could "rejoin the conversations", which was wrong. The section is restructured: copying `~/.mcli/mcli.db` is now presented first as the only way to continue an in-flight trade, and the mnemonic-only path carries an explicit limitation note plus a FAQ entry. Codex P2 — `-v` overwrites `RUST_LOG`. get_env_var calls `set_var("RUST_LOG", "info")` unconditionally (src/cli.rs:359-361), so `RUST_LOG=debug -v` still logs at info. The previous phrasing ("only takes effect together with -v") implied the level was configurable. It is not; documented as such in both tables and in the flag list. CodeRabbit — MSRV inconsistency. .github/workflows/ci.yml builds at 1.86.0 while rust-toolchain.toml pins 1.89.0 and Cargo.toml declared no `rust-version`. README now states 1.86 as the floor and explains that a clone fetches the pinned 1.89; `rust-version = "1.86"` added to Cargo.toml so cargo enforces the same number CI tests. CodeRabbit — restore step ran before configuration. `MOSTRO_PUBKEY` and `RELAYS` are validated before `connect()` creates the database (#179), so the bootstrap command aborted with no database on a fresh machine. Added the export step ahead of it. CodeRabbit — mnemonic exposed in argv and shell history. Replaced the inline `sqlite3 "UPDATE ... '<12 words>'"` with `read -rs` into a variable expanded inside a heredoc, so the words reach sqlite3 on stdin and never appear in `argv` or history. CodeRabbit — stale `i0_pubkey` after restore. Nothing derives from that column and `User::save` matches on the stored value, so the database stays self-consistent; documented as a non-authoritative field, with an optional realignment step using the identity pubkey that `restore` prints. CodeRabbit — "Nothing works until MOSTRO_PUBKEY..." overstated, since `--version` and `--help` do not need configuration. Narrowed to networked commands. --- Cargo.toml | 1 + README.md | 63 ++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 365155f..9b3086d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ name = "mostro-cli" version = "0.16.0" edition = "2021" +rust-version = "1.86" license = "MIT" authors = [ "Francisco Calderón ", diff --git a/README.md b/README.md index 4ba89a3..9d2edbd 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ A command-line client for [Mostro](https://github.com/MostroP2P/mostro), the P2P ## Requirements -- **Rust** 1.89 or higher. The repository pins this in `rust-toolchain.toml`, so a `rustup` install picks it up automatically when you build from source. +- **Rust 1.86 or higher.** That is the minimum the CI verifies a build against. Note that `rust-toolchain.toml` pins `1.89.0` as the development toolchain, so building from a clone with `rustup` installed will fetch 1.89 regardless; 1.86 is the floor for `cargo install mostro-cli`. - **A Mostro node to connect to** — its pubkey is mandatory configuration. See [Choosing a Mostro instance](#choosing-a-mostro-instance). - A **Lightning wallet** to pay/receive hold invoices and regular invoices. - Network access to public Nostr relays. @@ -134,7 +134,7 @@ The mnemonic-based user and the admin key are completely independent. You can ru | `SECRET` | `-s, --secret` | Use secret/anonymous mode for the inner event tuple (advanced, hides trade index from gift-wrap inner). | | `TRANSPORT` | `-t, --transport` | Wire transport: `gift-wrap` (protocol v1) or `nip44` (protocol v2). Leave unset to auto-detect from the instance's info event. | | `ADMIN_NSEC` | — | Admin/solver private key in `nsec1...` or hex format. Only read when an `adm*` command is invoked. | -| `RUST_LOG` | `-v, --verbose` | Log level. **Only takes effect together with `-v`** — the logger is initialised solely when `-v` is passed, so exporting `RUST_LOG` on its own produces no output. `-v` sets `RUST_LOG=info` for you. | +| `RUST_LOG` | `-v, --verbose` | **Not actually configurable.** The logger is initialised only when `-v` is passed, and `-v` overwrites `RUST_LOG` with `info` first. So `RUST_LOG` alone produces no output, and `RUST_LOG=debug -v` still logs at `info`. `-v` is the only available level. | ### Choosing a Mostro instance @@ -165,7 +165,7 @@ source ~/.config/mostro/env.sh mostro-cli listorders ``` -> Replace both placeholders with the real values of the instance you want to trade on — see [Choosing a Mostro instance](#choosing-a-mostro-instance). Nothing works until `MOSTRO_PUBKEY` points at a live node. +> Replace both placeholders with the real values of the instance you want to trade on — see [Choosing a Mostro instance](#choosing-a-mostro-instance). No networked command works until `MOSTRO_PUBKEY` points at a live node (`--version` and `--help` are the only exceptions). ### About `.env` files @@ -466,27 +466,46 @@ sqlite3 ~/.mcli/mcli.db "SELECT mnemonic FROM users;" Store the 12 words offline (paper, metal, encrypted vault). Do **not** commit them to git or put them in plain text on shared machines. -### Restoring on a new machine +### Moving to a new machine: copy the database + +**If you have trades in flight, copy `~/.mcli/mcli.db` to the new machine.** This is the only path that lets you *continue* those trades, because commands like `release`, `cancel`, `addinvoice` and `senddm` look the order up in the local `orders` table and fail without it. The file contains no funds — only your mnemonic and cached order metadata — but it does contain the mnemonic, so move it over a secure channel and keep the `0600` permissions. + +### Restoring from the mnemonic alone + +Use this when the database is gone. It recovers your **identity**, not your local order history — read the limitation at the end of this section before relying on it mid-trade. > **Let the CLI create the database — do not hand-craft it.** `mostro-cli` only creates its tables when `~/.mcli/mcli.db` does not yet exist. If you pre-create that file yourself with just a `users` table, the `orders` table is never created, `listorders` still appears to work, and the first command that touches an order fails with `no such table: orders`. Always run the CLI once first, then overwrite the mnemonic. 1. Install `mostro-cli` on the new machine. -2. **Run any command once** so the CLI builds a complete, correctly-permissioned database. It will generate a throwaway mnemonic that you are about to replace: +2. **Configure the CLI first.** `MOSTRO_PUBKEY` and `RELAYS` are validated *before* the database is created, so without them the next step aborts and no database appears: + + ```bash + export MOSTRO_PUBKEY="" + export RELAYS="wss://" + ``` + +3. **Run any command once** so the CLI builds a complete, correctly-permissioned database. It will generate a throwaway mnemonic that you are about to replace: ```bash mostro-cli listorders ``` -3. **Overwrite the mnemonic** with your backed-up 12 words and clear the trade index that belonged to the throwaway user: +4. **Overwrite the mnemonic** with your backed-up 12 words and clear the trade index that belonged to the throwaway user. + + Do not type the mnemonic as a command argument: it would land in your shell history and be visible to any local user running `ps`. Read it into a variable instead, with echo disabled, and let `sqlite3` take the statement on stdin: ```bash - sqlite3 ~/.mcli/mcli.db "UPDATE users SET mnemonic = '', last_trade_index = NULL;" + read -rs -p "mnemonic: " MNEMONIC && echo + sqlite3 ~/.mcli/mcli.db < A friendlier `import-mnemonic` subcommand may land in the future. Until then, the flow above is the supported path. +7. **(Cosmetic) realign `i0_pubkey`.** The `users` row still carries the throwaway identity in its primary key column. Nothing derives from it — every identity and trade key comes from the `mnemonic` column at runtime, and `User::save` matches on whatever value is stored, so the database stays self-consistent. If you want the column to reflect reality anyway, take the `User` pubkey that `restore` printed in the previous step: -### Backing up the whole DB + ```bash + sqlite3 ~/.mcli/mcli.db "UPDATE users SET i0_pubkey = '';" + ``` -If you also want to preserve cached order metadata and avoid re-fetching, copy `~/.mcli/mcli.db` to the new machine instead. The DB contains no funds — only Nostr keys and order metadata. +> **Limitation: `restore` does not rebuild your local order cache.** It reports what Mostro knows, but it does not insert those orders into the local `orders` table. Commands that operate on a specific order — `release`, `cancel`, `fiatsent`, `addinvoice`, `rate`, `senddm` — read that table first and will fail on an order that is not in it. So a mnemonic-only restore gets your identity and your ratings back and lets you trade again from scratch, but it cannot resume a trade that was already in flight. For that, copy the database (see above). + +> A friendlier `import-mnemonic` subcommand may land in the future. Until then, the flow above is the supported path. --- @@ -562,7 +585,7 @@ Every command supports `-h, --help`. The list below is a one-line summary; run ` > **These must come *before* the subcommand.** They are parsed on the top-level command, so `mostro-cli listorders -m ` fails with `error: unexpected argument '-m' found`. Write `mostro-cli -m listorders` instead. This also avoids clashing with subcommand flags that reuse the same letters (`-m` is `--payment-method` on `neworder` and `--message` on `senddm`, `-p` is `--premium` on `neworder` and `--pubkey` on the DM commands). -- `-v, --verbose` — enable info logging (also the only way to make `RUST_LOG` take effect). +- `-v, --verbose` — enable info logging. This is the only log control; it overwrites `RUST_LOG` with `info`. - `-m, --mostropubkey ` — overrides `MOSTRO_PUBKEY`. - `-r, --relays ` — overrides `RELAYS`. - `-p, --pow ` — overrides `POW`. @@ -592,7 +615,7 @@ Environment variables read by the CLI: | `SECRET` | Optional — `true` enables secret-mode inner tuple. | | `TRANSPORT` | Optional — `gift-wrap` or `nip44`; auto-detected when unset. | | `ADMIN_NSEC` | Optional — only used by admin commands. | -| `RUST_LOG` | Optional — log level, but only honoured when `-v` is also passed (the logger is initialised only by `-v`). | +| `RUST_LOG` | Read but effectively not configurable — `-v` overwrites it with `info` and is the only thing that initialises the logger. | The database stores **secret material** (your mnemonic). Treat `~/.mcli/mcli.db` like a wallet seed file: @@ -629,13 +652,15 @@ Run with `-v` (before the subcommand) for relay-level logs. **Mostro rejects events / no reply** — The instance may require `POW`. Ask the operator what difficulty is enforced and export `POW=`. -**`no such table: orders`** — Your `~/.mcli/mcli.db` was created by something other than the CLI (usually by hand-crafting it while restoring a mnemonic). The CLI only creates its tables when that file does not exist, so a pre-made database is missing `orders`. Delete it and follow [Restoring on a new machine](#restoring-on-a-new-machine) — but back up the mnemonic first: `sqlite3 ~/.mcli/mcli.db "SELECT mnemonic FROM users;"`. +**`no such table: orders`** — Your `~/.mcli/mcli.db` was created by something other than the CLI (usually by hand-crafting it while restoring a mnemonic). The CLI only creates its tables when that file does not exist, so a pre-made database is missing `orders`. Delete it and follow [Restoring from the mnemonic alone](#restoring-from-the-mnemonic-alone) — but back up the mnemonic first: `sqlite3 ~/.mcli/mcli.db "SELECT mnemonic FROM users;"`. -**Mostro rejects my order after restoring on a new machine** — You very likely skipped the trade-index sync. Run `mostro-cli getlasttradeindex`; see [Restoring on a new machine](#restoring-on-a-new-machine). +**Mostro rejects my order after restoring on a new machine** — You very likely skipped the trade-index sync. Run `mostro-cli getlasttradeindex`; see [Restoring from the mnemonic alone](#restoring-from-the-mnemonic-alone). **Nothing happens / I'm waiting for my counterpart** — The CLI does not stay connected. Re-run `mostro-cli getdm --since ` to pull new messages; see [The CLI does not stay connected — you poll](#the-cli-does-not-stay-connected--you-poll). -**Lost the database / changed machine** — See [Backup, recovery and multi-device](#backup-recovery-and-multi-device). Without the mnemonic, active orders/disputes cannot be recovered. +**Lost the database / changed machine** — See [Backup, recovery and multi-device](#backup-recovery-and-multi-device). Without the mnemonic you cannot recover anything; with the mnemonic you recover your identity but not in-flight trades (see below). + +**I restored my mnemonic but `release` / `addinvoice` / `senddm` says the order doesn't exist** — Expected. `mostro-cli restore` reports the orders Mostro holds for you, but it does not write them into the local `orders` table, and those commands look the order up there first. A mnemonic-only restore cannot resume a trade that was already in flight — copying `~/.mcli/mcli.db` is the only way to do that. See [Moving to a new machine: copy the database](#moving-to-a-new-machine-copy-the-database). **Multiple orders in flight** — Each gets its own derived trade key. The DB tracks them; just keep using order IDs.