home / skills / microck / ordinary-claude-skills / using-tmux-for-interactive-commands

This skill helps you automate interactive terminal workflows by controlling tmux sessions and sending keys to vim, REPLs, and git commands.

This is most likely a fork of the using-tmux-for-interactive-commands skill from obra
npx playbooks add skill microck/ordinary-claude-skills --skill using-tmux-for-interactive-commands

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
5.0 KB
---
name: using-tmux-for-interactive-commands
description: Use when you need to run interactive CLI tools (vim, git rebase -i, Python REPL, etc.) that require real-time input/output - provides tmux-based approach for controlling interactive sessions through detached sessions and send-keys
---

# Using tmux for Interactive Commands

## Overview

Interactive CLI tools (vim, interactive git rebase, REPLs, etc.) cannot be controlled through standard bash because they require a real terminal. tmux provides detached sessions that can be controlled programmatically via `send-keys` and `capture-pane`.

## When to Use

**Use tmux when:**
- Running vim, nano, or other text editors programmatically
- Controlling interactive REPLs (Python, Node, etc.)
- Handling interactive git commands (`git rebase -i`, `git add -p`)
- Working with full-screen terminal apps (htop, etc.)
- Commands that require terminal control codes or readline

**Don't use for:**
- Simple non-interactive commands (use regular Bash tool)
- Commands that accept input via stdin redirection
- One-shot commands that don't need interaction

## Quick Reference

| Task | Command |
|------|---------|
| Start session | `tmux new-session -d -s <name> <command>` |
| Send input | `tmux send-keys -t <name> 'text' Enter` |
| Capture output | `tmux capture-pane -t <name> -p` |
| Stop session | `tmux kill-session -t <name>` |
| List sessions | `tmux list-sessions` |

## Core Pattern

### Before (Won't Work)
```bash
# This hangs because vim expects interactive terminal
bash -c "vim file.txt"
```

### After (Works)
```bash
# Create detached tmux session
tmux new-session -d -s edit_session vim file.txt

# Send commands (Enter, Escape are tmux key names)
tmux send-keys -t edit_session 'i' 'Hello World' Escape ':wq' Enter

# Capture what's on screen
tmux capture-pane -t edit_session -p

# Clean up
tmux kill-session -t edit_session
```

## Implementation

### Basic Workflow

1. **Create detached session** with the interactive command
2. **Wait briefly** for initialization (100-500ms depending on command)
3. **Send input** using `send-keys` (can send special keys like Enter, Escape)
4. **Capture output** using `capture-pane -p` to see current screen state
5. **Repeat** steps 3-4 as needed
6. **Terminate** session when done

### Special Keys

Common tmux key names:
- `Enter` - Return/newline
- `Escape` - ESC key
- `C-c` - Ctrl+C
- `C-x` - Ctrl+X
- `Up`, `Down`, `Left`, `Right` - Arrow keys
- `Space` - Space bar
- `BSpace` - Backspace

### Working Directory

Specify working directory when creating session:
```bash
tmux new-session -d -s git_session -c /path/to/repo git rebase -i HEAD~3
```

### Helper Wrapper

For easier use, see `/home/jesse/git/interactive-command/tmux-wrapper.sh`:
```bash
# Start session
/path/to/tmux-wrapper.sh start <session-name> <command> [args...]

# Send input
/path/to/tmux-wrapper.sh send <session-name> 'text' Enter

# Capture current state
/path/to/tmux-wrapper.sh capture <session-name>

# Stop
/path/to/tmux-wrapper.sh stop <session-name>
```

## Common Patterns

### Python REPL
```bash
tmux new-session -d -s python python3 -i
tmux send-keys -t python 'import math' Enter
tmux send-keys -t python 'print(math.pi)' Enter
tmux capture-pane -t python -p  # See output
tmux kill-session -t python
```

### Vim Editing
```bash
tmux new-session -d -s vim vim /tmp/file.txt
sleep 0.3  # Wait for vim to start
tmux send-keys -t vim 'i' 'New content' Escape ':wq' Enter
# File is now saved
```

