Architecture

Technical overview of repartee's internal design.

Technology stack

ComponentTechnology
LanguageRust 2024 edition
TUI frameworkratatui 0.30.2 with crossterm backend + ratatui-image 11.1.0
Web frontendLeptos 0.7 (WASM CSR) + Axum 0.8 + rustls (aws_lc_rs) + beamterm-renderer 1.0
Async runtimetokio (full features)
IRC protocolirc-repartee crate v1.5.2
ScriptingLua 5.4 via mlua 0.12.2
StorageSQLite via rusqlite 0.40.2 (bundled, WAL + FTS5)
EncryptionAES-256-GCM via aes-gcm 0.11.1 (log storage) + Ed25519 / X25519 / XChaCha20-Poly1305 (RPE2E v1)
Error handlingcolor-eyre + thiserror
ConfigTOML via serde

TEA architecture

repartee follows The Elm Architecture (TEA) pattern:

Model → Message → Update → View
  • Model: AppState -- all application state (buffers, connections, config)
  • Message: Events from IRC, keyboard, mouse, timers, web sessions, shell PTYs
  • Update: Event handlers that transform state
  • View: ratatui rendering functions that read state (and broadcast snapshots for web clients)

State is UI-agnostic -- the state/ module has no ratatui imports.

Module structure

src/
  main.rs              # Entry point, fork, terminal setup, CLI subcommands
  app/                 # Main event loop, App struct, event dispatch
  constants.rs         # APP_NAME and global constants
  config/              # TOML config loading & validation
  state/               # Application state (buffers, connections, sorting, typing, act)
  session/             # Detach/reattach infrastructure
    mod.rs             # Socket paths, session listing, PID liveness
    protocol.rs        # Shim ↔ backend message types (bincode framing)
    shim.rs            # Terminal shim (relay loop, splash, input)
    writer.rs          # SocketWriter (impl Write for socket output)
  irc/                 # IRC connection, event handling, formatting
    events.rs          # IRC message → state update
    mod.rs             # Connection setup, CAP negotiation, SASL, bouncer probe
    cap.rs             # IRCv3 CAP framework (30+ capabilities)
    isupport.rs        # ISUPPORT + draft/extended-isupport parsing
    batch.rs           # IRCv3 BATCH (netsplit/netjoin, chathistory, multiline, search)
    sasl.rs            # SASL PLAIN, EXTERNAL, SCRAM-SHA-1/256/512, ECDSA, OAUTHBEARER
    extban.rs          # Extended ban types ($a:account, etc.)
    flood.rs           # Flood protection & CTCP rate limiting
    netsplit.rs        # Netsplit detection
    ignore.rs          # Ignore list matching
    formatting.rs      # IRC formatting helpers
    whox.rs            # WHOX (extended WHO) tracking
  dcc/                 # DCC CHAT protocol (active & passive)
  e2e/                 # RPE2E v1 end-to-end encryption (Ed25519, X25519, XChaCha20-Poly1305)
  translate/           # Inline message translation (Lingva, Google, MyMemory, LibreTranslate)
  shrink/              # Automatic URL shrinking (is.gd)
  emote/               # Text emote dictionary & expansion
  image_preview/       # Inline & popup image rendering (Kitty, iTerm2, Sixel, halfblocks)
  shell/               # Embedded PTY terminal sessions (vt100 screen parser)
  spellcheck/          # Multi-language Hunspell spellchecker
  web/                 # Embedded HTTPS/WebSocket server, WebPush (RFC 8291), WASM bundle
  ui/                  # TUI rendering
    layout.rs          # Screen layout + regions
    tree_list.rs       # Tree & flat buffer sidebar
    nick_list.rs       # Right sidebar
    chat_view.rs       # Message display + inline image thumbnails
    bare_view.rs       # Bare mode (stripped chrome for clean text selection)
    shell_view.rs      # Embedded terminal PTY view
    settings_modal.rs  # Interactive /wizard & /config modal
    window_overlay.rs  # Searchable /window list popup overlay
    input.rs           # Command input + tab completion + multiline paste guard
    status_line.rs     # Bottom status bar (+typing, [E2E], [TR], [LAG], Act)
    topic_bar.rs       # Top topic display
    message_line.rs    # Single message rendering
    styled_text.rs     # Format string → ratatui spans
  theme/               # Theme loading + irssi-compatible format string parser
  scripting/           # Lua scripting engine
    engine.rs          # ScriptEngine trait + ScriptManager
    api.rs             # Event names & Lua API bindings
    event_bus.rs       # Priority-ordered event dispatch
    lua/               # Lua 5.4 backend (mlua 0.12.2)
  storage/             # SQLite logging + E2E keyring tables
    db.rs              # Database schema + migrations
    writer.rs          # Batched async writer
    query.rs           # Search + read queries
    crypto.rs          # AES-256-GCM encryption
    types.rs           # LogRow, StoredMessage
  commands/            # Command system
    parser.rs          # /command arg parsing
    registry.rs        # Command registration (80+ built-in commands)
    handlers_irc.rs    # IRC & IRCv3 commands (/join, /chathistory, /bouncer, /redact, etc.)
    handlers_ui.rs     # UI commands (/clear, /close, /wizard, /bare, /shell, etc.)
    handlers_admin.rs  # Admin commands (/set, /reload, /e2e, /translate, /script, etc.)
    handlers_dcc.rs    # DCC commands (/dcc chat, /dcc close, etc.)
    docs.rs            # Bilingual command documentation loader (EN + PL)

