Expand description
Turn detection for interactive TUIs piloted through the PTY.
“Has the program finished this turn and is it ready for the next input?” is
the core question when driving a full-screen TUI (the claude CLI, codex,
a REPL, …) like a human operator. We answer it with a hybrid signal:
- a generic quiescence check (the rendered screen stopped changing), handled by the caller, plus
- pluggable per-app recognizers here that read the rendered screen and
classify it as
TurnState::Busy,TurnState::AwaitingInputorTurnState::AwaitingApproval.
Recognizers operate on already-rendered, ANSI-stripped screen lines, so they never deal with escape codes — only with the visible text a human sees.
Structs§
- Antigravity
Recognizer - Recognizer for the
agy(Antigravity CLI, Gemini) TUI. Best-effort. Unlike claude/codex (Ink, alt-screen + in-place redraw), agy renders in append mode inside winx’s PTY: spentGenerating…/esc to cancelframes ghost into later screens and are never cleared. We therefore lead with the idle hint? for shortcuts, which only sits at the bottom of the screen when input is actually ready — a busy turn pushes it out of the tail — and only then fall back to the busy markers. Markers verified against a real agy 1.0.8 (Gemini 3.5 Flash) session captured through winx. - Auto
Recognizer - Runs every app-specific recognizer and combines their verdicts by priority:
Busy>AwaitingApproval>AwaitingInput>Unknown. A recognizer that sees the app working therefore always wins over one that only sees a (possibly stale) prompt glyph — soautonever reports a busy app as ready, while still falling back toUnknown(quiescence) for an unknown TUI. - Claude
Recognizer - Recognizer for the
claudeCLI (Ink/React TUI). Markers verified against a real claude v2.1.x session captured through winx: - Codex
Recognizer - Recognizer for the
codexCLI (Ink TUI). Markers verified against a real codex-cli 0.139.0 (gpt-5.5) session captured through winx: - Generic
Configurable - A recognizer built from marker strings/regexes in config
(
crate::types::TurnRecognizerMarkers), sowait_for_turncan pilot an arbitrary TUI without bespoke code. Same scan discipline as the built-ins: busy across the whole screen (a long response can push its footer out of the tail), approval/input tail-scoped so a stale scrollback prompt can’t fire. - Generic
Recognizer - No app knowledge: always
TurnState::Unknownso the caller decides purely by quiescence. Correct (if conservative) for any TUI.
Enums§
- Turn
State - What an interactive program is doing right now, inferred from the screen.
Traits§
- Turn
Recognizer - Reads a rendered screen (ANSI already stripped, one
Stringper line) and classifies the current turn state for a specific kind of TUI.
Functions§
- recognizer_
for - Build the recognizer for a hint string (
auto|claude|codex|generic). Unknown hints fall back toauto.