Architecture
The Elm Architecture (TEA) #
All state lives in a single
App
model. Events become messages,
update()
applies them,
view()
renders the result.
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
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
.
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 attachwith 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