Skip to content

wait_for_content_change: surface pane death and respawn as ToolError for parity with wait_for_text #53

Closed

Description

@tony

Type: enhancement · Tier: deferred · Tool: wait_for_content_change

Problem

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)
  • Same detection path wait_for_text already uses — verified via test_wait_for_text_raises_on_pane_death and test_wait_for_text_raises_on_pane_respawn

Trade-offs

  • 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:

None of those address wait_for_content_change lifecycle parity.

Activity

  1. tony commented on May 16, 2026

    @tony
    MemberAuthor

    Reproduction confirmed (blank-to-blank respawn)

    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.

  2. tony commented on May 24, 2026

    @tony
    MemberAuthor

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions