Needs [Rust](https://rustup.rs/) **1.87+** (`edition = "2024"`). A distro `rustc` is fine if `rustc --version` reports 1.87 or newer. Do not install `tor` for this app.
```bash
# rustup (if you do not already have cargo)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
On start you should see `onionwire: bootstrapping Arti…` on stderr. First bootstrap can take a minute. Data lives in `ONIONWIRE_HOME` if set, otherwise `~/.local/share/onionwire/` (`onionwire.db` + Arti state, mode 0700). First open creates an ed25519 identity key. That key **is** you.
A friend is an ed25519 pubkey (`UNIQUE(pubkey)`). The `.onion` on that row is only where they are reachable right now. Re-scanning the same `k` updates the locator; it never creates a second person.
Focus starts on the composer so typing works immediately. `Tab` cycles panes; `j`/`k` and arrows only move the focused pane (roster or chat). `1`/`2`/`3` switch focus when you are not typing in the composer. `?` opens help from every screen except paste (so a payload can contain `?`).
`F3` pastes a payload. Unknown `k` asks for approval. Same `k` already in the roster updates `onion` only.
## F4 rotate onion
`F4` is a locator change, not a new identity. Confirm by typing `ROTATE` (Enter alone does nothing).
- Your identity fingerprint stays the same.
- A new onion is published; the old one is hard-cut (no dual-host grace).
- Online friends get a signed `loc` frame.
- Offline friends cannot find you until they rescan the new QR. There is no directory.
## Fail closed
If a peer’s onion is down, send fails. v1 has no outbox, no retry queue, no DHT, no name server.
## Wipe
Composer (bottom of the roster screen):
-`/wipe` — confirm by typing `WIPE`. Overwrites the message log and `VACUUM`s. Identity key and friends stay.
-`/wipe-all` — confirm by typing `WIPEALL`. Deletes the data dir. Next start is a **new person** (new identity key). Esc cancels. Nothing is wiped without confirm.
Push a version tag. GitHub Actions builds Linux binaries and publishes a GitHub Release.
```bash
# version in Cargo.toml must match the tag without the leading v
git tag v0.1.0
git push github v0.1.0 # GitHub remote — this is what triggers CI
```
Workflows:
- [`.github/workflows/ci.yml`](.github/workflows/ci.yml) — `cargo test --locked` and clippy on `main` / PRs (ignored Tor-live tests are not run).
- [`.github/workflows/release.yml`](.github/workflows/release.yml) — on `v*.*.*` tags, `cargo build --release` for `x86_64-unknown-linux-gnu` and `aarch64-unknown-linux-gnu`, strip, sha256, attach to the release.
Do not run `cargo publish`; `publish = false`.
## Troubleshooting
| Symptom | What to do |
|---|---|
| `GLIBC_… not found` | Binary is newer than your libc. Build from source (Option B). |
| `sha256sum: FAILED` | Re-download both the binary and `.sha256`; run the check in the same directory. |
| Hang on `bootstrapping Arti…` | Need outbound network. First consensus fetch is slow. Wait a couple of minutes; if it never publishes, it fails closed — no C-tor fallback. |
| `onionwire: unknown argument` | No subcommands. Flags are `--version` / `--help` only, then the TUI. |
| Blank / broken TUI | Run in a real terminal emulator, not `nohup` / systemd without a TTY. |
| Two chats, same laptop | Separate `ONIONWIRE_HOME` per process. |
| Friend cannot find you after F4 | Expected if they were offline. They must F3-paste the new QR. Same `k` updates the row. |