Replace the current tmux-driven multi-process architecture with one gsdv process that owns all UI state and renders every panel through Ratatui.
The replacement should keep the current product behavior:
- left outline / slide tree
- markdown preview
- editor/content terminal panel
- reviewer in GSD mode
- reviewer in git mode
- global-ish shortcuts such as
Ctrl+F1,Ctrl+F2,Ctrl+F3
But it should remove these implementation dependencies:
- tmux windows
- tmux panes
- tmux key bindings
- pane titles as state
- temporary tmux windows
- repeated
gsdvsubcommands for panel switching - temp files as primary UI state
Most recent bugs came from tmux orchestration, not from core UI logic.
Observed failure classes:
- Stale tmux global key bindings pointed at an old project directory.
Ctrl+F1depended on pane titles and temp-window parking state.- Bad states like "two view panes and no editor pane" were possible.
editor-returncould restore an empty parked pane into the content area.reviewerandmarkdown-viewrequired separategsdvchild processes.- tmux session options, pane cwd, pane title, and temp state files could disagree.
These are structural issues. More patches will keep adding recovery paths rather than eliminating the failure mode.
One process:
gsdv
AppState
EventLoop
Layout
Panels
OutlinePanel
OverviewPanel
MarkdownPanel
ReviewerPanel
TerminalPanel(content/codex/editor/shell)
Ratatui owns the full screen layout.
tui-term owns terminal emulation inside terminal panels, following the smux example style:
TerminalPanel
portable-pty child process
vt100 Parser
tui_term::widget::PseudoTerminal render
input encoder
resize bridge
No tmux is involved.
These panels should remain native Ratatui views:
- outline / slide tree
- overview / progress dashboard
- reviewer GSD mode
- reviewer git mode
- markdown preview
- help overlay
- command/status line
These are deterministic UI components and should not run as subprocesses.
Only interactive child processes should use tui-term:
codex- shell
- vim/nvim if we keep external editor behavior
Use the tui-term smux example as the baseline, not the simpler ls examples. The smux example is closer to what we need because it handles:
- long-running PTY processes
- keyboard forwarding
- resize
- redraw signaling
- multiple panes as a concept
src/
app/
mod.rs
state.rs
event_loop.rs
layout.rs
commands.rs
panels/
mod.rs
outline.rs
overview.rs
markdown.rs
reviewer.rs
terminal.rs
help.rs
terminal/
mod.rs
pane.rs
pty.rs
input.rs
render.rs
reviewer/
app.rs
diff.rs
git.rs
provenance.rs
Notes:
- Existing
src/reviewer/*can mostly survive, but should stop owning terminal lifecycle. - Existing
src/markdown_view.rsshould becomepanels/markdown.rs. - tmux-specific code in
src/main.rsshould be deleted, not moved. main.rsshould become thin: parse args, initializeApp, run event loop.
Central state should replace tmux pane state:
struct AppState {
project_dir: PathBuf,
focused_panel: PanelId,
layout_mode: LayoutMode,
outline: OutlineState,
overview: OverviewState,
markdown: MarkdownState,
reviewer: ReviewerState,
terminal: TerminalPanelState,
}Important invariants:
- There is exactly one source of truth for current file.
- There is exactly one source of truth for current view mode.
- There is exactly one source of truth for current reviewer mode.
- No pane title or temp file should be required to decide what the UI is showing.
Replace with a TerminalPanel running codex or shell.
The current content_panel_command() becomes TerminalPanel::spawn_codex(args).
Two possible approaches:
- Keep external vim/nvim inside
TerminalPanel. - Later replace with native editor widget.
For this reset, use option 1. It is less scope.
Replace with native MarkdownPanel.
Ctrl+F1 toggles:
TerminalPanel(editor) <-> MarkdownPanel(current_file)
No subprocess markdown-view.
No toggle-markdown-view subcommand.
No editor-return subcommand.
Reviewer becomes a native panel/view inside the same app.
Ctrl+F3 should switch to reviewer git mode.
Clicking a phase should switch to reviewer GSD mode with that phase.
No reviewer tmux window.
No reviewer subcommand required for normal use.
Proposed global keys:
Ctrl+F1: toggle current file editor/markdown previewCtrl+F2: show help overlayCtrl+F3: open reviewer in git modeEsc: close overlay or return focus to previous panelTab/Shift+Tab: move focus between panels
Panel-local keys:
- Outline keeps
j/k, arrows, enter, space expand/collapse. - Reviewer keeps existing navigation.
- TerminalPanel forwards almost everything to child process unless wrapper key is reserved.
Use a structure modeled after tui-term's smux example:
struct TerminalPanel {
parser: Arc<RwLock<vt100::Parser>>,
writer: Sender<Bytes>,
master: Box<dyn MasterPty>,
child: Box<dyn Child>,
title: String,
focused: bool,
last_area: Rect,
}Responsibilities:
- spawn child process with PTY
- read PTY output on background thread
- feed bytes to
vt100::Parser - send terminal query replies if required by parser/library
- write encoded key input to PTY
- resize PTY and parser when panel area changes
- render
PseudoTerminalinto Ratatui frame
Input encoding should start from the tui-term smux example, then be extended for:
- Ctrl keys
- Alt keys
- Enter/backspace/delete
- arrows/home/end/page
- paste
- bracketed paste if needed
- function keys if needed
We already know simple tui-term/ratkit spikes can have issues with Codex terminal queries and color assumptions.
The reset should still use tui-term smux as the first implementation because it is the closest ratatui-native path. But it must include a compatibility gate:
Codex is acceptable only if:
- input prompt colors are correct enough
- typed input is visible
- Codex does not hang on terminal queries
- resize works
- paste works
- Ctrl+C behavior is acceptable
- alternate screen and scrollback do not corrupt layout
If this fails, do not reintroduce tmux. Instead replace the TerminalPanel backend behind the same interface:
trait TerminalBackend {
fn spawn(...);
fn resize(...);
fn write_input(...);
fn render(...);
}Possible backend replacement:
alacritty_terminalwezterm-term
The UI architecture should not depend on which terminal backend wins.
Move existing logic without changing behavior:
- move outline code out of
main.rs - move overview code out of
main.rs - move markdown view into a panel module
- keep reviewer module as-is internally
Success criteria:
- tests still pass
- no tmux behavior changed yet
Create single-process layout that can render:
- outline on left
- overview on right/top
- placeholder content/editor area
At this stage, content can still be placeholder text.
Success criteria:
- app runs without tmux for outline + overview
- file selection state is in memory
Ctrl+F2help works natively
Embed current markdown renderer as a native panel.
Success criteria:
- selecting a markdown file opens preview in main area
- no
markdown-viewsubcommand - no tmux panel swap
Implement TerminalPanel using tui-term smux pattern.
Start with sh, then test codex.
Success criteria:
- shell starts
- input works
- resize works
- process exits cleanly
- Codex starts
Replace:
open_editor_panelopen_view_paneltoggle_markdown_viewreturn_editor_paneleditor_statetemp filesoutline_active_filetemp file as primary state
With in-memory mode transitions:
EditorTerminal(current_file) <-> MarkdownPanel(current_file)
ContentTerminal(codex)
Success criteria:
Ctrl+F1always toggles reliably:wqcannot blank content because content is not a tmux pane- no tmp window
- no pane title dependency
Move reviewer into main app as a native route/panel.
Modes:
- phase click -> GSD reviewer
Ctrl+F3-> git reviewergcan still toggle modes when phase context exists
Success criteria:
- reviewer no longer opens a tmux window
- git reviewer works without GSD
- phase reviewer still works
Remove:
- tmux bootstrap
- tmux pane/window helpers
- tmux key bindings
- tmux state files
- hidden subcommands used only for tmux orchestration
Potentially keep hidden subcommands only if still useful for debugging.
Success criteria:
rg tmux src/returns no production references- app runs directly in current terminal
- all tests pass
Core UI:
- open app from normal shell
- browse outline
- select project markdown file
- select
~markdown file - preview markdown
- toggle preview/editor
- open reviewer git mode
- open reviewer GSD mode from phase click
TerminalPanel:
- shell input
- vim/nvim input
- Codex input
- Ctrl+C
- paste
- resize
- child exit
- restart child
- Unicode rendering
- colors
Regression cases from current tmux implementation:
- no stale project-dir in shortcuts
- no empty content panel after
:wq - no two-view/no-editor bad state
- no temp window state mismatch
- no pane title dependency
- no need to press shortcut multiple times
Do not delete tmux code until the single-process path can run:
- outline
- markdown preview
- git reviewer
- GSD reviewer
- shell TerminalPanel
- Codex TerminalPanel
If Codex fails in tui-term, keep the native app architecture and swap only the terminal backend.
The final app should be:
one process
one event loop
one state tree
ratatui-native panels
tui-term-backed child terminal panel
zero tmux orchestration
This is the path that removes the class of bugs caused by tmux pane state drift.