<p align="center">
  <img src="assets/term-cli.svg" alt="term-cli" width="150">
  <img src="assets/challenge.webp" alt="term-cli challenge demo">
</p>

**term-cli: unlock interactive terminals for AI agents**

If it blocks in a terminal, it blocks your agent.

Run interactive programs from your AI coding agent without blocking. Dev servers, debuggers, REPLs, databases, editors, SSH sessions, TUIs, long-running watchers, and interactive installers.

<details>
<summary>More examples</summary>

Dev servers (`npm run dev`), debuggers (`pdb`, `gdb`), REPLs (python, node), databases (`psql`, mysql), editors (vim, nano), SSH sessions, TUIs (htop, less), log watchers (`tail -f`, `journalctl`), terminal browsers (carbonyl, browsh, lynx), IRC clients (irssi, weechat), packet capture (termshark), package manager prompts (apt, brew, pacman), EULAs and interactive wizards.
</details>

Hand control to humans for passwords and MFA prompts. Or flip it: human drives while the agent watches, advises, and learns—a pair programmer, rubber duck, or observer looking over your shoulder.

- **term-cli**: Agents run interactive programs in detached terminal sessions (tmux-backed)
- **term-assist**: Humans collaborate, enter passwords, handle MFA, prepare sessions

Single-file Python. No dependencies beyond tmux. 680+ tests, CI on every commit. BSD licensed.

## The Problem

Agents can run shell commands, but interactive programs block forever:

```bash
vim config.yaml           # millions of developers trapped, now agents join them
npm run dev               # blocks, need to see output
python -m pdb script.py   # blocks, need to interact
gdb ./crash               # blocks, need to step through
ssh user@server           # needs password
apt-get install nginx     # needs Y/n confirmation
certbot certonly          # interactive wizard
tail -f /var/log/app.log  # runs forever, need to watch
```

## The Solution

```bash
term-cli start --session debug && term-cli run --session debug "python -m pdb script.py" --wait
term-cli send-text --session debug "b main" --enter && term-cli wait --session debug
term-cli send-text -s debug "c" --enter && term-cli wait -s debug   # continue
term-cli capture --session debug                                    # see where we are
term-cli kill --session debug
```

Agents run commands in detached tmux sessions. Humans join when needed via term-assist.

## TTY-first workflows you can’t --yes away

Some workflows have no reliable non-interactive mode: serial consoles, boot menus, installers, and full-screen TUIs. `term-cli` lets agents wait for prompts, send keys, capture state, and hand off to humans only when needed.

- **Professional network gear and console access**
  - **SSH sessions:** interactive prompts for passwords/MFA and stateful CLI workflows.
  - **Paged output (“more”):** keypress to continue on long command output.
  - **Serial console sessions:** run tools like `screen` or `picocom` on USB-serial adapters (lab devices, console servers, remote hands).
  - **BMC Serial-over-LAN (SOL):** interactive console access via IPMI/iDRAC/iLO-style SOL when the OS is down or pre-boot.
  - **Virtual machine consoles:** QEMU/`virsh console`/hypervisor consoles are terminal-first and commonly explored interactively.
  - <details>
    <summary>Vendor examples</summary>

    - **Cisco IOS / IOS XE and Cisco NX-OS:** first-boot setup wizard/utility with interactive yes/no and field entry.
    - **Juniper Junos:** password setup with enter and confirm a second time.
    </details>

- **Embedded, SoC, and lab bring-up**
  - **Bootloaders:** U-Boot autoboot interrupt, boot menus, environment editing, netboot and flash flows over serial.
  - **Manufacturing and validation firmware:** text menus for tests, calibration, burn-in loops, operator prompts.
  - **JTAG/SWD debugging:** GDB interactive stepping and inspection loops (you can script parts, but engineers usually explore interactively).

- **System recovery and pre-OS troubleshooting**
  - **Boot repair shells:** GRUB rescue and bootloader menus when the system won’t boot normally.
  - **Initramfs and emergency modes:** dracut, BusyBox, systemd emergency shell workflows that require live interaction.
  - **Filesystem repair and recovery:** tools like `fsck` that ask repeated fix/skip prompts (optionally with human approval).

- **Linux installers and package configuration prompts**
  - **Debconf TUIs:** timezone (`tzdata`), locales, keyboard, mail setup (`postfix`), database setup wizards.
  - **License/EULA accept flows:** “scroll and accept” installers that block on keypress.
  - **Config-file conflicts during upgrades:** keep local vs maintainer config prompts (`dpkg`/`apt`).

## Installation

Requires Python 3.8+ and tmux.

