osmaczko c677cc9334
feat: introduce client event system (#106)
* chore(flake): accept extra system attr; add perl for openssl-sys build

forAllSystems calls the lambda with {system, pkgs}; strict
destructuring requires `..` to ignore the system attribute.

`pkgs.perl` is needed because openssl-sys is pulled vendored via
libsqlite3-sys / rusqlite / chat-sqlite, and its `perl Configure`
step needs FindBin.pm, which Fedora's system perl doesn't ship.

* feat: introduce client event system

- Core processing yields a `PayloadOutcome` enum — `Empty`, `Convo`, or
  `Inbox`. `ConvoOutcome` carries a conversation id and an optional
  decrypted `Content`; `InboxOutcome` adds a `NewConversation`
  (id + `ConversationClass`) for a peer-initiated conversation.
- Client translates `PayloadOutcome` into app-facing `Vec<Event>`
  (`ConversationStarted`, `MessageReceived`) at the boundary, so the
  application loop sees discrete events rather than core types.
- MLS group welcomes produce a `ConversationStarted` event with no
  initial content, fixing the silent-group-join case where the inbox
  layer dropped the observation.
- C FFI exposes an `EventList` opaque type with indexed accessors and
  an `Invalid` sentinel for out-of-bounds / non-applicable reads.
- Symmetric `Inbox` / `InboxV2` handlers: both return
  `Result<InboxOutcome, _>` and own the persistence + ephemeral-key
  cleanup for the conversations they create.
- Updated and simplified `docs/adr/0001-client-event-system.md`.

* chore(flake): bump nixpkgs to nixos-unstable-small

Temporary. The two crates.io UA fixes (NixOS/nixpkgs#512735 for
fetchCargoVendor's python-requests UA, NixOS/nixpkgs#524985 for
importCargoLock's curl UA) haven't propagated to nixos-unstable yet.
Switch to nixos-unstable-small and force logos-delivery to follow so
the smoketest gets the same fix. Revert once nixos-unstable catches up.

Refs:
- https://github.com/rust-lang/crates.io/issues/13482
- https://github.com/rust-lang/crates.io/issues/13783
- https://crates.io/data-access
2026-05-28 23:51:15 +02:00
..
2026-05-19 11:54:54 -07:00
2026-05-20 13:18:25 -07:00

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

  1. In Alice's terminal, type /intro — the bundle is copied to your clipboard automatically.
  2. In Bob's terminal, type /connect <paste bundle here>.
  3. Bob's "Hello!" message appears in Alice's terminal. Both can now chat.

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
--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)