bhwi-cli 0.1.0

Command-line tool to talk to Bitcoin hardware wallets, plus an hwi parity binary
Documentation
# BHWI, the Bitcoin Hardware Wallet Interface

**BHWI** is a [sans-IO](https://sans-io.readthedocs.io/) Bitcoin hardware wallet
interface. For each device it implements an *interpreter* that encodes commands,
decodes device responses and routes data to its recipients, while leaving all
I/O (transport, async runtime, HTTP) to the caller. That lets one Rust core
serve every target platform, from desktop and mobile to the browser (WASM) and
other languages through FFI. And because every device
sits behind one common interface, applications share a single dependency tree
instead of pulling a separate client library (and its transitive dependencies)
per hardware wallet. It ships a CLI plus a Python-HWI-compatible `hwi` binary.

<img src="docs/imgs/bhwi-iso-embedded.svg" width="100%" alt="bhwi embedded in a host app">

Keeping I/O out of the core matters because driving a hardware wallet is rarely
one request/response: registering a Miniscript descriptor before signing,
answering a Ledger's Merkle-proof data requests, or routing through a Jade PIN
server all take several round trips. Rather than commit every caller to one
execution model, BHWI leaves that choice to them: each device is a small state
machine that performs no I/O itself, so it fits synchronous, asynchronous, FFI
and WASM callers alike. This matters most across an FFI boundary, where the host
language often brings its own native I/O stack: a sans-IO core lets that language
plug in its own transport directly instead of embedding a Rust runtime. The
repository ships [`bhwi-async`](bhwi-async) for those who want a ready-made
rust async layer. See [docs/VISION.md](docs/VISION.md) for the full rationale
behind this design.

Concretely, each device is an `Interpreter`: the caller calls `start`, feeds
device replies back through `exchange` until no further `Transmit` is returned,
then `end` yields the response. Throughout, the caller performs the actual I/O
for each `Transmit` payload the interpreter hands back.

```rust
pub trait Interpreter {
    type Command;
    type Transmit;
    type Response;
    type Error;
    fn start(&mut self, command: Self::Command) -> Result<Self::Transmit, Self::Error>;
    fn exchange(&mut self, data: Vec<u8>) -> Result<Option<Self::Transmit>, Self::Error>;
    fn end(self) -> Result<Self::Response, Self::Error>;
}
```

`bhwi-async` is one such driver: it pumps the common interpreter (BitBox02,
Coldcard, Jade, KeepKey, Ledger, Specter-DIY, and Trezor) over HID, USB serial,
TCP, UDP, or the browser and routes each `Transmit` to the device transport,
the Jade PIN server, or a typed host-interaction provider via its `Recipient`.

## Workspace

| crate        | description                                                        |
| ------------ | ------------------------------------------------------------------ |
| `bhwi`       | Core sans-IO interpreters and the `common` command/response model. |
| `bhwi-async` | `async`/`await` `HWI` trait over the interpreters, with protocol framing. |
| `bhwi-async-transport` | Native device channels (HID/USB/serial/TCP) and discovery.     |
| `bhwi-cli`   | `bhwi` command-line tool and the `hwi` parity binary.              |
| `bhwi-wasm`  | WebAssembly bindings for browser callers.                          |

## Supported devices

- [BitBox02]https://github.com/digitalbitbox/bitbox02-firmware
- [Coldcard]https://github.com/Coldcard/firmware
- [Jade]https://github.com/Blockstream/Jade
- [KeepKey]https://github.com/keepkey/keepkey-firmware
- [Ledger]https://github.com/LedgerHQ/app-bitcoin-new
- [Specter-DIY]https://github.com/cryptoadvance/specter-diy
- [Trezor]https://github.com/trezor/trezor-firmware (Model One and Model T)

Every device implements the full [`HWI` trait](bhwi-async/src/lib.rs): `unlock`,
`get_info`, `get_master_fingerprint`, `get_extended_pubkey`, `sign_message`,
`display_address`, `register_wallet` and `sign_tx`. Three capability gaps
remain: `backup_device` is supported on BitBox02 and Coldcard but not on Jade,
KeepKey, Ledger, Specter-DIY, or Trezor; `register_wallet` is unsupported on
KeepKey and Trezor, which verify supported multisig descriptors at display and
signing time instead; and `get_info` is unsupported on Specter-DIY, whose
protocol exposes no firmware version. See [docs/SPECTER.md](docs/SPECTER.md)
for the Specter-DIY setup and limits.

## CLI

`bhwi` is a Unix-friendly command-line tool over `bhwi-async`:

```sh
cargo build -p bhwi-cli
```

All devices are built by default. Build a subset with the `bitbox`,
`coldcard`, `jade`, `keepkey`, `ledger`, `specter` and `trezor` features:

```sh
cargo build -p bhwi-cli --no-default-features --features jade,ledger
```

The same features exist on `bhwi`, `bhwi-async` and `bhwi-async-transport`, and each
forwards to the crate below it. `device install-udev-rules` is Linux only.

| command      | subcommand          | purpose                                                  |
| ------------ | ------------------- | -------------------------------------------------------- |
| `address`    | `get`               | get an address from the device                           |
| `descriptor` | `pubkeys`           | get pubkey descriptors from the device                   |
| `descriptor` | `keypool`           | get a ranged keypool descriptor from the selected device |
| `descriptor` | `register`          | register a named wallet policy with the selected device  |
| `device`     | `list`              | list all available devices                               |
| `device`     | `backup`            | start a backup on the selected device                    |
| `device`     | `setup`             | initialize an unseeded device                            |
| `device`     | `wipe`              | erase wallet material from the selected device           |
| `device`     | `restore`           | restore an unseeded device via its mnemonic flow         |
| `device`     | `toggle-passphrase` | toggle mnemonic-passphrase use on the selected device    |
| `device`     | `prompt-pin`        | ask the selected device to show its PIN keypad           |
| `device`     | `send-pin`          | send the keypad positions shown on the device screen     |
| `device`     | `install-udev-rules` | install udev rules for hardware wallet device access     |
| `xpub`       | `get`               | get an extended public key at a derivation path          |
| `psbt`       | `sign`              | sign a PSBT with the selected device                     |
| `message`    | `sign`              | sign a message with the selected device                  |

Shared `--fingerprint`, `--device-type`, `--device-path`, `--network`,
`--format`, and `--passphrase` options work before a command group, between
the group and action, or after the action. For example:

```sh
bhwi message sign --network testnet --fingerprint f5acc2fd \
  --message hello --path "m/44'/1'/0'/0"
```

Output is chainable by default (no headers). Use `--format pretty` or
`--format json` where supported; PSBT, address, and xpub output remains plain
regardless of format.

## HWI parity

`bhwi-cli` also builds a Python-HWI-compatible `hwi` binary. A parity suite
checks its output against Bitcoin Core HWI for the devices where parity is
claimed. See [docs/HWI_PARITY.md](docs/HWI_PARITY.md).

## Documentation

- [docs/VISION.md]docs/VISION.md: design rationale
- [docs/DEVICE_ONBOARDING.md]docs/DEVICE_ONBOARDING.md: adding a device
- [docs/HWI_PARITY.md]docs/HWI_PARITY.md: Python-HWI parity
- [docs/NIX.md]docs/NIX.md: Nix emulator runners
- Device emulation: [BITBOX]docs/BITBOX.md · [COLDCARD]docs/COLDCARD.md · [JADE]docs/JADE.md · [KEEPKEY]docs/KEEPKEY.md · [LEDGER]docs/LEDGER.md · [SPECTER]docs/SPECTER.md · [TREZOR]docs/TREZOR.md

## License

BHWI is released under the terms of the license in [LICENSE](LICENSE). The
BitBox02 integration additionally carries [BITBOX_LICENSE](BITBOX_LICENSE).