Files
libchat/bin/chat-cli
osmaczko 182e1f8b31 test: spawn a farm of chat-cli peers and print their addresses
Growing a group to a realistic size by hand needs that many clients running at once, and chat-cli cannot simply be backgrounded: it has no headless mode, crossterm opens /dev/tty when stdin is not a terminal, and an instance without one exits at launch. The account address is only reachable through the TUI as well, since nothing logs it and the data dir keeps chats alone.

So each peer gets its own pty, is asked for its address once its delivery node reports in, and is held open until the script is interrupted.
2026-08-21 22:37:34 +02:00
..

chat-cli

A terminal chat application built on top of libchat. End-to-end encrypted messaging in your terminal.

Building

chat-cli links the native logos-delivery library. The dev shell builds it and sets LOGOS_DELIVERY_LIB_DIR for you:

nix develop
cargo build --release -p chat-cli

Or build the library yourself and point LOGOS_DELIVERY_LIB_DIR at it:

nix build .#logos-delivery
LOGOS_DELIVERY_LIB_DIR=./result/lib cargo build --release -p chat-cli

The binary lands at target/release/chat-cli.

Transports

Both transports are compiled into the binary and selected at runtime via --transport:

Value (--transport) Description
logos-delivery (default) Embedded Waku node on the logos.dev network
file Shared directory; no network needed — great for local testing

Quick start

Run two instances in separate terminals:

# Terminal 1
cargo run -p chat-cli -- --name saro --port 60001

# Terminal 2
cargo run -p chat-cli -- --name raya --port 60002

For local-only testing without any network dependency, use the file transport:

# Terminal 1
cargo run -p chat-cli -- --name saro --transport file

# Terminal 2
cargo run -p chat-cli -- --name raya --transport file

Starting a conversation

Every conversation is an MLS group. A DM is a 1:1; a group is a named conversation. First share your address: type /account — it prints your address and copies it to the clipboard.

Direct message (1:1):

  1. Raya runs /account and shares her address.
  2. Saro types /dm <paste raya's address>.
  3. The chat opens on both sides; either can message.

Group:

  1. Saro types /new weekend to create a group named "weekend". A name is required; addresses can follow (e.g. Pax's) to invite people at creation.
  2. Saro types /add <raya's address> to invite Raya; the invite stays pending until the group commits it.
  3. /members lists the roster — Raya shows (pending) until the commit lands, then appears without it. Once committed, both can chat.

Optional: KeyPackage registry

When --registry-url <url> is set, the client publishes its MLS KeyPackage to the keypackage-registry service on startup so other clients can later fetch it by account_id. Without the flag, an in-memory registry is used and is only visible inside the local process.

# Terminal 1 — registry server (from a chat-store checkout)
cargo run -- --bind 127.0.0.1:18080

# Terminal 2 / 3 — chat clients pointing at it
cargo run -p chat-cli -- --name saro --transport file \
  --registry-url http://127.0.0.1:18080
cargo run -p chat-cli -- --name raya --transport file \
  --registry-url http://127.0.0.1:18080

The registry is a throwaway testnet helper; v0.3 replaces it with a λLEZ-based discovery service.

Options

Flag Default Description
--transport <kind> logos-delivery Transport to use (logos-delivery or file)
--data <dir> tmp/chat-cli-data Data directory (UI state and default SQLite path)
--db <path> <data>/<name>.db SQLite file for persistent identity
--preset <name> logos.dev logos-delivery network preset
--port <n> 60000 TCP port for the embedded logos-delivery node
--registry-url <url> (unset) Use the HTTP-backed keypackage-registry at this URL instead of the in-memory registry
--log-file <path> (stderr, off) Write logs to a file instead of stderr

Commands

Command Description
/help Show available commands
/account Show your account address (copies to clipboard)
/dm <address> Start a direct (1:1) chat
/new <name> [address...] Create a named group chat (optionally inviting members)
/add <address> Add someone to the active group
/members List members of the active conversation
/chats List all established chats
/switch <user> Switch active chat
/delete <user> Delete a chat session
/status Show identity and connection info
/clear Clear current chat's message history
/quit · Esc · Ctrl+C Exit

Storage

All data lives under tmp/chat-cli-data/ by default (override with --data):

Path Contents
<name>.db SQLite — identity keys, ratchet state, chat metadata (encrypted)
<name>_state.json UI state — message history, active chat
transport/<name>/ Inbox directory watched for incoming messages (file transport only)

The SQLite database can be inspected with DB Browser for SQLite: password chat-cli, cipher SQLCipher 4 defaults.

Architecture

bin/chat-cli/
├── src/
│   ├── main.rs           entry point, CLI arg parsing, runtime transport dispatch
│   ├── app.rs            application state and command handling
│   ├── ui.rs             ratatui terminal UI
│   ├── utils.rs          shared helpers
│   ├── transport.rs      module declarations
│   └── transport/
│       ├── file.rs       file-based transport
│       └── logos_delivery.rs   logos-delivery (Waku) transport + FFI
└── build.rs              links liblogosdelivery (LOGOS_DELIVERY_LIB_DIR required)