# How to Set Up tmux‑Based CLI Testing for Terminal Scenarios

> Master tmux-based CLI testing for terminal scenarios with Freebuff. Run commands in isolated sessions, capture YAML output, and inspect results with a React viewer. Avoid flaky stdin/stdout piping.

- Repository: [Codebuff/freebuff](https://github.com/CodebuffAI/freebuff)
- Tags: how-to-guide
- Published: 2026-08-20

---

**Use Freebuff's `scripts/tmux/` harness to run CLI commands in isolated tmux sessions, capture screen output as YAML, and inspect results with a React viewer—all without flakiness from direct stdin/stdout piping.**

The Freebuff project provides a production‑ready tmux testing framework for validating terminal applications in realistic conditions. Unlike conventional subprocess testing that struggles with TTY detection, color codes, and timing issues, Freebuff's [`scripts/tmux/tmux-cli.sh`](https://github.com/CodebuffAI/freebuff/blob/main/scripts/tmux/tmux-cli.sh) wrapper creates genuine terminal sessions with full control over dimensions, input handling, and session recording.

## Core Architecture of the tmux Testing Harness

Freebuff's testing infrastructure resides in `scripts/tmux/` and addresses three critical challenges in CLI automation:

- **Bracketed paste mode** – The `send` command wraps input to prevent character dropping and ensure atomic delivery
- **Deterministic session lifecycle** – Created, captured, and destroyed through a single wrapper interface
- **Inspectable artifacts** – Every screen state is serialized to YAML in `debug/tmux-sessions/` for programmatic or visual verification

The implementation delegates to standard tmux commands but abstracts away the orchestration complexity. Session logs use a structured YAML format that preserves cursor position, cell contents, and metadata—enabling diff‑based assertions or manual review.

## Running Your First CLI Test Session

The canonical workflow involves five shell commands. These examples assume execution from the repository root with the [`tmux-cli.sh`](https://github.com/CodebuffAI/freebuff/blob/main/tmux-cli.sh) wrapper.

### 1. Start a Detached Session

```bash
SESSION=$(./scripts/tmux/tmux-cli.sh start \
  --name cli-check -w 160 -h 40 --wait 6)

```

Parameters control terminal geometry (`-w`, `-h`) and initial stabilization time (`--wait`). The command returns a session identifier stored in `$SESSION` for subsequent operations.

### 2. Capture Baseline Screen State

```bash
./scripts/tmux/tmux-cli.sh capture "$SESSION" --label initial

```

This creates a timestamped YAML snapshot under `debug/tmux-sessions/$SESSION/` tagged with the provided label.

### 3. Send Input with Bracketed Paste Protection

```bash
./scripts/tmux/tmux-cli.sh send "$SESSION" \
  "Search for getAgentBaseName and report what you find" --wait-idle 4

```

The `send` subcommand automatically enables bracketed paste mode, ensuring the entire string arrives as one unit. The `--wait-idle` flag pauses execution until the terminal reports no further output activity.

### 4. Capture Post‑Action State

```bash
./scripts/tmux/tmux-cli.sh capture "$SESSION" --label after-search --wait 2

```

Multiple captures with descriptive labels create a breadcrumb trail through complex multi‑step scenarios.

### 5. Terminate the Session

```bash
./scripts/tmux/tmux-cli.sh stop "$SESSION"

```

Sessions left running consume tmux server resources; always include explicit cleanup in test scripts or trap handlers.

## Testing Custom Commands and Scripts

The tmux harness supports arbitrary executables, not just the Freebuff CLI. Launch a TypeScript harness or any shell pipeline:

```bash
SESSION=$(./scripts/tmux/tmux-cli.sh start \
  --name render-check \
  -w 160 -h 20 \
  --wait 1 \
  --command "bun .context/my-render-check.tsx")

./scripts/tmux/tmux-cli.sh capture "$SESSION" --label rendered
./scripts/tmux/tmux-cli.sh stop "$SESSION"

```

The `--command` argument overrides the default CLI invocation, making the framework reusable across projects.

## Inspecting Results with the Viewer UI

Captured sessions are human‑readable YAML files:

```bash
cat debug/tmux-sessions/$SESSION/*.yaml

```

For visual inspection across multiple captures, Freebuff includes a React viewer in [`scripts/tmux/tmux-viewer/index.tsx`](https://github.com/CodebuffAI/freebuff/blob/main/scripts/tmux/tmux-viewer/index.tsx):

```bash
bun scripts/tmux/tmux-viewer/index.tsx

```

The viewer renders terminal state with preserved colors and layout, supports navigation between capture labels, and highlights cursor positions. This is particularly valuable for debugging rendering bugs or verifying ANSI sequence handling.

## Key Implementation Files

Reference these paths when extending or debugging the tmux testing setup:

| Path | Purpose |
|------|---------|
| [`scripts/tmux/tmux-cli.sh`](https://github.com/CodebuffAI/freebuff/blob/main/scripts/tmux/tmux-cli.sh) | Core wrapper implementing start, send, capture, and stop operations |
| [`scripts/tmux/README.md`](https://github.com/CodebuffAI/freebuff/blob/main/scripts/tmux/README.md) | Maintainer documentation for the harness internals |
| [`docs/testing.md`](https://github.com/CodebuffAI/freebuff/blob/main/docs/testing.md) (lines 79‑101) | Usage patterns and capture layout specification |
| [`scripts/tmux/tmux-viewer/index.tsx`](https://github.com/CodebuffAI/freebuff/blob/main/scripts/tmux/tmux-viewer/index.tsx) | React application for browsing YAML session logs |
| `debug/tmux-sessions/` | Runtime output directory for session artifacts (git‑ignored) |

According to the Freebuff source code, the testing guide in [`docs/testing.md`](https://github.com/CodebuffAI/freebuff/blob/main/docs/testing.md) documents additional edge cases including multi‑byte character handling and resize event capture.

## Summary

- **`tmux-cli.sh start`** creates isolated terminal sessions with configurable geometry and stabilization delays
- **`tmux-cli.sh send`** transmits input with bracketed paste protection for reliable command delivery
- **`tmux-cli.sh capture`** serializes screen state to labeled YAML files for inspection or assertion
- **[`tmux-viewer/index.tsx`](https://github.com/CodebuffAI/freebuff/blob/main/tmux-viewer/index.tsx)** provides a React interface for visual debugging of captured sessions
- All artifacts route through `debug/tmux-sessions/` with structured metadata enabling CI integration

## Frequently Asked Questions

### What problem does tmux-based testing solve that subprocess testing cannot?

Subprocess testing fails when applications probe for TTY availability, rely on terminal dimensions for layout, or use interactive features like password prompts. Freebuff's tmux harness provides a genuine PTY environment while remaining scriptable—eliminating the flakiness of stubbing `isatty()` or wrestling with `pexpect` timing heuristics.

### Can I assert against captured screen content programmatically?

Yes. The YAML files in `debug/tmux-sessions/$SESSION/` contain structured cell data including text content, foreground/background colors, and cursor coordinates. Test frameworks can parse these directly or generate image snapshots for pixel‑perfect visual regression testing.

### How do I customize terminal dimensions for responsive layout testing?

Pass `-w` (width in columns) and `-h` (height in rows) to the `start` subcommand. The example `scripts/tmux/tmux-cli.sh start --name mobile -w 80 -h 24` simulates a narrow viewport without modifying application code.

### Where does session output persist after `tmux-cli.sh stop`?

Capture files written before stopping remain in `debug/tmux-sessions/$SESSION/` indefinitely. The directory name matches the session identifier returned by `start`, allowing correlation between test logs and CI artifacts. Clean these directories aggressively in CI environments to prevent disk exhaustion.