You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
wait_for_content_change: surface pane death and respawn as ToolError for parity with wait_for_text #53
wait_for_text raises ToolError when the pane dies (#{pane_dead}=1), is respawned (#{pane_pid} changes), or has its history shrunk (clear-history — history_size drops below entry baseline). wait_for_content_change does none of this — it polls capture_pane() until content differs or timeout. If the pane dies mid-wait, the tool returns changed=False after the full timeout instead of surfacing the lifecycle event.
An agent using wait_for_content_change to confirm "the pane is doing something" has no signal that the underlying process has exited or been swapped. Same footgun the wait_for_text lifecycle detection was added to address — different tool, identical mechanism.
Proposed fix
Read a small per-tick state snapshot via one display-message round-trip:
"#{pane_pid}|#{pane_dead}"
Cache baseline_pid at entry. Re-read each tick. Raise ToolError on:
state.pane_dead == True — "pane {pane_id} died during wait" (same message/shape as wait_for_text)
state.pane_pid != baseline_pid — "pane {pane_id} was respawned during wait (pid X -> Y)"
No baseline-anchor math needed. wait_for_content_change's "any change anywhere" semantics are unaffected — the lifecycle check is orthogonal to the capture-diff comparison the tool already does.
Source pointers at tmux SHA 134ba6c
#{pane_dead} and #{pane_pid} are stable format strings (see format.c)
Adds one display-message round-trip per tick to wait_for_content_change (currently the tool issues only capture_pane per tick). The cost is symmetric with wait_for_text — same number of subprocesses per poll.
Adds two regression tests (death + respawn) mirroring the existing wait_for_text ones.
Recommendation
Defer until an agent flow asks for it OR a small refactor opportunistically lands the parity. Filed as a deferred enhancement so the inconsistency doesn't get lost. The downstream wait_for_text PR documents the gap by analogy; this issue is the standalone tracking point.
Why this is non-duplicative
Cross-checked against the deferred wait-family issues (#50, #51, #52) and libtmux #671:
Independent confirmation that the silent-miss path described above is real:
Reproduced blank-to-blank respawn: PID changed, content stayed blank, and the tool returned (changed=False, timed_out=True).
This is exactly the failure mode the parity fix is intended to close. wait_for_text already raises ToolError on pane respawn (via state.pane_pid != baseline_pid) — wait_for_content_change needs the same lifecycle check. The "any change anywhere" semantics are unaffected; only the failure-mode signal would be added.
Source pointers unchanged from the issue body: #{pane_dead} and #{pane_pid} format strings are stable across tmux 3.2a→master and are the same path wait_for_text already uses.
Triage pass (2026-05-24): keep this, but tighten the wording around the failure mode.
Current-code check: wait_for_text already treats pane_dead and pane_pid changes as lifecycle failures, while wait_for_content_change only diffs captures. tmux exposes both lifecycle facts as format fields (pane_dead, pane_pid) (tmux 134ba6c, tmux 134ba6c); libtmux also models them in its format metadata (libtmux f70cb62).
Overlap/value: this is a correctness parity issue, not an observation-architecture issue. #60 may reduce how often agents use blocking change waits, but it does not make wait_for_content_change safe to report lifecycle churn as ordinary content. Recommended action: snapshot lifecycle state at entry, raise ToolError on pane death or respawn/pid change, and test death, respawn, and normal content-change paths.
Activity
tony commentedon May 16, 2026
Reproduction confirmed (blank-to-blank respawn)
Independent confirmation that the silent-miss path described above is real:
This is exactly the failure mode the parity fix is intended to close.
wait_for_textalready raisesToolErroron pane respawn (viastate.pane_pid != baseline_pid) —wait_for_content_changeneeds the same lifecycle check. The "any change anywhere" semantics are unaffected; only the failure-mode signal would be added.Source pointers unchanged from the issue body:
#{pane_dead}and#{pane_pid}format strings are stable across tmux 3.2a→master and are the same pathwait_for_textalready uses.Pane(docs[wait_for_content_change]): note weaker baseline-loss detect…
tony commentedon May 24, 2026
Triage pass (2026-05-24): keep this, but tighten the wording around the failure mode.
Current-code check:
wait_for_textalready treatspane_deadandpane_pidchanges as lifecycle failures, whilewait_for_content_changeonly diffs captures. tmux exposes both lifecycle facts as format fields (pane_dead,pane_pid) (tmux134ba6c, tmux134ba6c); libtmux also models them in its format metadata (libtmuxf70cb62).Overlap/value: this is a correctness parity issue, not an observation-architecture issue. #60 may reduce how often agents use blocking change waits, but it does not make
wait_for_content_changesafe to report lifecycle churn as ordinary content. Recommended action: snapshot lifecycle state at entry, raiseToolErroron pane death or respawn/pid change, and test death, respawn, and normal content-change paths.