tmux-python / tmux-python/libtmux

feat: Add Non-polling Waiters (Deterministic Channels & Delta-Polling)

Open
#673 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
1.2k
Forks
127
Avg merge
2h 13m
Merged PRs (30d)
1

Description

As libtmux has evolved with the 0.57.0 "Neo" ORM parity, we've solved the N+1 problem for object hydration. However, synchronizing with terminal output still largely relies on client-side loop polling via capture_pane().

We propose introducing a two-tier waiter system modeled after the patterns battle-tested in libtmux-mcp. This brings "Wait, Don't Poll" semantics natively to libtmux.

1. Best-of-Breed: Deterministic Channel Sync (Server.wait_for_channel)

For commands where the user controls the execution, we should avoid scraping scrollback entirely and rely on tmux's native OS-level IPC blocks.

  • The Concept: Bracket shell commands with tmux wait-for -S <channel> and block the libtmux client until the signal fires.
  • libtmux-mcp Prior Art: See wait_for_tools.py which implements wait_for_channel via subprocess.run(timeout=timeout).
  • tmux Internals: This leverages tmux's cmd-wait-for.c (tmux/tmux@18ddda4), allowing the Python thread to sleep completely until tmux wakes it.
  • Proposed API:
    pane.send_keys("pytest; tmux wait-for -S tests_done")
    server.wait_for_channel("tests_done", timeout=60.0)
    
2. Intelligent Fallback: Delta Polling (Pane.wait_for_text)

When observing third-party output (where we can't inject a signal), we must poll. However, naive capture_pane loops often match stale screen paint. We need Absolute Grid Anchoring.

  • The Concept: At entry, snapshot the grid's absolute baseline (history_size + cursor_y). On each tick, capture only the rows below this absolute anchor to ensure we strictly match new text.
  • libtmux-mcp Prior Art: See pane_tools/wait.py for the anchor math and scrollback limit protections.
  • tmux Internals: This approach is grounded in how tmux defines the grid (see format_cb_history_bytes and format_cb_history_size in format.c at 3.2a). It ensures compatibility with grid_collect_history and clear-history shifts.
  • Proposed API:
    # Under the hood, this will use Neo-style batch hydration 
    # to fetch `#{history_size}|#{cursor_y}` in a single IPC turn.
    pane.wait_for_text("READY", timeout=8.0) 
    
3. Future Scope: Control Mode Listener

A long-term architectural goal could involve spawning a background tmux -C client (as currently used in libtmux testing via ControlMode) to listen for %output or %pane-mode-changed streams, offering a completely event-driven API.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the linked libtmux-mcp implementations in wait_for_tools.py and pane_tools/wait.py, then inspect libtmux's Server, Pane, and ControlMode entry points. Done means defining and validating both proposed waiter APIs, including channel timeouts and absolute-grid delta matching, while treating the Control Mode listener as future scope.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
api, cli
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.