```bash
# Install tmux first (if not already installed)
brew install tmux        # macOS
apt install tmux         # Debian/Ubuntu

# Install term-cli, term-assist, and agent skill files
curl -fsSL https://raw.githubusercontent.com/EliasOenal/term-cli/main/install.sh | bash
```

Or from a cloned repo:

```bash
git clone https://github.com/EliasOenal/term-cli.git && cd term-cli && ./install.sh
```

<details>
<summary>Install options</summary>

```bash
# System-wide install (to /usr/local/bin, requires sudo)
./install.sh --system

# Custom install directory
./install.sh --prefix ~/bin

# Skip skill file installation
./install.sh --no-skill

# Install skills only for specific agents
./install.sh --skill opencode,claude

# Uninstall
./install.sh --uninstall
```

</details>

<details>
<summary>Manual installation</summary>

```bash
curl -O https://raw.githubusercontent.com/EliasOenal/term-cli/main/term-cli
curl -O https://raw.githubusercontent.com/EliasOenal/term-cli/main/term-assist
chmod +x term-cli term-assist
```

</details>

### Agent Skills

[Agent Skills](https://agentskills.io) are instructions and resources that agents discover and load on demand to work more accurately. term-cli includes a skill in `skills/term-cli/`. The installer automatically installs it for all known agents.

**Skills vs MCP:** Skills suit coding agents—concise CLI commands keep context lean when balancing automation with large codebases. MCP servers suit specialized loops that benefit from persistent state and rich introspection. term-cli is CLI-native; no MCP server needed.

**No skill? No problem.** Point your agent at `term-cli --help` and let it figure things out. The CLI is self-documenting.

<details>
<summary>Manual skill installation</summary>

Install to your home directory so it works across projects.

```bash
# GitHub Copilot (VS Code / Copilot CLI)
mkdir -p ~/.copilot/skills && cp -r skills/term-cli ~/.copilot/skills/

# Gemini CLI
mkdir -p ~/.gemini/skills && cp -r skills/term-cli ~/.gemini/skills/

# OpenAI Codex CLI
mkdir -p ~/.agents/skills && cp -r skills/term-cli ~/.agents/skills/

# OpenClaw
mkdir -p ~/.openclaw/skills && cp -r skills/term-cli ~/.openclaw/skills/

# Claude Code
mkdir -p ~/.claude/skills && cp -r skills/term-cli ~/.claude/skills/

# OpenCode
mkdir -p ~/.config/opencode/skills && cp -r skills/term-cli ~/.config/opencode/skills/
```

</details>

### Works with

<details>
<summary>Agents and tools</summary>

Works with **Claude Code**, **Gemini CLI**, **Cursor**, **Aider**, **OpenCode**, **Cline**, **Kilo Code**, **Windsurf**, **Amazon Q**, **Augment Code**, **Moltbot**, **OpenHands**, and any agent that can run shell commands.
</details>

## term-cli Commands (for agents)

| Command | Description |
|---------|-------------|
| `start --session NAME` | Create session |
| `kill --session NAME` | Destroy session |
| `list` | List sessions |
| `status --session NAME` | Show state and process tree |
| `run --session NAME "cmd" --wait --timeout 60` | Run command, wait for prompt |
| `send-text --session NAME "text" --enter` | Send text (--enter for Enter key) |
| `send-key --session NAME C-c` | Send special key |
| `send-mouse --session NAME --text "Item"` | Click a visible TUI item (alternate screen mode) |
| `send-mouse --session NAME --text "Item" --scroll-down 3` | Scroll at a visible TUI item |
| `send-stdin --session NAME < file.txt` | Send multiline content |
| `capture --session NAME` | Capture screen (auto-annotates active TUIs; --tail/--scrollback for more) |
| `wait --session NAME --timeout 30` | Wait for prompt |
| `wait-idle --session NAME --idle 2` | Wait for output to settle |
| `wait-for --session NAME "pattern"` | Wait for text to appear (--print-match/--print-match-context N) |
| `resize --session NAME --cols 120 --rows 40` | Resize terminal |
| `scroll --session NAME -50` | Scroll viewport (negative=up) |
| `pipe-log --session NAME /tmp/out.log` | Stream output to file |
| `unpipe --session NAME` | Stop streaming |
| `upload --session NAME local.txt remote.txt` | Upload file to session (gzip-compressed, SHA-256 verified) |
| `download --session NAME remote.txt local.txt` | Download file from session (gzip-compressed, SHA-256 verified) |
| `request --session NAME --message "help"` | Request human assistance |
| `request-wait --session NAME` | Wait for human to complete |
| `request-status --session NAME` | Check if request pending |
| `request-cancel --session NAME` | Cancel pending request |

Run `term-cli --help` or `term-cli <command> --help` for details.

### Keys

`C-c` `C-d` `C-z` `C-u` `C-l` (ctrl), `Enter` `Escape` `Tab` `Space` `BSpace`, `Up` `Down` `Left` `Right`, `Home` `End` `PPage` `NPage`, `F1`-`F12`

## term-assist Commands (for humans)

| Command | Description |
|---------|-------------|
| `list` | List all sessions (highlights pending requests) |
| `attach --session NAME` | Join session with status bar UI |
| `attach --session NAME --readonly` | Observe without typing |
| `done --session NAME` | Mark request complete (with optional message) |
| `detach` | Detach from current session |
| `start --session NAME` | Create session for agent to use later |
| `kill --session NAME` | Kill session |
| `kill --all` | Kill all sessions |
| `lock --session NAME` | Lock session (agent read-only) |
| `unlock --session NAME` | Unlock session |

### Key Bindings (when attached)

| Key | Action |
|-----|--------|
| `Ctrl+B Enter` | Complete request (prompt for optional message to agent) |
| `Ctrl+B d` | Detach (if request still pending, agent's request-wait fails) |

## Example: Dev Server

```bash
term-cli start --session server && term-cli run --session server "npm run dev"
term-cli wait-idle --session server --timeout 15 && term-cli capture --session server
# ... later ...
term-cli send-key --session server C-c && term-cli wait --session server
term-cli kill --session server
```

## Example: Python Debugger

```bash
term-cli start --session debug && term-cli run --session debug "python3 -m pdb script.py"
term-cli wait -s debug && term-cli send-text -s debug "b 42" --enter && term-cli wait -s debug
term-cli send-text -s debug "c" --enter && term-cli wait -s debug && term-cli capture -s debug
```

## Example: File Transfer (over SSH)

```bash
term-cli start --session remote && term-cli run --session remote "ssh user@server" --wait
term-cli upload --session remote ./deploy.tar.gz /tmp/deploy.tar.gz
term-cli download --session remote /var/log/app.log ./app.log
# Pipe support
cat config.json | term-cli upload --session remote - /app/config.json
term-cli download --session remote /app/data.csv - | head -5
```

## Example: SSH with Password (Agent + Human)

**Agent side:**
```bash
term-cli start --session remote && term-cli run --session remote "ssh user@server"
term-cli wait --session remote && term-cli capture --session remote
# If password prompt shown, request human help; if shell prompt, key auth succeeded
term-cli request --session remote --message "Please enter SSH password"
term-cli request-wait --session remote && term-cli capture --session remote
term-cli run --session remote "ls -la" --wait
```

**Human side:**
```bash
term-assist list                        # See: "remote: Please enter SSH password"
term-assist attach --session remote     # Join, see status bar with message
# (enter password)
# Press Ctrl+B Enter, then type optional message or just Enter to complete
```

## Example: Human Prepares Session for Agent

**Human side:**
```bash
term-assist start --session prod --locked
term-assist attach --session prod
# (login to server, set up environment, etc.)
# Press Ctrl+B d to detach when ready
term-assist unlock --session prod
```

**Agent side:**
```bash
term-cli capture --session prod         # See current state
term-cli run --session prod "deploy.sh" --wait --timeout 300
term-cli kill --session prod
```

## Key Features

- **Explicit errors**: `start` fails if session exists; `kill` fails if not exists
- **Wait strategies**: `wait` (prompt), `wait-idle` (output settles), `wait-for` (pattern)
- **Human collaboration**: `request`/`request-wait` + term-assist for passwords, MFA prompts, manual steps
- **Locked sessions**: Human controls, agent observes (start with `--locked` or use `term-assist lock`)
- **Dimension preservation**: Human joining doesn't resize agent's terminal
- **File transfer**: `upload`/`download` with gzip compression, SHA-256 verification, and pipe support (`-` for stdin/stdout)
- **Clean output**: Visible screen only, whitespace trimmed, `--scrollback N` for history
- **Self-documenting**: `--help` on every command

## Exit Codes

| Code | Meaning |
|------|---------|
| 0 | Success |
| 1 | Runtime error |
| 2 | Invalid input |
| 3 | Timeout |
| 4 | Human detached while request pending |
| 5 | Session locked (agent read-only) |
| 127 | tmux not found |

## Design Philosophy

- **Two tools**: term-cli for agents, term-assist for humans
- **Single files**: No dependencies beyond Python stdlib + tmux
- **Self-documenting**: Point at `--help` and go

## Requirements

- Python 3.8+
- tmux

## License

BSD License — see [LICENSE](LICENSE)

## Contributing

Issues and PRs welcome. This is a small, focused tool: simplicity is a feature.
