Motivation
--exec drove nearly the entire post-1.0.0 UX audit and is great for CI/batch functional tests — deterministic, zero-dependency, one process per scenario. But it hit a repeatable ceiling in specific ways that caused real friction (and a couple of false positives) during the audit. Capturing the idea of a small persistent command mode to complement it.
Where --exec hits its ceiling
- Statelessness.
--exec is a pre-scripted batch — you write the whole command list up front and read the result at the end. You can't observe state, then branch on it. "Do X, look, decide next" requires many separate processes.
- Async / timing. PTY output, debounced search, file watchers, LSP are all async;
--exec only has fixed wait N guesses.
BUG-057 (terminal focus after dialog dismiss) did not reproduce in the batch harness due to timing.
BUG-031 (deleted-file watcher warning) couldn't get a functional test — needed a backgrounded shell rm mid-session, which the one-shot batch can't do.
- Input fidelity. Clicks are always
ModNone (no Alt/Ctrl/Shift-click → Alt+Click add-cursor untestable), no drag verb (drag-selection unprobed), and shift+tab synthesizes KeyTab+ModShift not KeyBacktab (BUG-004 needed an e2e event-injection test).
- Rich introspection — caused actual false positives. Screenshots carry no color/style info:
BUG-033 (CJK tree alignment) was masked by the char-grid screenshot.
BUG-035 (Quick Open reveal) was over-reported as a bug — the active-file highlight actually works, the agent just couldn't see it.
- The debug dump was extended 3x mid-audit (buffer text, multicursor, viewport) and still lacks: search state, fold ranges, overlay rects/types, per-cell color;
focus reports "other" for most non-editor widgets.
Proposal
Not either/or, and probably not full HTTP:
- Keep
--exec for CI batch/functional tests.
- Add a persistent stdin-driven command mode — essentially
--exec as a REPL instead of one-shot: read one JSON command per line, execute it through the real event loop (this also fixes the synchronous-exec-skips-render class that produced stale-status/word-wrap false positives), and emit the debug state as JSON after each command. Unix socket or plain stdin/stdout JSON-RPC — no HTTP ceremony or port management.
- Richer input verbs: click-with-modifiers, drag, raw key events (incl.
KeyBacktab).
- Extend the debug state (needed regardless of transport): per-cell style/color, search state, fold ranges, overlay rects/types, precise focus.
- Reserve HTTP for if language-agnostic or remote clients are ever wanted.
Payoff
- Enables stateful, branch-on-observed-state automation (interactive test harnesses and agent-driven driving of the real editor).
- Handles async areas (PTY/terminal/watchers/LSP) by awaiting settling state instead of guessing
wait N.
- Could consolidate/replace the flaky
tui-use PTY integration tests (LSP, bracketed paste, external changes) with direct structured state — no terminal parsing.
Scope note
The color/search/fold introspection gaps are debug-dump content, not transport — worth doing either way. The transport change (persistent stdin/socket loop through the real event loop) is the small, high-leverage piece.
Context: surfaced during the post-1.0.0 UX audit (see audit/2026-07-12-ux-bug-audit.md).
Motivation
--execdrove nearly the entire post-1.0.0 UX audit and is great for CI/batch functional tests — deterministic, zero-dependency, one process per scenario. But it hit a repeatable ceiling in specific ways that caused real friction (and a couple of false positives) during the audit. Capturing the idea of a small persistent command mode to complement it.Where
--exechits its ceiling--execis a pre-scripted batch — you write the whole command list up front and read the result at the end. You can't observe state, then branch on it. "Do X, look, decide next" requires many separate processes.--execonly has fixedwait Nguesses.BUG-057(terminal focus after dialog dismiss) did not reproduce in the batch harness due to timing.BUG-031(deleted-file watcher warning) couldn't get a functional test — needed a backgrounded shellrmmid-session, which the one-shot batch can't do.ModNone(no Alt/Ctrl/Shift-click → Alt+Click add-cursor untestable), no drag verb (drag-selection unprobed), andshift+tabsynthesizesKeyTab+ModShiftnotKeyBacktab(BUG-004needed an e2e event-injection test).BUG-033(CJK tree alignment) was masked by the char-grid screenshot.BUG-035(Quick Open reveal) was over-reported as a bug — the active-file highlight actually works, the agent just couldn't see it.focusreports"other"for most non-editor widgets.Proposal
Not either/or, and probably not full HTTP:
--execfor CI batch/functional tests.--execas a REPL instead of one-shot: read one JSON command per line, execute it through the real event loop (this also fixes the synchronous-exec-skips-render class that produced stale-status/word-wrap false positives), and emit the debug state as JSON after each command. Unix socket or plain stdin/stdout JSON-RPC — no HTTP ceremony or port management.KeyBacktab).Payoff
wait N.tui-usePTY integration tests (LSP, bracketed paste, external changes) with direct structured state — no terminal parsing.Scope note
The color/search/fold introspection gaps are debug-dump content, not transport — worth doing either way. The transport change (persistent stdin/socket loop through the real event loop) is the small, high-leverage piece.
Context: surfaced during the post-1.0.0 UX audit (see
audit/2026-07-12-ux-bug-audit.md).