@did-btcr2/cli 0.23.0 → 0.23.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,13 +6,15 @@ Part of the [`did-btcr2-js`](https://github.com/dcdpr/did-btcr2-js) monorepo.
6
6
 
7
7
  ## Summary
8
8
 
9
- This package provides the `btcr2` CLI for creating, resolving, updating, and deactivating did:btcr2 decentralized identifiers. It decodes and validates identifiers offline, and it builds the genesis document of an external identifier. It also manages an encrypted keystore of keypairs, reads and writes CLI configuration and profiles, and prints shell completion scripts. It wraps the `@did-btcr2/api` SDK via dependency injection, using [commander.js](https://github.com/tj/commander.js/) for argument parsing.
9
+ The `btcr2` command creates, resolves, updates, and deactivates did:btcr2 identifiers. It decodes and validates identifiers offline. It builds the genesis document of an external identifier. It manages the keys in an encrypted keystore. It reads and writes the CLI config and its profiles. It prints shell completion scripts.
10
10
 
11
- Out of the box, `btcr2 resolve` works with zero configuration. The Bitcoin network is derived from the DID itself, and public endpoints (mempool.space, ipfs.io) are used as defaults. Override endpoints via CLI flags, environment variables, or a config file.
11
+ The CLI wraps the `@did-btcr2/api` SDK. It parses the arguments with [commander.js](https://github.com/tj/commander.js/).
12
12
 
13
- Signing operations (`update`, `deactivate`, and generated `create` keys) read secret keys from an encrypted on-disk keystore. Choose a key with `--signing-key <ref>` or set an active key with `btcr2 key use <ref>`.
13
+ `btcr2 resolve` works with no config. The identifier names its network, and the CLI uses public endpoints (mempool.space, ipfs.io) by default. A flag, an environment variable, or the config file can override each endpoint.
14
14
 
15
- Full reference documentation lives in [`docs/`](./docs/README.md): a page per command, the global options and configuration precedence, and a guided end-to-end walkthrough on Mutinynet in [`docs/DEMO.md`](./docs/DEMO.md).
15
+ `update` and `deactivate` read the signing key from the keystore. Select a key with `--signing-key <ref>`, or set the active key with `btcr2 key use <ref>`.
16
+
17
+ The reference documentation is in [`docs/`](./docs/README.md). It has one page per command, the global flags, the environment variables, and the precedence rules. [`docs/DEMO.md`](./docs/DEMO.md) is a walkthrough of the full lifecycle on mutinynet.
16
18
 
17
19
  ## Install
18
20
 
@@ -26,9 +28,9 @@ Or with pnpm:
26
28
  pnpm add -g @did-btcr2/cli
27
29
  ```
28
30
 
29
- Requires Node.js >= 22.
31
+ The CLI needs Node.js 22 or newer.
30
32
 
31
- Without installing globally, run directly via npx:
33
+ To run the CLI without a global install, use npx:
32
34
 
33
35
  ```bash
34
36
  npx @did-btcr2/cli resolve -i did:btcr2:k1qq...
@@ -38,424 +40,47 @@ npx @did-btcr2/cli resolve -i did:btcr2:k1qq...
38
40
 
39
41
  | Command | Alias | Description |
40
42
  |---|---|---|
41
- | `init` | - | Set up the btcr2 home: create the directory, a default config, and establish the keystore |
42
- | `quickstart` | - | One-command onboarding: `init` + record the network + (optionally) cache the session and probe endpoints |
43
- | `create` | - | Create an identifier and initial DID document |
44
- | `resolve` | `read` | Resolve a DID document |
45
- | `update` | - | Update a DID document (signs via the keystore) |
46
- | `deactivate` | `delete` | Deactivate a DID permanently (signs via the keystore) |
47
- | `identifier` | - | Decode and validate identifiers (offline) |
48
- | `genesis` | - | Build the genesis document of an external identifier (offline) |
49
- | `key` | - | Manage keypairs in the keystore |
50
- | `keystore` | - | Establish, inspect, and re-key the keystore |
51
- | `config` | - | Read and write CLI configuration |
52
- | `profile` | - | Manage configuration profiles |
53
- | `completion` | - | Print a shell completion script |
54
-
55
- ### create
56
-
57
- Creates an identifier and initial DID document. Two identifier types, selected by `-t/--type`:
58
-
59
- - **`k`** (deterministic): a 33-byte compressed secp256k1 public key. Three mutually-exclusive input modes:
60
- - **generate** (neither `--bytes` nor `--signing-key`): mint a fresh key, persist it to the keystore, set it active, and print the identifier. Sealing the secret prompts for the keystore passphrase.
61
- - **existing** (`--signing-key <ref>`): use a stored key's public key as the genesis bytes. Reading a public key never decrypts, so this never prompts.
62
- - **raw** (`--bytes <hex>`): a 33-byte public key as hex. Offline and keystore-free.
63
- - **`x`** (external): the genesis document file via `--document <path>` (the api hashes it; see `genesis build`), or the 32-byte SHA-256 hash via `--bytes`.
64
-
65
- | Flag | Description |
66
- |---|---|
67
- | `-t, --type <type>` | Identifier type: `k` (deterministic) or `x` (external). Default: `k` |
68
- | `-n, --network <network>` | Bitcoin network: `bitcoin`, `testnet3`, `testnet4`, `signet`, `mutinynet`, or `regtest`. Default: config `defaults.network`, else the active profile's network, else `regtest` |
69
- | `-b, --bytes <bytes>` | Genesis bytes as a hex string. For type=k, a 33-byte public key (omit to generate a key); for type=x, the 32-byte genesis-document hash |
70
- | `--document <path>` | For type=x, the JSON genesis document to hash. Exclusive with `--bytes`. The result adds `genesisBytes` |
71
-
72
- `--signing-key <ref>` (global) selects a stored key for the existing-key mode; it applies only to `-t k`.
73
-
74
- On a testnet with a public faucet, text-mode `create` (for a `-t k` identifier) also prints a **funding hint** on stderr: the initial P2WPKH beacon address next to its faucet and explorer links, from the per-network preset. It is suppressed under `--quiet` and `-o json`, and absent on regtest and mainnet.
75
-
76
- ### resolve (alias: read)
77
-
78
- Required flag: `-i/--identifier`. If both `-r` and `-p` are given, `-r` wins and `-p` is silently ignored.
79
-
80
- | Flag | Description |
81
- |---|---|
82
- | `-i, --identifier <identifier>` | did:btcr2 identifier to resolve (required) |
83
- | `-r, --resolution-options <json>` | Resolution options as an inline JSON string |
84
- | `-p, --resolution-options-path <path>` | Path to a JSON file containing resolution options |
85
- | `--min-conf <n>` | Minimum block confirmations a beacon signal needs before resolution applies it. A positive integer; default `6`, the specification value. Overrides a `minConf` inside `-r`/`-p`. Pass `1` to see a fresh update after one block |
86
- | `--genesis-document <path>` | The JSON genesis document of an external (`x`) identifier. Fills `sidecar.genesisDocument`; wins over a value inside `-r`/`-p`. Refused for a `k` identifier |
87
-
88
- ### update
89
-
90
- Signs and broadcasts an update to a DID document. The signing key comes from the encrypted keystore (choose one with `--signing-key <ref>` or set an active key with `btcr2 key use`).
91
-
92
- Required flags: `-i/--identifier`, `-p/--patches`. The command resolves the current document from the network unless you supply the source pair `-s/--source-document` and `--source-version-id` (both or neither). The api derives the verification method and the beacon unless you pass `-m` or `-b`.
93
-
94
- | Flag | Description |
95
- |---|---|
96
- | `-i, --identifier <identifier>` | did:btcr2 identifier to update (required) |
97
- | `-p, --patches <json>` | JSON Patch operations as a JSON array string (required) |
98
- | `-s, --source-document <json>` | Source DID document as a JSON string. Requires `--source-version-id`. Omit both to resolve the current document first |
99
- | `--source-version-id <number>` | Version ID of the source document, a non-negative integer. Requires `--source-document` |
100
- | `-m, --verification-method-id <id>` | Verification method that signs the update. Default: the one method of the document that publishes the signing key. Pass it when the api names several candidates |
101
- | `-b, --beacon-id <id>` | Beacon service that announces the update, as a DID URL (`#initialP2WPKH` or absolute). Default: the only beacon of the document, else the one beacon with a spendable UTXO. Pass it when the api names several funded beacons |
102
- | `-r, --resolution-options <json>` | Resolution options as an inline JSON string, for the resolution of the source document. Supply sidecar data here if the DID's prior updates are not in a CAS. Not allowed with the source pair |
103
- | `--resolution-options-path <path>` | Path to a JSON file containing resolution options (`-r` wins if both are given). Not allowed with the source pair |
104
- | `--min-conf <n>` | Minimum block confirmations a beacon signal needs before the source resolution applies it. A positive integer; default `6`, the specification value. Overrides a `minConf` inside `-r`/`--resolution-options-path`. Not allowed with the source pair |
105
- | `--publish-to-cas <mode>` | Publish update artifacts to a writable CAS before broadcast: `auto`, `always`, or `never` (default: `never`). See [Publishing updates to CAS](#publishing-updates-to-cas) |
106
- | `--fee-rate <satsPerVByte>` | Fee rate in sats/vByte for the beacon transaction (default: `5`). Raise it under congestion so the transaction confirms (also `BTCR2_FEE_RATE`, profile `btc.feeRate`) |
107
- | `--change-address <address>` | Send transaction change to this address instead of the beacon address, so a DID's announcements are not linked on-chain (profile `btc.changeAddress`) |
108
-
109
- On a network with a block explorer, text-mode `update` (and `deactivate`) also prints a `Watch:` link on stderr for the broadcast txid, suppressed under `--quiet` and `-o json`.
110
-
111
- ### deactivate (alias: delete)
112
-
113
- Permanently deactivates a DID. This is irreversible. The command calls the api's `deactivateDid`, which applies the `{ "op": "add", "path": "/deactivated", "value": true }` patch and refuses a DID that is deactivated already. It signs via the keystore like `update`.
114
-
115
- Required flag: `-i/--identifier`. Optional: the same source, derivation, resolution, CAS, fee, and change-address flags as `update`, minus `-p`.
116
-
117
- ### identifier
118
-
119
- Decodes and validates identifiers. Both subcommands are offline and keystore-free. The identifier is a positional argument.
120
-
121
- | Subcommand | Description |
122
- |---|---|
123
- | `identifier decode <did>` | Print the identifier type, the `hrp`, the version, the network, and the genesis bytes as hex. `--initial-document` adds the initial DID document; an `x` identifier needs `--genesis-document <path>` for it. |
124
- | `identifier validate <did>` | Run the checks of the identifier decoding algorithm in order and print the report. Exit code `1` if a check fails. `-b, --bytes <hex>` adds the `genesisBytesMatch` check: the identifier must encode these genesis bytes (`k` or `x`). `--genesis-document <path>` adds the `genesisDocument` check for an `x` identifier. |
125
-
126
- See [`docs/identifier.md`](./docs/identifier.md) for the check list and the output fields.
127
-
128
- ### genesis
129
-
130
- Builds the genesis document of an external (`x`) identifier, writes it to a file, and prints the identifier. Offline: the beacon addresses are derived from the keys. The keystore opens only for public reads of a key reference.
131
-
132
- | Subcommand | Description |
133
- |---|---|
134
- | `genesis build` | On a terminal, ask for the keys, the relationships, the beacons, and the services (defaults: the active key, all four relationships, one P2WPKH Singleton beacon). `--spec <path>` reads a JSON spec instead and asks nothing. `-n <network>` as in `create`. `--out <path>` names the file (default `genesis.json`); `--force` overwrites. Prints `{ did, network, genesisBytes, path, beacons }`. |
135
-
136
- Then: `create -t x --document <path>` mints the identifier again from the file, `identifier validate <did> --genesis-document <path>` confirms the pair, and `resolve`, `update`, and `deactivate` take the file with `--genesis-document <path>`.
137
-
138
- See [`docs/genesis.md`](./docs/genesis.md) for the wizard questions, the spec file, and the output fields.
139
-
140
- ### init
141
-
142
- `btcr2 init` is the one-command setup: it creates the btcr2 home directory, writes a default config if none exists, and establishes the keystore if none exists. It is idempotent (existing files are left untouched unless `--force`). For a single command that also records the network and (optionally) caches the session and probes the endpoints, see [`quickstart`](#quickstart).
143
-
144
- | Flag | Description |
145
- |---|---|
146
- | `-n, --network <network>` | Bitcoin network to record as `defaults.network` so later commands can drop `-n`. Written idempotently: it never clobbers a network you set earlier |
147
- | `--dev` | Establish an **unencrypted** dev keystore (plaintext keys, no passphrase). Testnet/regtest only; mainnet operations are refused |
148
- | `--force` | Re-create the config even if it exists. **Never** re-creates the keystore (re-establishing one is the explicit `keystore init --force`) |
149
-
150
- By default `init` establishes an **encrypted** keystore and prompts (with confirmation) for a passphrase up front, so the first `key generate` never seals the keystore under an unconfirmed, mistyped passphrase. Supply the passphrase non-interactively with `BTCR2_KEYSTORE_PASSPHRASE` or `--passphrase-file` for scripted setup. The output envelope reports the resolved `network` alongside the paths and `protection`.
151
-
152
- ### quickstart
153
-
154
- `btcr2 quickstart` collapses onboarding into one step: it runs `init`'s scaffold, records the network (default **mutinynet**), and optionally caches the session and probes the endpoints. It reimplements nothing - it composes `init`, `keystore unlock`, and `config doctor` - so the keystore and session guarantees hold unchanged.
155
-
156
- | Flag | Description |
157
- |---|---|
158
- | `-n, --network <network>` | Bitcoin network to set up. Default: `mutinynet` |
159
- | `--dev` | Establish an unencrypted dev keystore (testnet only) |
160
- | `--unlock` | Cache the passphrase for the session so later commands do not re-prompt. Opt-in; on a fresh encrypted keystore it reuses the establish-time passphrase with no second prompt |
161
- | `--ttl <duration>` | Session lifetime with `--unlock`: bare seconds or an `s`/`m`/`h` suffix (default `1h`, max `24h`; also `BTCR2_KEYSTORE_TTL`) |
162
- | `--no-doctor` | Skip the endpoint reachability probe (which is on by default and **advisory**: a failed probe warns but `quickstart` still exits 0) |
163
- | `--allow-mainnet` | Permit `-n bitcoin` (records mainnet as the default; dev keystores are still refused). Guarded before any writes |
164
- | `--force` | Re-create the config even if it exists (never the keystore) |
165
-
166
- The workshop happy path:
167
-
168
- ```bash
169
- btcr2 quickstart -n mutinynet --unlock --ttl 2h # (or: --dev for an unencrypted dev keystore)
170
- btcr2 key generate --set-active
171
- btcr2 create # network comes from defaults.network
172
- # ...fund the beacon (create prints the faucet + explorer links), resolve, update, deactivate...
173
- ```
174
-
175
- ### key
176
-
177
- Manage keypairs in the keystore. All subcommands operate offline (no Bitcoin connection).
178
-
179
- | Subcommand | Alias | Description |
180
- |---|---|---|
181
- | `key generate` | - | Generate a new keypair and store it. Flags: `--name <name>`, `--set-active` |
182
- | `key list` | `ls` | List stored keys (id, fingerprint, name, active) |
183
- | `key show <ref>` | - | Show a key's public material and tags (never prints the secret) |
184
- | `key import` | - | Import a secret from a hex file (`--secret-file`) or a public key as watch-only (`--public`). Flags: `--name`, `--set-active` |
185
- | `key export <ref>` | - | Export public material by default; `--secret --out <path>` writes the secret to a new 0600 file |
186
- | `key delete <ref>` | `rm` | Delete a key. `--force` deletes even the active key |
187
- | `key use <ref>` | - | Set the active key, persisted across invocations |
188
-
189
- A key reference is a full URN, a unique `name` tag, or a unique fingerprint prefix.
190
-
191
- ### keystore
192
-
193
- Establish, inspect, and re-key the keystore. These operate on the keystore file directly (no Bitcoin connection).
194
-
195
- | Subcommand | Alias | Description |
196
- |---|---|---|
197
- | `keystore init` | - | Establish the keystore (encrypted by default; prompts and confirms the passphrase). `--dev` creates an unencrypted dev keystore; `--force` re-establishes an existing one (discards its keys) |
198
- | `keystore status` | - | Show the resolved path, protection mode (`encrypted`/`dev`/`absent`), whether a passphrase is established, the key count, and the `session` state (whether one is live and its remaining lifetime). Never decrypts or prompts |
199
- | `keystore change-passphrase` | `passwd` | Re-seal every key under a new passphrase (encrypted keystores only). Prompts for the current passphrase, then a new one (with confirmation). Clears any cached session |
200
- | `keystore unlock` | - | Cache the verified passphrase for the session so later commands do not re-prompt. `--ttl <duration>` sets the lifetime (default `1h`, max `24h`; also `BTCR2_KEYSTORE_TTL`); `--allow-mainnet` permits unlocking a `bitcoin`-default context |
201
- | `keystore lock` | - | Revoke the cached session so later commands prompt again. Idempotent; needs no passphrase |
202
-
203
- **Encrypted vs dev keystores.** An encrypted keystore seals each secret with argon2id + XChaCha20-Poly1305 under one passphrase, and records a verifier so a mistyped passphrase fails loudly (with `Incorrect passphrase`) instead of sealing a key under an unknown or divergent passphrase. A **dev keystore** (`--dev`) stores secrets in plaintext and never prompts: it is for disposable testnet/regtest keys only, and the CLI **hard-refuses** to sign or generate a mainnet (`bitcoin`) key with one.
204
-
205
- **Session unlock.** `keystore unlock` caches the verified passphrase in `<home>/session.json` (`0600`) so a returning operator authenticates once instead of on every signing command. A cached session sits below `BTCR2_KEYSTORE_PASSPHRASE` / `--passphrase-file` and above the interactive prompt, so unattended and CI paths still win. Mainnet keeps per-use authentication: a `bitcoin` operation is withheld from a session that was not unlocked with `--allow-mainnet`. The cached passphrase is base64url-encoded, not encrypted; its only protection at rest is the `0600` file mode.
206
-
207
- ### config
208
-
209
- Read and write CLI configuration.
210
-
211
- | Subcommand | Alias | Description |
212
- |---|---|---|
213
- | `config init` | - | Create a default config file with one profile per network. `--force` overwrites |
214
- | `config get [path]` | - | Print a value at a dotted path, or the whole config. Secret values are redacted; `--show-secrets` reveals them |
215
- | `config set <path> <value>` | - | Set a value at a dotted path (value parsed as JSON when valid, else a string; known endpoint/credential/name paths are always stored as strings). An invalid enum for a known key is rejected; an unknown path warns but writes |
216
- | `config unset <path>` | - | Delete a value at a dotted path |
217
- | `config list` | `ls` | Print the entire config file. Secret values are redacted; `--show-secrets` reveals them |
218
- | `config validate` | - | Report unknown keys, invalid enum values, and an unsupported schema version |
219
- | `config effective` | - | Print the resolved connection config with per-value provenance (`flag`/`env`/`file`/`default`). `-n, --network <n>` selects the network; `--show-secrets` reveals the RPC password |
220
- | `config path` | - | Print the resolved home directory, config-file, and keystore paths |
221
- | `config doctor` | - | Probe reachability of the resolved endpoints (read-only; touches the network). `-n, --network <n>` selects the network |
222
-
223
- ### profile
224
-
225
- Manage configuration profiles.
226
-
227
- | Subcommand | Alias | Description |
228
- |---|---|---|
229
- | `profile add <name>` | - | Add an empty profile |
230
- | `profile use <name>` | - | Set the active profile (writes `defaults.profile`) |
231
- | `profile show [name]` | - | Show a profile (defaults to the active profile). Secret values are redacted; `--show-secrets` reveals them |
232
- | `profile remove <name>` | `rm` | Remove a profile |
233
-
234
- ### completion
235
-
236
- `btcr2 completion [shell]` prints a shell completion script (bash, zsh, or fish) to stdout. Defaults to bash. For example: `eval "$(btcr2 completion bash)"`.
43
+ | [`init`](./docs/init.md) | | Set up the home: create the directory, a default config file, and the keystore. |
44
+ | [`quickstart`](./docs/quickstart.md) | | Set up the home in one command, record the network, and (optional) cache the session and probe the endpoints. |
45
+ | [`create`](./docs/create.md) | | Create an identifier and its initial DID document (offline). |
46
+ | [`resolve`](./docs/resolve.md) | `read` | Resolve the DID document of an identifier. |
47
+ | [`update`](./docs/update.md) | | Update a DID document. The keystore signs the update. |
48
+ | [`deactivate`](./docs/deactivate.md) | `delete` | Deactivate an identifier. This is permanent. The keystore signs the deactivation. |
49
+ | [`identifier`](./docs/identifier.md) | | Decode and validate identifiers (offline). |
50
+ | [`genesis`](./docs/genesis.md) | | Build the genesis document of an external identifier (offline). |
51
+ | [`key`](./docs/key.md) | | Manage the keys in the keystore. |
52
+ | [`keystore`](./docs/keystore.md) | | Create, inspect, re-key, and unlock the keystore. |
53
+ | [`config`](./docs/config.md) | | Read and write the CLI config. |
54
+ | [`profile`](./docs/profile.md) | | Manage the config profiles. |
55
+ | [`completion`](./docs/completion.md) | | Print a shell completion script. |
56
+
57
+ Each page lists the flags, the output, the environment variables, and examples of the command. `btcr2 <command> --help` prints the flags of a command.
237
58
 
238
59
  ## Usage
239
60
 
240
- ### Create a DID
241
-
242
- ```bash
243
- # Generate a fresh key (type=k), store it in the keystore, and print the identifier
244
- btcr2 create -n regtest
245
-
246
- # Deterministic (type=k): from an explicit compressed secp256k1 public key (33 bytes hex)
247
- btcr2 create -t k -n regtest -b 02aa...
248
-
249
- # Deterministic (type=k): from a stored key's public key
250
- btcr2 create -t k -n regtest --signing-key mykey
251
-
252
- # External (type=x): from a SHA-256 hash of a genesis document (32 bytes hex)
253
- btcr2 create -t x -n bitcoin -b bb...
254
- ```
255
-
256
- ### Resolve a DID
257
-
258
- ```bash
259
- # Zero-config: network and endpoints are derived from the DID
260
- btcr2 resolve -i did:btcr2:k1qq...
261
-
262
- # Alias: read
263
- btcr2 read -i did:btcr2:k1qq...
264
-
265
- # With resolution options as inline JSON
266
- btcr2 resolve -i did:btcr2:k1qq... -r '{"versionId":"1"}'
267
-
268
- # With resolution options from a JSON file
269
- btcr2 resolve -i did:btcr2:k1qq... -p resolution-options.json
270
-
271
- # Apply a signal after one confirmation instead of the default six
272
- btcr2 resolve -i did:btcr2:k1qq... --min-conf 1 -r '{"sidecar":{"updates":[...]}}'
273
-
274
- # JSON output
275
- btcr2 -o json resolve -i did:btcr2:k1qq...
276
- ```
277
-
278
- ### Update a DID
279
-
280
61
  ```bash
281
- # Signs with the active keystore key (or one chosen via --signing-key).
282
- # The command resolves the current document, derives the verification
283
- # method and the beacon, then signs and broadcasts.
284
- btcr2 update -i did:btcr2:k1qq... \
285
- -p '[{"op":"add","path":"/service/-","value":{"id":"#svc","type":"X","serviceEndpoint":"https://x"}}]'
286
-
287
- # A DID whose prior update is sidecar-only: hand that update to the source resolution
288
- btcr2 update -i did:btcr2:k1qq... --min-conf 1 -r '{"sidecar":{"updates":[...]}}' \
289
- -p '[{"op":"remove","path":"/service/1"}]'
62
+ # Set up the home, the config file, and an encrypted keystore on mutinynet.
63
+ # Cache the passphrase for two hours.
64
+ btcr2 quickstart -n mutinynet --unlock --ttl 2h
290
65
 
291
- # Offline source: supply the document and its version, and name the method and the beacon
292
- btcr2 update -i did:btcr2:k1qq... \
293
- -s "$(cat did.json)" --source-version-id 1 \
294
- -p '[{"op":"remove","path":"/service/1"}]' \
295
- -m '#initialKey' -b '#initialP2WPKH'
296
- ```
66
+ # Generate a key, store it as the active key, and create an identifier (offline).
67
+ btcr2 create -n mutinynet
297
68
 
298
- ### Deactivate a DID
69
+ # Resolve the DID document from Bitcoin.
70
+ btcr2 resolve -i did:btcr2:k1q5p...
299
71
 
300
- ```bash
301
- # Irreversible. Resolves the current document, then signs the deactivation via the keystore.
302
- btcr2 deactivate -i did:btcr2:k1qq... --min-conf 1 -r '{"sidecar":{"updates":[...]}}'
72
+ # Update the DID document: sign a JSON Patch and broadcast a beacon signal.
73
+ btcr2 update -i did:btcr2:k1q5p... \
74
+ -p '[{"op":"add","path":"/alsoKnownAs","value":["https://example.com/demo"]}]'
303
75
  ```
304
76
 
305
- ### Manage keys
306
-
307
- ```bash
308
- btcr2 key generate --name mykey --set-active
309
- btcr2 key list
310
- btcr2 key use mykey
311
- ```
77
+ An update needs a funded beacon. On a test network, `create` prints the beacon address and the faucet link. [`docs/DEMO.md`](./docs/DEMO.md) has the full sequence.
312
78
 
313
79
  ## Configuration
314
80
 
315
- Override precedence, highest wins: CLI flags, then environment variables, then config file, then network defaults.
316
-
317
- ### Global flags
318
-
319
- | Flag | Description |
320
- |---|---|
321
- | `-v, --version` | Output the current version |
322
- | `-o, --output <format>` | Output format: `json` or `text` (default: config `defaults.output`, else `text`) |
323
- | `--verbose` | Verbose output |
324
- | `--quiet` | Suppress non-essential output |
325
- | `--home <dir>` | btcr2 home directory holding `config.json` + `keystore.json` (default: `~/.btcr2`, `%LOCALAPPDATA%\btcr2` on Windows; overrides `$BTCR2_HOME`) |
326
- | `-c, --config <path>` | Path to config file (default: `<home>/config.json`) |
327
- | `--profile <name>` | Config profile name (default: auto-detected from network) |
328
- | `--btc-rest <url>` | Override Bitcoin REST endpoint (Esplora API) |
329
- | `--btc-rpc-url <url>` | Override Bitcoin Core RPC endpoint |
330
- | `--btc-rpc-user <user>` | Bitcoin Core RPC username |
331
- | `--btc-rpc-wallet <name>` | Bitcoin Core wallet name for wallet-scoped RPCs (`/wallet/<name>`) |
332
- | `--btc-rpc-header <header>` | Extra Bitcoin Core RPC header `"Key: Value"` (repeatable). A credential passed here is on argv: prefer `btc.rpcHeaders` in a profile |
333
- | `--btc-signal-discovery <mode>` | Where beacon signals are read from `<indexer\|fullnode>` (default: `indexer`; `fullnode` scans blocks over Bitcoin Core RPC) |
334
- | `--btc-rest-header <header>` | Extra Bitcoin REST header `"Key: Value"` (repeatable). A credential passed here (an API key, a bearer token) is on argv and readable through `ps`: prefer `btc.headers` in a profile |
335
- | `--btc-timeout <ms>` | Bitcoin REST/RPC request timeout in milliseconds (default: unbounded) |
336
- | `--cas-gateway <url>` | IPFS HTTP gateway for CAS reads (read-only) |
337
- | `--cas-rpc-url <url>` | IPFS HTTP RPC endpoint for a writable CAS (reads + writes; enables `--publish-to-cas`) |
338
- | `--cas-timeout <ms>` | CAS request timeout in milliseconds (default: `30000`; `0` disables) |
339
- | `--keystore <path>` | Path to the keystore file (default: `<home>/keystore.json`) |
340
- | `--passphrase-file <path>` | Read the keystore passphrase from a file (unattended use) |
341
- | `--signing-key <ref>` | Key for create/update/deactivate signing: a URN, fingerprint prefix, or name |
81
+ The CLI keeps its state in one home directory: `~/.btcr2` on Linux and macOS, `%LOCALAPPDATA%\btcr2` on Windows. The home holds `config.json`, `keystore.json`, and `session.json`. `--home <dir>` or `BTCR2_HOME` moves the home.
342
82
 
343
- ### Environment variables
344
-
345
- | Variable | Equivalent flag |
346
- |---|---|
347
- | `BTCR2_BTC_REST` | `--btc-rest` |
348
- | `BTCR2_BTC_RPC_URL` | `--btc-rpc-url` |
349
- | `BTCR2_BTC_RPC_USER` | `--btc-rpc-user` |
350
- | `BTCR2_BTC_RPC_PASS` | no flag: a password on argv is readable through `ps` and shell history |
351
- | `BTCR2_BTC_RPC_PASS_FILE` | file whose contents are the RPC password |
352
- | `BTCR2_CAS_GATEWAY` | `--cas-gateway` |
353
- | `BTCR2_CAS_RPC_URL` | `--cas-rpc-url` |
354
- | `BTCR2_BTC_SIGNAL_DISCOVERY` | `--btc-signal-discovery` |
355
- | `BTCR2_BTC_TIMEOUT` | `--btc-timeout` |
356
- | `BTCR2_CAS_TIMEOUT` | `--cas-timeout` |
357
- | `BTCR2_FEE_RATE` | `--fee-rate` |
358
- | `BTCR2_OUTPUT` | `-o, --output` |
359
- | `BTCR2_HOME` | `--home` |
360
- | `BTCR2_KEYSTORE_PASSPHRASE` | keystore passphrase (unattended use) |
361
- | `BTCR2_KEYSTORE_TTL` | session lifetime for `keystore unlock` / `quickstart --unlock` (default `1h`, max `24h`) |
362
-
363
- ### Home directory
364
-
365
- The CLI keeps its config and keystore side by side in one home directory, resolved as `--home <dir>`, then `$BTCR2_HOME`, then the platform default: `~/.btcr2` on Linux/macOS and `%LOCALAPPDATA%\btcr2` on Windows. Both files live directly under it (`<home>/config.json`, `<home>/keystore.json`); `btcr2 config path` prints the resolved locations. `--config` and `--keystore` still override each file individually, so the historical XDG split can be reproduced explicitly.
366
-
367
- ### Config file
368
-
369
- Default location: `<home>/config.json`. A malformed config file fails loudly (the CLI never silently falls back to public endpoints, and never overwrites an unparseable file).
370
-
371
- Profiles are matched by network name when neither `--profile` nor the config's `defaults.profile` selects one. For example, with no active profile set, resolving a regtest DID automatically selects the `"regtest"` profile. A profile that is not named after a network can declare its network with a `network` field.
372
-
373
- ```json
374
- {
375
- "schemaVersion": 1,
376
- "defaults": {
377
- "profile": "production",
378
- "network": "bitcoin",
379
- "output": "text"
380
- },
381
- "profiles": {
382
- "regtest": {
383
- "btc": {
384
- "rest": "http://localhost:3000",
385
- "rpcUrl": "http://localhost:18443",
386
- "rpcUser": "polaruser",
387
- "rpcPass": "polarpass",
388
- "wallet": "primary",
389
- "feeRate": 5,
390
- "timeoutMs": 30000
391
- }
392
- },
393
- "production": {
394
- "network": "bitcoin",
395
- "btc": {
396
- "rest": "https://my-mempool/api",
397
- "headers": { "Authorization": "Bearer <api-key>" },
398
- "feeRate": 20
399
- },
400
- "cas": { "gateway": "https://ipfs.io", "rpcUrl": "http://127.0.0.1:5001", "timeoutMs": 30000 },
401
- "identity": { "keystore": "/secure/prod-keystore.json", "default": "did:btcr2:...#key-0" }
402
- }
403
- }
404
- }
405
- ```
406
-
407
- Field notes:
408
-
409
- - **`defaults`**: `profile` selects the active profile; `network` fixes the network `create` encodes when `-n` is absent; `output` sets the default output format. `schemaVersion` is stamped on every write; a file written by a newer CLI is refused.
410
- - **`btc`**: `rest`/`rpcUrl`/`rpcUser`/`rpcPass` are endpoints and credentials; `wallet` targets a Bitcoin Core wallet (`/wallet/<name>`); `headers`/`rpcHeaders` add REST/RPC headers; `feeRate` (sats/vByte), `changeAddress`, and `timeoutMs` set broadcast and request behavior;
411
- `signalDiscovery` (`"indexer"` or `"fullnode"`) picks where beacon signals are read from. The RPC url, user, and pass are resolved as one atomic unit, so a URL from a higher-precedence layer never inherits credentials from a lower one.
412
- - **`cas`**: `gateway` is a read-only IPFS HTTP gateway; `cas.rpcUrl` is a writable IPFS HTTP RPC endpoint (enables `--publish-to-cas`; `rpcUrl` wins over `gateway`); `timeoutMs` bounds CAS operations (`0` disables).
413
- - **`identity`**: `keystore` points the profile at its own keystore file, and `default` is the profile's default signing key. Both fall **below** the corresponding `--keystore` / `--signing-key` flags.
414
-
415
- Use `config validate` to check a file, and `config effective` to see the resolved values with their provenance.
416
-
417
- ### RPC password and secrets
418
-
419
- `config get`, `config list`, and `profile show` redact secret-looking values (the RPC password and any key matching `pass`/`secret`/`token`/`auth`/`api-key`/`credential`/`bearer`, e.g. an `Authorization` header) by default; pass `--show-secrets` to reveal them.
420
-
421
- An `rpcPass` written directly into `config.json` is stored in cleartext (the file is mode 0600 but not encrypted). For anything sensitive, keep the secret out of the file with a reference or an RPC-URL-embedded credential:
422
-
423
- - `"rpcPass": "env:MY_RPC_PASS"` reads the password from the `MY_RPC_PASS` environment variable.
424
- - `"rpcPass": "file:/run/secrets/rpc-pass"` reads it from a file (a single trailing newline is trimmed).
425
- - `BTCR2_BTC_RPC_PASS_FILE=/run/secrets/rpc-pass` names a file to read when no other RPC password source applies.
426
-
427
- ### Defaults
428
-
429
- When no overrides are configured:
430
-
431
- - **Bitcoin REST**: [mempool.space](https://mempool.space) for `bitcoin`, `testnet3`, `testnet4`, and `signet`; [mutinynet.com](https://mutinynet.com) for `mutinynet`; `http://localhost:3000` for `regtest`
432
- - **Bitcoin RPC**: `http://localhost:18443` for `regtest` (credentials required), not configured for public networks
433
- - **CAS**: [ipfs.io](https://ipfs.io) HTTP gateway (read-only). Configure a writable CAS with `--cas-rpc-url` (or `cas.rpcUrl`) to publish with `--publish-to-cas`
434
-
435
- ## Publishing updates to CAS
436
-
437
- CAS publication is **optional and never required**. Every `update` and `deactivate` can be completed and shared entirely via sidecar: the command always prints the artifacts a resolver needs (the signed update, the transaction id, the CAS announcement for CAS beacons, and the SMT proof for SMT beacons) for you to distribute yourself.
438
-
439
- Optionally, the signed update (and, for CAS beacons, the announcement) can be published to a content-addressed store before the on-chain broadcast, so any OP_RETURN update hash is fetchable from CAS at resolution time without sidecar data. This is opt-in via `--publish-to-cas`:
440
-
441
- | Mode | Behavior |
442
- |---|---|
443
- | `never` (default) | Publish nothing. Distribute the printed artifacts via sidecar. |
444
- | `auto` | Best-effort. Publish when a writable CAS is configured; otherwise skip publication silently for every beacon type and proceed. Never blocks an update. |
445
- | `always` | Require a writable CAS; error up-front for every beacon type when none is configured. |
446
-
447
- A writable CAS is configured with `--cas-rpc-url <url>` (an IPFS HTTP RPC endpoint, e.g. a local Kubo node at `http://127.0.0.1:5001`), the `BTCR2_CAS_RPC_URL` environment variable, or a profile's `cas.rpcUrl`. The default IPFS gateway is read-only, so without a configured `--cas-rpc-url`, `--publish-to-cas auto` publishes nothing and completes the update sidecar-only, while `--publish-to-cas always` errors up-front (naming the fix) for every beacon type.
448
-
449
- **Privacy:** under `auto`/`always`, canonical signed updates (and announcements) are published to the configured, possibly public, CAS before the on-chain anchor. Keep `never` (the default) to distribute update data privately via sidecar.
450
-
451
- ```bash
452
- # Opt into CAS publication against a local IPFS (Kubo) node
453
- btcr2 update \
454
- --cas-rpc-url http://127.0.0.1:5001 \
455
- --publish-to-cas auto \
456
- -i did:btcr2:k1qq... \
457
- -p '[{"op":"add","path":"/service/-","value":{"id":"#svc","type":"X","serviceEndpoint":"https://x"}}]'
458
- ```
83
+ A value comes from the first of these sources: a flag, an environment variable, the active profile in the config file, the built-in default of the network. [`docs/config.md`](./docs/config.md) describes the config file and the `config` subcommands. [`docs/README.md`](./docs/README.md) lists the global flags, the environment variables, and the precedence of each value.
459
84
 
460
85
  ## Links
461
86