Session architecture

On startup, repartee forks into two processes:

repartee
  ├── Backend (child)     # headless daemon — IRC, state, socket listener
  │     └── Unix socket   # ~/.repartee/sessions/{pid}.sock
  └── Shim (parent)       # terminal bridge — renders UI, forwards input

The backend runs the tokio event loop, manages IRC connections, state, scripts, and logging. It listens on a Unix socket for shim connections.

The shim captures terminal events (keyboard, mouse, resize) and sends them to the backend as ShimMessage variants. The backend renders ratatui frames and sends raw terminal output back as MainMessage::Output. Communication uses length-prefixed bincode serialization.

On detach, the shim exits (shell gets its prompt back). The backend continues running. On reattach, a new shim connects to the socket. The shim sends a TerminalEnv snapshot (dimensions, font size, terminal type env vars) so the backend can adapt to the new terminal.

On SIGHUP (terminal closed unexpectedly), the backend auto-detaches instead of crashing.

Event flow

  1. Terminal events (keyboard, mouse) arrive via crossterm event::poll in a spawn_blocking thread (or via socket from the shim)
  2. Events are sent through a tokio mpsc channel to the main loop
  3. IRC events arrive via the irc crate's async reader, converted to IrcEvent enum variants
  4. The main loop in App::run() processes all events sequentially, updating AppState
  5. After each event batch, the UI is re-rendered from the current state

IRC connection layer

Each server connection spawns:

  • An async reader task that receives IRC messages and sends IrcEvent to a shared mpsc channel
  • Messages are sent through the irc crate's Sender stored in the connection state

All connections share a single event channel, with events tagged by connection_id.

Scripting architecture

ScriptManager
  └── Vec<Box<dyn ScriptEngine>>
        └── LuaEngine (mlua)
              ├── Per-script Lua environments (sandboxed)
              ├── Event handlers (priority-sorted, per-event)
              └── Command handlers

The ScriptEngine trait allows adding new languages (Rhai, etc.) by implementing the trait and registering with ScriptManager.

IRCv3 & Bouncer support

repartee implements 30+ IRCv3 and bouncer capabilities negotiated during connection via CAP LS 302 / REQ / ACK (plus dynamic CAP NEW / CAP DEL):

CapabilityDescription
multi-prefixMultiple mode prefixes per nick (e.g. @+nick)
extended-joinAccount name and realname in JOIN messages
server-timeMessage timestamps from the server
account-tagAccount name on every message
cap-notifyServer-side capability change notifications
away-notifyReal-time away status changes
account-notifyAccount login/logout notifications
chghostReal-time ident/hostname changes
setnameReal-time realname/gecos changes (/setname)
echo-messageAuthoritative echo of sent messages
invite-notifyNotifications for channel invites
batchGrouped message batches (netsplit, netjoin, chathistory, draft/multiline, soju.im/search)
labeled-responseRequest/response correlation via @label tags
userhost-in-namesFull user@host in NAMES replies
no-implicit-namesSuppresses automatic NAMES burst on JOIN
message-tagsArbitrary IRCv3 message metadata (+typing, +draft/reply, +draft/react, +draft/channel-context)
monitor / extended-monitorServer-side online presence watching (/monitor)
draft/chathistoryServer-side message history retrieval (/chathistory)
draft/event-playbackIncludes non-message events in history batches
draft/multilineMulti-line message transmission and assembly
draft/read-markerCross-device read position sync (MARKREAD)
draft/message-redactionServer-side message deletion (REDACT / /redact)
draft/account-registrationIn-band account registration (REGISTER / /register)
draft/metadata-2User and channel key-value metadata (METADATA / /metadata)
draft/extended-isupportExtended RPL_ISUPPORT token discovery via ISUPPORT
draft/webpushNative IRCv3 WebPush notifications
soju.im/bouncer-networksBouncer upstream network discovery and per-network sibling spawning (BOUNCER)
soju.im/bouncer-networks-notifyLive notifications of upstream network changes
soju.im/searchServer-side full-text log search (SEARCH / /bsearch)
soju.im/client-certClient TLS certificate fingerprint management (CERTFP / /bcertfp)

SASL mechanisms supported (strongest-first selection): ECDSA-NIST256P-CHALLENGE, SCRAM-SHA-512, SCRAM-SHA-256, SCRAM-SHA-1, EXTERNAL (client TLS certificate), OAUTHBEARER, and PLAIN.

WHOX (extended WHO) is auto-detected and used to populate account names and full user@host for nick entries.

Storage pipeline

AppState::add_message()
  → log_tx (tokio mpsc sender)
  → WriterTask (batches 50 rows / 1 second)
  → SQLite (WAL mode, FTS5 index)

Messages flow from the UI thread to the writer task asynchronously, ensuring zero UI blocking on disk I/O.