EmbeddedLogosDelivery now drives waku-bindings' LogosDeliveryCtx over the reliable channels API (channel_create/channel_send + onChannelMessageReceived) instead of the hand-written FFI, which is deleted (~1050 lines, including a byte-identical duplicate build.rs). Each conversation maps to one SDS channel. The node runs on a dedicated thread that is the sole caller of the ctx, with DeliveryService methods handing it commands over a queue. Every ctx call is blocking, and issuing one from libchat's inbound-draining thread — which subscribes while processing a received frame — wedges, because the call is made downstream of the node's own event dispatch. Serialising on one thread, decoupled from the caller and the callback, is what the previous transport did for the same reason, and it restores two-party delivery (join went from a deterministic hang to reliable; a message sent in an established conversation is received and displayed by the peer). chat-cli derives the node's storage path from its data dir: SDS state is a process-wide singleton keyed on that path, so two instances sharing it would each read the other's causal history and drop messages as replays. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ai43sF2rymPFMG9iki9fwL
chat-cli
A terminal chat application built on top of libchat. End-to-end encrypted messaging in your terminal.
Building
logos-delivery is exposed as a Nix package.
Build it once, then point LOGOS_DELIVERY_LIB_DIR at the result:
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 alice --port 60001
# Terminal 2
cargo run -p chat-cli -- --name bob --port 60002
For local-only testing without any network dependency, use the file transport:
# Terminal 1
cargo run -p chat-cli -- --name alice --transport file
# Terminal 2
cargo run -p chat-cli -- --name bob --transport file
Establishing a connection
- In Alice's terminal, type
/intro— the bundle is copied to your clipboard automatically. - In Bob's terminal, type
/connect <paste bundle here>. - Bob's "Hello!" message appears in Alice's terminal. Both can now 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 alice --transport file \
--registry-url http://127.0.0.1:18080
cargo run -p chat-cli -- --name bob --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 |
/intro |
Generate your introduction bundle (copies to clipboard) |
/connect <bundle> |
Connect to a user using their introduction bundle |
/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)