Type: enhancement · Tier: deferred · Tool: wait_for_text
What's happening
wait_for_text deliberately skips the cursor row at entry via:
start_line = baseline_abs - state.history_size + 1
The + 1 avoids false-matching the row the cursor sat on at entry — typically the prompt line that contains the typed command echo (which already includes the pattern as a substring). This is the documented "same-row blind spot."
But this means several common CLI output shapes are invisible to the wait:
printf OK (no trailing newline — stays on the cursor row)
\\r-progress updates and spinners (rewrite the same row)
- Single-line status redraws (cursor returns to column 0 and overwrites)
- Some prompt redraws that paint over the prompt line
Why anchor invariance holds for the baseline row
tmux's screen_write_reverseindex only scrolls within [s->rupper, s->rlower] via grid_view_scroll_region_down, which is pure grid_move_lines — no hsize change. \\r rewriting also doesn't touch hsize. So the absolute baseline anchor (hs0 + cy0) remains pointing at the same grid row even when that row is repainted; we just don't capture it.
Proposed surface
wait_for_text(pattern=\"OK\", include_baseline_row=True)
When set, the implementation:
- At entry: capture the baseline row's current content (one extra
capture-pane -S cy0 -E cy0).
- Each tick: re-capture the baseline row and diff against the entry snapshot.
- Match the pattern against the diff (i.e., the bytes that changed), not the whole row.
This avoids false-matching the typed echo (which is in the entry snapshot and therefore not in the diff) while picking up legitimate same-row writes.
Trade-offs
- Adds one
display-message / capture-pane round-trip at entry (small).
- Adds row-content comparison per tick (cheap).
- Diff predicate has to handle the wraparound case for narrow panes where the "baseline row" might itself wrap.
- New public parameter on a stable-feeling API. Worth the surface only if real agent flows hit the limitation.
Recommendation
Defer until a real agent flow asks for it. Today the documented escape hatch is wait_for_content_change for "any change anywhere" and the sentinel pattern for "a unique marker I authored." If/when same-row writes become the question, this is the cleanest answer.
References
- tmux reverse-index (no hsize touch): screen-write.c#L1419
- tmux scroll-region-down (pure grid_move_lines): grid-view.c#L127
- Current docstring of the blind spot: see
wait_for_text Notes section
Type: enhancement · Tier: deferred · Tool:
wait_for_textWhat's happening
wait_for_textdeliberately skips the cursor row at entry via:The
+ 1avoids false-matching the row the cursor sat on at entry — typically the prompt line that contains the typed command echo (which already includes the pattern as a substring). This is the documented "same-row blind spot."But this means several common CLI output shapes are invisible to the wait:
printf OK(no trailing newline — stays on the cursor row)\\r-progress updates and spinners (rewrite the same row)Why anchor invariance holds for the baseline row
tmux's
screen_write_reverseindexonly scrolls within[s->rupper, s->rlower]viagrid_view_scroll_region_down, which is puregrid_move_lines— nohsizechange.\\rrewriting also doesn't touchhsize. So the absolute baseline anchor (hs0 + cy0) remains pointing at the same grid row even when that row is repainted; we just don't capture it.Proposed surface
When set, the implementation:
capture-pane -S cy0 -E cy0).This avoids false-matching the typed echo (which is in the entry snapshot and therefore not in the diff) while picking up legitimate same-row writes.
Trade-offs
display-message/capture-paneround-trip at entry (small).Recommendation
Defer until a real agent flow asks for it. Today the documented escape hatch is
wait_for_content_changefor "any change anywhere" and the sentinel pattern for "a unique marker I authored." If/when same-row writes become the question, this is the cleanest answer.References
wait_for_textNotes section