tmux-python / tmux-python/libtmux
feat: Add Non-polling Waiters (Deterministic Channels & Delta-Polling)
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 thelibtmuxclient until the signal fires. - libtmux-mcp Prior Art: See
wait_for_tools.pywhich implementswait_for_channelviasubprocess.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.pyfor the anchor math and scrollback limit protections. - tmux Internals: This approach is grounded in how tmux defines the grid (see
format_cb_history_bytesandformat_cb_history_sizeinformat.cat 3.2a). It ensures compatibility withgrid_collect_historyandclear-historyshifts. - 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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