Waiting and retrying
After sending input or starting a process, wait for the state your next step
requires. Pane
interaction covers
waiting for screen text. This page covers arbitrary conditions and tmux's named
wait-for signal channels.
Polling a condition¶
Polling checks a condition repeatedly until it succeeds or a deadline expires. Set a deadline and choose an interval that limits unnecessary tmux commands.
Python¶
Helper: libtmux.test.retry_until(fn, seconds=, interval=)
Where it lives: src/libtmux/test/ in the main package; raises
WaitTimeout.
TypeScript¶
Helper: connectedServer.waitFor(matches, options)
Where it lives: The public control-connection API. Tests a predicate over
ServerSnapshot; see Control mode vs one-shot.
Go¶
Helper: tmuxtest.WaitFor(ctx, interval, condition)
Where it lives: tmuxtest, a separate test-support package from tmux
Rust¶
Helper: libtmux::test::retry_until(within, condition)
Where it lives: crates/libtmux/src/test.rs, enabled with the test-support Cargo
feature.
Java¶
Helper: Not listed.
Where it lives: not found in the shipped library; a package-private
Await.until(...) exists only inside the integration-tests module, which
downstream code cannot depend on
C#¶
Helper: LibTmux.Testing.TmuxWait.UntilAsync(probe, timeout, interval)
Where it lives: the separate LibTmux.Testing package
C++¶
Helper: Not listed.
Where it lives: no generic condition-poll helper found in the public
library; a wait_until exists only in the private testing component, for
waiting on a spawned child process, not on tmux state
Swift¶
Helper: Not listed.
Where it lives: a waitUntil helper exists only inside the test target's
own support code, not shipped
Examples¶
waitFor subscribes before reading a server snapshot so it does not miss a
change between those steps.
tmuxtest.WaitFor probes immediately, then at the requested positive interval.
It returns a probe error or context error unchanged. Each probe must read fresh
state and honor its context. Session.Windows() only reads a stored snapshot;
use Session.SearchWindows to query tmux on every probe.
def is_window_up(pane, name): return any(w.window_name == name for w in pane.window.session.windows)
libtmux.test.retry_until(lambda: is_window_up(pane, "build"), seconds=5.0)await using live = await server.connect();await live.waitFor((snapshot) => snapshot.windows.exists({ name: "build" }));waitCtx, cancel := context.WithTimeout(ctx, 5*time.Second)defer cancel()err := tmuxtest.WaitFor(waitCtx, 50*time.Millisecond, func(ctx context.Context) (bool, error) { windows, err := session.SearchWindows(ctx, nil) if err != nil { return false, err } for _, w := range windows { if name, ok := w.Name(); ok && name == "build" { return true, nil } } return false, nil})if err != nil { return fmt.Errorf("wait for build window: %w", err)}libtmux::test::retry_until(std::time::Duration::from_secs(5), async || { session.windows().await.map(|ws| ws.iter().any(|w| w.name() == "build")).unwrap_or(false)}).await?;await LibTmux.Testing.TmuxWait.UntilAsync( async ct => (await session.GetWindowsAsync(ct)).Any(w => w.Name == "build"), TimeSpan.FromSeconds(5), TimeSpan.FromMilliseconds(50));Use a loop with a deadline and interval when a specific wait API does not fit. Pane interaction covers output waits.
tmux's own wait-for channel¶
Use tmux wait-for -S <channel> to signal and tmux wait-for <channel> to
block until signalled. This avoids repeated screen captures when the command can
announce its own completion:
Python¶
Signal a channel with Server.wait_for and set_flag=True.
Call the same method without that flag to wait for the signal.
TypeScript¶
The public API does not expose the channel handshake used internally by the test server during startup.
Go¶
Call Server.WaitFor with a WaitForRequest. Set its mode to
WaitForModeSignal to signal the channel; the zero-value mode waits.
Rust¶
Server.signal_channel signals a channel.
Server.wait_for_channel waits with a timeout and returns a ChannelWait
indicating whether it was signalled or timed out.
Java¶
Obtain a channel through Server.channel. Its signal() method
wakes a waiter; await(timeout) returns a WakeReason so the caller can
distinguish a signal from a timeout.
C#¶
Server.OpenWaitChannel returns a TmuxWaitChannel. Keep it in
an await using scope and call WaitAsync with a budget. Select the
signal mode to signal the channel.
C++¶
Server.signal signals a channel. Server.wait_for waits for the
channel with a timeout.
Swift¶
Server.signal signals a channel, and Server.wait(for:) waits
for it. Both calls are async and throwing.
server.new_session(session_name="work")server.wait_for("built", set_flag=True) # signalserver.wait_for("built") # block until signalledif err := server.WaitFor(ctx, tmux.WaitForRequest{ Channel: "built", Mode: tmux.WaitForModeSignal,}); err != nil { return err}if err := server.WaitFor(ctx, tmux.WaitForRequest{Channel: "built"}); err != nil { return err}server.signal_channel("built").await?;let outcome = server.wait_for_channel("built", std::time::Duration::from_secs(5)).await?;Channel built = server.channel("built");built.signal();WakeReason reason = built.await(Duration.ofSeconds(5));await using TmuxWaitChannel channel = server.OpenWaitChannel("built");bool signalled = await channel.WaitAsync(TimeSpan.FromSeconds(5));server.signal("built");server.wait_for("built", std::chrono::seconds{5});try await server.signal("built")try await server.wait(for: "built")tmux remembers a signal sent before a waiter starts. The next wait on that channel returns immediately, so completion is not lost when the command finishes first.
A raw wait-for client can exit zero when the server dies, as well as when the
channel is signalled. Verify server liveness when a lost server must be treated
as a failed task.
Check WakeReason to distinguish server loss from a signal. drain() can
clear a remembered signal before reusing a channel.
wait(for:) checks the server PID before and after waiting to distinguish
server loss from a signal.
Use a channel name specific to the task. A remembered signal can otherwise satisfy an unrelated later wait.
The wait-for reference describes completion signals and locks for each supported tmux version.
tmux manual and source
The tmux manual describes completion channels. The channel implementation retains an early signal until a waiter consumes it. Use a fresh channel name for each operation.