### Interactive Git Rebase
```bash
tmux new-session -d -s rebase -c /repo/path git rebase -i HEAD~3
sleep 0.5
tmux capture-pane -t rebase -p  # See rebase editor
# Send commands to modify rebase instructions
tmux send-keys -t rebase 'Down' 'Home' 'squash' Escape
tmux send-keys -t rebase ':wq' Enter
```

## Common Mistakes

### Not Waiting After Session Start
**Problem:** Capturing immediately after `new-session` shows blank screen

**Fix:** Add brief sleep (100-500ms) before first capture
```bash
tmux new-session -d -s sess command
sleep 0.3  # Let command initialize
tmux capture-pane -t sess -p
```

### Forgetting Enter Key
**Problem:** Commands typed but not executed

**Fix:** Explicitly send Enter
```bash
tmux send-keys -t sess 'print("hello")' Enter  # Note: Enter is separate argument
```

### Using Wrong Key Names
**Problem:** `tmux send-keys -t sess '\n'` doesn't work

**Fix:** Use tmux key names: `Enter`, not `\n`
```bash
tmux send-keys -t sess 'text' Enter  # ✓
tmux send-keys -t sess 'text\n'      # ✗
```

### Not Cleaning Up Sessions
**Problem:** Orphaned tmux sessions accumulate

**Fix:** Always kill sessions when done
```bash
tmux kill-session -t session_name
# Or check for existing: tmux has-session -t name 2>/dev/null
```

## Real-World Impact

- Enables programmatic control of vim/nano for file editing
- Allows automation of interactive git workflows (rebase, add -p)
- Makes REPL-based testing/debugging possible
- Unblocks any tool that requires terminal interaction
- No need to build custom PTY management - tmux handles it all

Overview

This skill shows how to use tmux to run and control interactive CLI tools (vim, interactive git rebase, Python REPL, etc.) from scripts or automation. It provides a practical tmux-based pattern: create detached sessions, send keystrokes with send-keys, capture screen state with capture-pane, and clean up sessions. The aim is to enable programmatic interaction with programs that require a real terminal without building custom PTYs.

How this skill works

The skill uses tmux detached sessions to host the interactive process. After starting a session, scripts wait briefly for initialization, then send input via tmux send-keys (including special keys like Enter and Escape) and read output via tmux capture-pane. Finally, sessions are terminated with tmux kill-session to avoid orphaned sessions.

When to use it

  • Automating full-screen or terminal-based editors (vim, nano)
  • Controlling interactive REPLs (python3 -i, node) programmatically
  • Automating interactive git workflows (git rebase -i, git add -p)
  • Running terminal utilities that require control codes or readline (htop, less)
  • When you need to script interactive workflows without implementing a PTY

Best practices

  • Create sessions detached with tmux new-session -d -s <name> <command>
  • Wait 100–500ms after session start before sending keys or capturing output
  • Use tmux key names (Enter, Escape, C-c) rather than literal escape sequences
  • Capture output with tmux capture-pane -p to inspect screen state between interactions
  • Always kill sessions when finished (tmux kill-session -t <name>) and check for existing sessions before creating

Example use cases

  • Programmatically edit a file in vim: start session, send insert mode, type content, write and quit
  • Drive a Python REPL: import modules, run functions, capture printed results
  • Automate git rebase -i: open rebase editor in a session, edit instructions, save and close
  • Run htop or other terminal apps under control for scripted snapshots or diagnostics
  • Wrap tmux commands in a small helper script to simplify start/send/capture/stop operations

FAQ

Why use tmux instead of redirecting stdin?

Redirecting stdin often fails for full-screen or readline-based tools because they require a real terminal; tmux provides a proper terminal environment.

How do I send Enter or Escape?

Pass them as separate arguments to tmux send-keys using tmux key names, e.g. tmux send-keys -t name 'text' Enter Escape.

What if capture-pane shows blank output?

You likely captured too early—add a short sleep (100–500ms) after starting the session so the program can initialize.