# Tmux CLI Test

> Drives a CLI or TUI in tmux — sends keys, waits on conditions, asserts on output. Use to test a terminal app.

- Skill: `gpu-cli/tmux-cli-test` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add gpu-cli/tmux-cli-test`
- Raw SKILL.md: https://api.skillmd.com/api/skills/gpu-cli/tmux-cli-test/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: gpu-cli (https://skillmd.com/u/gpu-cli)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/gpu-cli/tmux-cli-test

---


# tmux CLI Testing

Test a CLI or TUI by running it in a tmux session: wait for a condition, send
input, assert on the captured frame, kill the session.

**Never sleep — always wait on a condition.** A `sleep` is a guess about timing;
it makes tests both slower and flakier than polling for the thing you actually
need.

## Helpers

```bash
source .claude/skills/tmux-cli-test/scripts/tmux_helpers.sh
```

| Function | Purpose |
|----------|---------|
| `tmux_start <session> <cmd>` | Launch command in a detached tmux session |
| `tmux_kill <session>` | Kill session |
| `tmux_is_alive <session>` | Check if session is running |
| `tmux_capture <session>` | Get pane text |
| `tmux_capture_ansi <session>` | Get pane text with ANSI codes |
| `tmux_capture_to_file <session> <path>` | Save pane text to a file |
| `tmux_wait_for <session> <text> [timeout]` | Poll until text appears |
| `tmux_wait_for_regex <session> <pattern> [timeout]` | Poll until regex matches |
| `tmux_wait_gone <session> <text> [timeout]` | Poll until text disappears |
| `tmux_wait_exit <session> [timeout]` | Poll until the process exits |
| `tmux_send <session> <keys...>` | Send keys (tmux key names) |
| `tmux_type <session> <text>` | Type literal text |
| `tmux_assert_contains <session> <text> [label]` | Assert text present |
| `tmux_assert_not_contains <session> <text> [label]` | Assert text absent |
| `tmux_assert_matches <session> <pattern> [label]` | Assert regex matches |
| `tmux_send_and_wait <session> <keys> <text> [timeout]` | Send then wait |
| `tmux_test <session> <cmd> <ready_text> <fn>` | Full lifecycle test |

Screenshot helpers (`tmux_screenshot`, `tmux_screenshot_sizes`) and color
assertions (`tmux_assert_not_monochrome`, `tmux_assert_min_colors`,
`tmux_assert_has_color`, `tmux_assert_text_color`) are documented in
[references/color-capture.md](references/color-capture.md), together with the
tmux true-color override that RGB-painting TUIs require.

Override the defaults before calling anything:

```bash
TMUX_TEST_POLL_INTERVAL=0.3  # seconds between polls
TMUX_TEST_TIMEOUT=30         # max wait seconds
TMUX_TEST_WIDTH=120          # terminal columns
TMUX_TEST_HEIGHT=30          # terminal rows
```

## Workflow

Every test is the same five steps: start the session, wait for a ready signal,
interact, assert on the captured output, kill the session.

```bash
source .claude/skills/tmux-cli-test/scripts/tmux_helpers.sh

tmux_start "test-help" "./crates/target/debug/gpu --help"
tmux_wait_for "test-help" "Usage:" 10
tmux_assert_contains "test-help" "run"
tmux_assert_contains "test-help" "dashboard"
tmux_kill "test-help"
```

Prefer `tmux_test` when a test has more than a couple of assertions — it kills
the session even when one fails.

## More Patterns

| Need | Read |
|---|---|
| Dashboards, interactive prompts, error paths, `C-c` interrupts, driving tmux without the helpers, debugging a failed test, session naming | [references/examples.md](references/examples.md) |
| Running the CLI inside a container | [references/docker.md](references/docker.md) |
| True color, screenshots, color assertions | [references/color-capture.md](references/color-capture.md) |

## Anti-Patterns

| Bad | Good | Why |
|-----|------|-----|
| `sleep 3` | `tmux_wait_for s "Ready"` | Sleeps are flaky and slow |
| `sleep 5 && tmux capture-pane` | `tmux_wait_for s "expected" && tmux_capture s` | Wait on a condition, not a duration |
| Hardcoded binary path | `GPU_BIN=./crates/target/debug/gpu` | Easy to switch debug/release |
| No cleanup on failure | `tmux_test` or an explicit `tmux_kill` | Leftover sessions break the next run |
| `grep -q` with no timeout loop | `tmux_wait_for` | The text may not be rendered yet |
| Checking `.len()` of TUI text | Check displayed content only | Unicode width is not byte length |

