Skip to content

Architecture Overview

  • Privacy-first: No central servers, no telemetry, no metadata leakage
  • Encrypted everywhere: at-rest (SQLCipher), in-transit (Tor), end-to-end (Signal Protocol)
  • Pure P2P: Each user = one Tor hidden service
  • Unix-focused: Linux, macOS, BSD
User → TUI (ratatui) ─┐
CLI → Unix socket ─────┤→ Signal Protocol (E2E) → Tor Hidden Service → Peer
MCP → Unix socket ─────┘

When you send a message:

  1. You type in the TUI input bar
  2. The message is encrypted with Signal Protocol (Double Ratchet via libsignal-dezire)
  3. The ciphertext is wrapped in a versioned MessageEnvelope with protocol version, ratchet header, and type metadata
  4. It’s sent via the connection pool (reuses cached Tor circuits)
  5. If the peer is offline, it’s queued in the message queue with retries
  6. The peer’s Tor hidden service receives the envelope
  7. The peer decrypts with their Signal Protocol session
  8. The plaintext is stored in the encrypted SQLCipher database

The central App struct owns all runtime state: settings, database, identity keys, Tor client, hidden service, and message queue. App::new() initializes synchronously; Tor bootstrapping happens asynchronously via init_tor().

SQLCipher provides at-rest encryption. The schema (currently v9) includes tables for friends, conversations, messages, signal sessions, blocked users, channels, and a key-value settings store. FTS5 virtual tables enable full-text message search with auto-sync triggers.

Migrations run automatically from v2 through v9 on startup.

  • Connection Pool (pool.rs): Uses DashMap for lock-free concurrent access. Caches Tor circuits per peer (max 50). Idle connections evicted after 5 minutes. Retry-on-stale: dead connections are evicted and retried with a fresh circuit.
  • Rate Limiter (rate_limit.rs): Per-peer token bucket rate limiter (5 req/s sustained, 20 burst) to prevent abuse.
  • Message Queue (queue.rs): FIFO queue persisted in the database. Exponential backoff retries (30s base, doubles each attempt, capped at 15min, 24h expiry).
  • Framing (framing.rs): Length-prefixed TCP framing for message I/O over Tor streams.

13 message types: FriendRequest, FriendRequestAccept, FriendRequestReject, TextMessage, DeliveryReceipt, ReadReceipt, ChannelSubscribe, ChannelUnsubscribe, ChannelPost, ChannelSyncRequest, ChannelSyncResponse, ChannelPostReceipt, Presence.

All messages are wrapped in a versioned MessageEnvelope and JSON-serialized. Encrypted messages include a Double Ratchet header, base64-encoded ciphertext, and a type flag (PreKeyMessage or Message).

Extracted handler functions for friend requests, messaging, and channel sync. These are shared by both the TUI and daemon — ensuring consistent behavior regardless of how you interact with chattor.

A headless background process for scripting and automation. The daemon owns the same App state as the TUI but exposes it over a JSON-RPC 2.0 Unix socket instead of a terminal UI. Components:

  • Event Loop (event_loop.rs): tokio::select! loop handling incoming Tor messages, queue commands, presence ticks, and shutdown signals. Broadcasts message events to streaming listen clients.
  • RPC Server (rpc.rs, socket.rs): 15 JSON-RPC methods covering friends, messaging, channels, settings, and status. Unix socket with 0600 permissions (owner-only access).
  • PID File (pid.rs): Mutual exclusion — only one daemon per data directory.
  • Background Tasks (tasks.rs): Channel sync (every 5 min) and heartbeat presence.

Thin client that connects to the daemon’s Unix socket and issues JSON-RPC calls. Each CLI subcommand maps to one RPC method, formats the response, and exits. The listen subcommand streams incoming messages in real time.

Model Context Protocol server over stdio for AI agent integration. Exposes 9 tools (send_message, receive_messages, list_friends, etc.) that delegate to the daemon via the same Unix socket as the CLI. Protocol version 2024-11-05.

Built with ratatui. Layout: friends sidebar (left) + conversation/channel view (right). Modals for add friend, friend requests, identity, settings, and channel subscribe. Theme engine with 7 presets and TOML config override.

src/
├── app.rs # Application state
├── cli.rs # CLI parsing (clap, 12 subcommands)
├── client.rs # JSON-RPC client for daemon IPC
├── main.rs # Entry point, subcommand routing
├── crypto/ # Ed25519 identity, Signal Protocol
├── daemon/ # Headless daemon mode
│ ├── event_loop.rs # tokio::select! main loop
│ ├── pid.rs # PID file mutual exclusion
│ ├── rpc.rs # JSON-RPC 2.0 dispatch (15 methods)
│ ├── socket.rs # Unix socket server
│ └── tasks.rs # Background tasks (sync, heartbeat)
├── db/ # SQLCipher database, queries, schema
├── handlers/ # Shared message handlers (TUI + daemon)
│ ├── channels.rs # Channel sync requests
│ ├── friend_request.rs # Friend request lifecycle
│ └── messaging.rs # Message send/receive/queue
├── mcp/ # Model Context Protocol server
│ ├── server.rs # MCP stdio transport
│ └── tools.rs # 9 tool definitions + RPC mapping
├── net/ # Connection pool, message queue, framing
├── protocol/ # Friend codes, messages, friend requests
├── tor/ # Arti client, onion service, connections
└── ui/ # TUI layout, themes, modals