Term Wrapper
Run any terminal application through the term-wrapper HTTP API or CLI commands. This enables programmatic control of TUI applications, automated CLI workflows, and interactive terminal sessions.
⚠️ IMPORTANT: Approach Priority
ALWAYS use this priority order:
CLI Subcommands (FIRST CHOICE) - Use
term-wrappercommands- Simplest approach, works directly from bash
- All examples below show CLI commands
- Use this unless it truly doesn't work
Python Client Library (SECOND CHOICE) - Only if CLI fails or is insufficient
- Use
from term_wrapper.cli import TerminalClient - See "Alternative: Python Client Library" section below
- Only use if CLI commands don't meet your needs
- Use
Direct HTTP API (LAST RESORT) - Only if both CLI and Python fail
- Use curl with REST endpoints
- See "Core API Operations (Low-Level HTTP)" section below
- Most complex approach, avoid unless necessary
Default to CLI commands. Only escalate to Python or HTTP if you encounter errors.
Recommended Approach: CLI Subcommands
The easiest way to use term-wrapper is via CLI subcommands. This requires no Python code and works directly from bash/shell scripts.
Auto-Start: The backend server starts automatically when you run any term-wrapper command. No need to manually start a server! The server picks an available port and saves it to ~/.term-wrapper/port.
Note: In development environments using uv, prefix all commands with uv run, e.g., uv run term-wrapper --help. After pip install, use term-wrapper directly.
Quick Example: Automate Claude Code
#!/bin/bash
# Create Claude session and make it create a file
# Create session
SESSION=$(term-wrapper create bash -c "cd /tmp && claude" | \
python3 -c "import sys, json; print(json.load(sys.stdin)['session_id'])")
# Wait for and accept trust prompt
term-wrapper wait-text $SESSION "Do you trust" --timeout 10
term-wrapper send $SESSION "\r"
# Wait for main UI
term-wrapper wait-text $SESSION "Welcome" --timeout 10
# Submit request
term-wrapper send $SESSION "create hello.py\r"
# Wait a bit and check for approval UI
sleep 5
TEXT=$(term-wrapper get-text $SESSION)
if echo "$TEXT" | grep -qi "esc to cancel"; then
sleep 2
term-wrapper send $SESSION "\r" # Approve
fi
# Cleanup
term-wrapper delete $SESSION
Available CLI Subcommands
# Session Management
term-wrapper create [--rows N] [--cols N] COMMAND...
term-wrapper list
term-wrapper info SESSION_ID
term-wrapper delete SESSION_ID
# Input/Output
term-wrapper send SESSION_ID TEXT # Supports \n, \r, \t, \x1b
term-wrapper get-text SESSION_ID # Clean text (ANSI stripped)
term-wrapper get-output SESSION_ID # Raw output with ANSI
term-wrapper get-screen SESSION_ID # 2D screen buffer (JSON)
# Waiting Primitives
term-wrapper wait-text SESSION_ID TEXT [--timeout SECS]
term-wrapper wait-quiet SESSION_ID [--duration SECS]
# Interactive
term-wrapper attach SESSION_ID # WebSocket interactive mode
term-wrapper web SESSION_ID # Open session in browser
# Server Management
term-wrapper stop # Stop the background server
When to use CLI vs Python:
- Use CLI subcommands for simple automation, bash scripts, one-off tasks
- Use Python client for complex logic, conditional flows, error handling
Alternative: Python Client Library
For more complex interactions, use the Python client with high-level primitives:
from term_wrapper.cli import TerminalClient
client = TerminalClient()
session_id = client.create_session(command=["bash"], rows=40, cols=120)
# High-level primitives
client.wait_for_text(session_id, "Welcome", timeout=10)
client.write_input(session_id, "ls -la\r")
text = client.get_text(session_id) # Clean text
client.wait_for_quiet(session_id, duration=2) # Wait for stability
client.delete_session(session_id)
client.close()
Core API Operations (Low-Level HTTP)
1. Check Server Health
curl -s http://localhost:8000/health
Returns: {"status":"healthy"} if running
2. Create Terminal Session
curl -X POST http://localhost:8000/sessions \
-H "Content-Type: application/json" \
-d '{
"command": ["COMMAND", "arg1", "arg2"],
"rows": 40,
"cols": 150,
"env": {
"TERM": "xterm-256color",
"COLORTERM": "truecolor"
}
}'
Returns: {"session_id": "uuid-here"}
3. Get Terminal Output
curl http://localhost:8000/sessions/{session_id}/output
Returns: {"output": "terminal output with ANSI codes"}
4. Send Input to Terminal
curl -X POST http://localhost:8000/sessions/{session_id}/input \
-H "Content-Type: application/json" \
-d '{"data": "text or escape sequence"}'
Common escape sequences:
- Arrow keys:
\x1b[A(up),\x1b[B(down),\x1b[C(right),\x1b[D(left) - Enter:
\n - Escape:
\x1b - Function keys:
\x1bOP(F1),\x1bOQ(F2), etc.
5. Delete Session (Cleanup)
curl -X DELETE http://localhost:8000/sessions/{session_id}
Complete Workflow Example
Example 1: Get Top 5 Memory Processes with htop
Problem: htop uses complex ANSI escape sequences and cursor positioning.
Solution: Use the CLI with get-screen to get parsed 2D screen buffer, then parse it.
#!/bin/bash
# Get top memory processes from htop using CLI
# Create htop session sorted by memory
SESSION=$(term-wrapper create --rows 40 --cols 150 htop -C --sort-key=PERCENT_MEM | \
python3 -c "import sys, json; print(json.load(sys.stdin)['session_id'])")
# Wait for htop to render
sleep 2.5
# Get parsed screen buffer (clean 2D text array, no ANSI codes)
term-wrapper get-screen $SESSION
# The output is JSON with 'lines' array - parse it to extract process info
# Look for the header line containing "PID" and "MEM%", then parse subsequent lines
# Cleanup when done
term-wrapper delete $SESSION
Example 2: Create and Edit File with vim
Use case: Create a Python file with vim, then edit it to add more code.
#!/bin/bash
# Create and edit a Python file with vim using CLI
# Step 1: Create /tmp/thepi.py with vim
SESSION=$(term-wrapper create vim /tmp/thepi.py | \
python3 -c "import sys, json; print(json.load(sys.stdin)['session_id'])")
sleep 1
# Enter insert mode and write code
term-wrapper send $SESSION "i"
sleep 0.3
# Type the code (note: \n for newlines)
term-wrapper send $SESSION "import math\\n\\n# Compute pi\\npi = math.pi\\nprint(f\\\"Pi = {pi}\\\")\\n"
sleep 0.5
# Exit insert mode (ESC), save and quit
term-wrapper send $SESSION "\x1b"
sleep 0.3
term-wrapper send $SESSION ":wq\r"
sleep 0.5
term-wrapper delete $SESSION
# Step 2: Edit the file to add exp(1)
SESSION=$(term-wrapper create vim /tmp/thepi.py | \
python3 -c "import sys, json; print(json.load(sys.stdin)['session_id'])")
sleep 1
# Go to end of file (G), open new line (o)
term-wrapper send $SESSION "G"
sleep 0.3
term-wrapper send $SESSION "o"
sleep 0.3
# Add exp(1) code
term-wrapper send $SESSION "\\n# Compute e (Euler's number)\\ne = math.exp(1)\\nprint(f\\\"e = {e}\\\")\\n"
sleep 0.5
# Exit insert mode, save and quit
term-wrapper send $SESSION "\x1b"
sleep 0.3
term-wrapper send $SESSION ":wq\r"
sleep 0.5
term-wrapper delete $SESSION
# Result: /tmp/thepi.py now computes both pi and e
cat /tmp/thepi.py
Example 3: Interactive Claude CLI
Use case: Use Claude CLI interactively through term-wrapper to write and execute code.
This is the same example shown at the top of this document. See "Quick Example: Automate Claude Code" above for the complete CLI implementation.
Key Requirements for Interactive Mode:
- Use output polling - Use
wait-textorwait-quietCLI commands instead of fixed sleeps. - Wait for UI stability - After detecting UI elements with
wait-text, add 1-3 second sleep before sending input. - Handle multiple prompts - Trust prompt → Request submission → Code approval.
- Poll for completion - Use
wait-quietto detect when output stabilizes, or check filesystem.
Why Interactive Mode Works:
Term-wrapper's PTY implementation provides:
isTTY: truefor all streams- Working
setRawMode()function - Proper terminal attributes for Ink's
useInputhook
The raw mode support added to terminal.py enables Ink-based applications like Claude Code to receive keyboard input properly.
Full Example: See examples/claude_interactive.py for a complete, production-ready Python implementation, or use the CLI commands shown in "Quick Example: Automate Claude Code" above for shell scripts.
Parsing Output
ANSI Escape Sequence Removal
Terminal output contains ANSI escape codes for colors, cursor movement, etc. Strip them before parsing:
import re
def strip_ansi(text):
ansi_pattern = re.compile(r'\x1b[@-_][0-?]*[ -/]*[@-~]')
return ansi_pattern.sub('', text)
Best Practices for Output Parsing
- Use simpler commands when possible:
ps,ls,grepare easier to parse thanhtop,top - Format output explicitly: Use command flags like
--no-colors,--format, etc. - Wrap in bash: Use
bash -c "command | head -n 10"to limit output - Add sleep: For quick commands, add
; sleep 2to keep session alive while fetching output
Starting the Server
If server isn't running:
cd /path/to/term_wrapper
nohup uv run python main.py > /tmp/term-wrapper.log 2>&1 &
sleep 3
curl -s http://localhost:8000/health # Verify it started
Common Patterns
Pattern 1: Run Command and Parse Output
For non-interactive commands that exit immediately:
# Wrap in bash with sleep to keep session alive
command = ["bash", "-c", "your_command; sleep 3"]
Pattern 2: Interactive Application Control
For TUI apps that stay running:
- Create session with the TUI app
- Wait for initialization (1-2 seconds)
- Send keyboard commands as needed
- Fetch output periodically
- Send 'q' or exit command
- Delete session
Pattern 3: File Editing
For vim/nano:
- Create session with editor and filename
- Send mode changes (i for insert in vim)
- Send text content
- Send save/quit sequence
- Verify file was written
- Delete session
Error Handling
- Session not found: Session may have exited. Check
GET /sessions/{id}foralive: false - Empty output: Command may not have run yet. Wait longer or check session status
- Garbled output: ANSI codes not stripped. Use the strip_ansi function
- Server not running: Start with
uv run python main.pyin project directory
Summary
This skill enables full programmatic control of any terminal application through CLI commands or HTTP APIs. Key points:
- Prefer CLI subcommands for simplicity and shell scripting
- Use
get-screenfor complex TUI apps to get clean parsed text - Use
wait-textandwait-quietinstead of fixed sleeps - Always cleanup sessions with
deletewhen done - CLI handles escape sequences:
\n,\r,\t,\x1b
The term-wrapper API bridges the gap between modern HTTP/REST interfaces and traditional terminal applications, making them accessible to AI assistants and automation tools.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.