Architecture

The Elm Architecture (TEA) #

All state lives in a single App model. Events become messages, update() applies them, view() renders the result.

event loop
Event  Message  update(model, msg)  view(model)  Frame

TEA makes state transitions explicit and testable. Every input has a traceable path from event to screen change. There's no hidden state scattered across components.

Event loop

main.rs
tokio::main  init backend (LocalTmuxBackend)
   open SQLite DB
   init terminal
   spawn/restore sessions
   loop {
    draw frame  poll crossterm events (10ms)
     convert to AppMessage
     app.update()
     app.tick()
  }
   app.shutdown() (detach sessions)
   restore terminal

Module Structure #

Dependencies flow strictly one-directionally. Enforced by tests/architecture_rules.rs .

dependency rules
session  ← pure data types, no project-local imports
agent    ← imports session only (NEVER ui or git)
ui       ← imports session only (NEVER agent or git)
app      ← coordinator, imports all modules

Module responsibilities

Module Responsibility
app/ Model ( App struct), Update ( AppMessage + handlers), View. Owns all state, coordinates side effects.
agent/ Side-effect layer. AgentProvider trait abstracts CLI command construction; GenericProvider launches any agent from its AgentDef . agent_config::load_or_seed reads agents.toml . Session wraps SessionBackend , backed by LocalTmuxBackend ( tmux -L thurbox ).
session/ Plain data types: SessionId , SessionStatus , SessionInfo , SessionConfig , AgentDef / AgentRegistry (declarative agent definitions). No logic beyond pure helpers.
ui/ Pure rendering functions. layout.rs computes panel areas (responsive breakpoints). Widgets: project_list, terminal_view, info_panel, status_bar.
cli/ Headless automation ( thurbox-cli binary). Session, automation, and editor subcommands sharing the TUI's SQLite database.

Session Pipeline #

A SessionBackend trait abstracts session lifecycle. The default is LocalTmuxBackend ( tmux -L thurbox ). vt100::Parser interprets escape sequences, tui_term::PseudoTerminal renders into ratatui.

Backend trait methods

  • check_available — verify backend prerequisites
  • ensure_ready — initialize backend resources
  • spawn() — returns (backend_id, output_reader, input_writer)
  • adopt() — reconnect to existing session, returns initial screen content
  • discover() — list existing sessions for restore-on-startup
  • resize() — update terminal dimensions
  • detach() — stop streaming without killing session
  • kill() — permanently destroy session

tmux details

Control mode ( -C ) supports multiple concurrent client connections. Output arrives as %output notifications (octal-encoded), input is sent via send-keys -H (hex-encoded). Configuration on init includes remain-on-exit on , extended-keys on , and flow control via pause-after .

Session Backend #

Session lifecycle (spawn, adopt, resize, kill, detach, discover) is abstracted behind a SessionBackend trait. The only implementation is LocalTmuxBackend , which runs every session in a dedicated tmux -L thurbox server. The trait boundary keeps the app layer transport-agnostic.

Async Runtime #

The app runs on tokio's multi-threaded runtime. PTY read loops run inside spawn_blocking (blocking I/O in a threadpool), while PTY write and event handling run in tokio::spawn (async).

PTY reads are blocking by nature. Putting them in spawn_blocking prevents stalling the async executor and freezing the UI.

Persistence #

All state is stored in SQLite at ~/.local/share/thurbox/thurbox.db . Multiple instances synchronize via PRAGMA data_version polling (250ms). SQLite WAL mode handles concurrent access.

Multi-instance sync

  • Database : Atomic transactions, no race conditions
  • Session I/O : Each instance independently connects to tmux control mode. Tmux broadcasts output to all clients.
  • Input : Commands serialized by tmux (same as tmux attach with multiple clients)

Core Principles #

Non-negotiable rules that define what Thurbox must always be. Each has an automated enforcement mechanism.

# Principle Enforcement
1 Crash-free operation Clippy + code review
2 Module isolation tests/architecture_rules.rs
3 Zero-warning policy clippy -D warnings + RUSTDOCFLAGS="-D warnings"
4 Permissive licenses only cargo-deny check bans licenses
5 Zero known vulnerabilities cargo-deny check advisories
6 Conventional commits cocogitto ( cog verify )
7 TEA as single pattern Architecture tests + code review
8 Backend-first sessions Code review
9 Logging never touches stdout Code review
10 Test-driven development cargo-nextest
11 Deterministic CI Scripts over LLMs
12 Tag-based versioning build.rs + release workflow

Key technical details

  • MSRV: 1.75, Edition 2021
  • Async runtime: tokio (multi-threaded)
  • Terminal state: vt100::Parser + tui_term::PseudoTerminal
  • Logging: file-based at ~/.local/share/thurbox/thurbox.log
  • Panic hook restores terminal before printing
  • Requires tmux >= 3.2