Root: mode stack, action dispatch, component tree (PLAN.md §6).
GitHub calls run on worker threads (blocking reqwest); results return
over an mpsc channel as AppEvents, drained once per event-loop tick.
Clipboard (plans/0003 §1): OSC 52 first — works over SSH and tmux
with zero deps — plus a best-effort Wayland/X fallback.
ROOTLE_CLIPBOARD=<path> redirects to a file for e2e/CI.
Command registry (plans/0003 §3): the : command line’s option
list is derived from this table — one source of truth, like the
keymap tables. Adding a command = one row + one RunCommand arm.
Opt-in diagnostic sessions and the common terminal/headless draw boundary.
Storage, ordering and limits live in rootle-trace; application observations
belong to the app and its providers. No trace output goes to the TUI stream.
Editor integration (PLAN.md §12): materialize the cached blob to a
real file, suspend the terminal, spawn the editor read-only, resume
with a full redraw — the one legitimate terminal.clear().
Headless driver (plans/0023 M1): scripted keys in, cell-grid
frames + state JSON out. Deterministic — no PTY, no raw mode, no
alternate screen. The TUI and this driver share one input path:
both feed App::handle_event, and both render through App::render
(here onto ratatui’s TestBackend instead of a terminal).
Binding tables are both the dispatcher and the help source. Aliases,
modifiers and two-key sequences are described once; contexts supply
typed commands to their state machines.
Provider composition root (plans/0005, 0024 M5): the one place
concrete implementations meet the app. build() reads the config
and hands back an Arc<dyn Provider> — the trait, wire types, and
errors live in the rootle-provider crate; the implementations in
rootle-github (in-tree reference) and rootle-stdio (external
NDJSON-RPC children); the binary manager in rootle-manager.
Persisted app state: ~/.local/state/rootle/state.json (PLAN.md §10).
Distinct from the cache — state survives cache eviction. Atomic
tmp+rename writes on state transitions; corrupt/missing → defaults.
Hone is the default, alongside all six original Strop palettes and
the existing Catppuccin, Dracula, One, Gruvbox, Nord, Tokyo Night,
Solarized and GitHub palettes.
~/.config/rootle/themes/<name>.toml overrides merge on top of the
embedded base — fork a builtin by writing a file with its name.