claude-code-system-prompts/system-prompts/skill-run-tui-interactive-terminal-app-example.md
2026-05-20 09:45:59 -06:00

3.2 KiB

Example: TUI / interactive terminal app

Interactive terminal apps (text editors, REPLs, curses-based UIs) can't be driven directly by an agent's bash tool — they take over the terminal. The skill must show how to wrap them in tmux so the agent can send input, capture output, and take screenshots.

The tmux pattern

This is the standard approach:

  1. Start the TUI inside a detached tmux session
  2. Send keystrokes with tmux send-keys
  3. Read screen contents with tmux capture-pane
  4. Clean up with tmux kill-session

The skill's SKILL.md should present this as the primary way to drive the app. A small driver.sh that wraps the launch+attach sequence can live in the skill directory, but for most TUIs the raw tmux commands in the skill body are enough.

Example snippet

Run (interactive, for agents)

Start the TUI inside tmux:

tmux new-session -d -s app -x 120 -y 40 './myapp'

Poll until the ready marker appears (faster + more reliable than a fixed sleep — returns the instant the app is up, fails loudly if it isn't):

timeout 10 bash -c 'until tmux capture-pane -t app -p | grep -q "Ready"; do sleep 0.2; done'
tmux capture-pane -t app -p

Send input (this example navigates to the Settings screen and toggles an option):

tmux send-keys -t app 's'
timeout 5 bash -c 'until tmux capture-pane -t app -p | grep -q "Settings"; do sleep 0.2; done'
tmux send-keys -t app 'Down' 'Down' 'Space'  # navigate + toggle
timeout 5 bash -c 'until tmux capture-pane -t app -p | grep -qF "[x]"; do sleep 0.2; done'
tmux capture-pane -t app -p

If you find yourself writing more than a couple of these poll lines, pull them into a wait_for() helper in a driver.sh next to the skill.

Quit:

tmux send-keys -t app 'q'
tmux kill-session -t app 2>/dev/null || true

Key reference

Key Action
j / k or Down / Up Navigate list
Enter Select
s Settings
q Quit

Details worth documenting

  • Terminal size. Some TUIs break or hide content at small widths. Specify a known-good size in the tmux new-session -x -y args.
  • Startup time. Poll for a ready marker (until tmux capture-pane | grep -q X) rather than a fixed sleep N — returns the instant the app is up, and fails usefully when it never does. Say what string means ready.
  • Keybinding reference. A table of the main keys. This is the "API" of a TUI — an agent needs it to drive the app.
  • Exit cleanly. Show the quit keystroke and tmux kill-session as a fallback.
  • Color/unicode quirks. If capture-pane output is hard to read, note flags that help (-e for escape sequences, -J to join wrapped lines).

Also document the direct invocation

For a human running the app interactively, tmux is overkill. Include the one-liner too:

Run (direct, for humans)

./myapp

Press q to quit.