Ghostty Terminal Automation
Control Ghostty terminals programmatically via the MCP server. Built on the ghostty-automator library with Playwright-style ergonomics.
Available MCP Tools
list_terminals
List all open terminal surfaces. Returns IDs, titles, dimensions, focus state, and working directory.
[
{
"id": "0x13604ba00",
"title": "~/dev/project",
"rows": 33,
"cols": 135,
"focused": true,
"pwd": "/Users/bliss/dev/project"
}
]
terminal
Interact with a specific terminal. Single supertool with 18 actions.
Required: terminal_id, action
Input Actions
| Action | Params | Description |
|--------|--------|-------------|
| send | text | Send command + Enter |
| type | text, delay_ms? | Type text without Enter |
| key | key, mods? | Press key combination |
Mouse Actions
| Action | Params | Description |
|--------|--------|-------------|
| click | x, y, button?, mods? | Click at position |
| double_click | x, y, button? | Double-click |
| drag | from_x, from_y, to_x, to_y, steps? | Drag operation |
| scroll | delta_y, delta_x?, mods? | Scroll terminal |
Screen Actions
| Action | Params | Returns |
|--------|--------|---------|
| read | screen_type? | {text, plain_text, cursor_x, cursor_y} |
| cells | screen_type? | {cells: [...], cursor_x, cursor_y, rows, cols} |
| screenshot | output_path | {path} |
Waiting Actions (Critical for Automation!)
| Action | Params | Description |
|--------|--------|-------------|
| wait_text | pattern, regex?, timeout_ms? | Wait for text/regex to appear |
| wait_prompt | prompt_pattern?, timeout_ms? | Wait for shell prompt |
| wait_idle | stable_ms?, timeout_ms? | Wait for screen to stabilize |
Assertion Actions
| Action | Params | Description |
|--------|--------|-------------|
| expect | text, timeout_ms? | Assert text is present |
| expect_not | text, timeout_ms? | Assert text is NOT present |
Management Actions
| Action | Params | Description |
|--------|--------|-------------|
| focus | - | Bring window to front |
| close | - | Close terminal |
| resize | rows?, cols? | Change dimensions |
new_terminal
Create a new Ghostty window or tab.
| Param | Type | Description |
|-------|------|-------------|
| type | "window" or "tab" | Type of terminal to create |
| command | list[str]? | Optional command to run |
Returns: {terminal_id, title, pwd}
Core Workflow
- Discover terminals with
list_terminals - Read current state with
action="read"to see what's on screen - Send commands with
action="send" - Wait for completion with
action="wait_text"oraction="wait_prompt" - Verify results by reading again or taking a screenshot
Examples
Run a Command and Wait for Output
1. list_terminals # Get terminal_id
2. terminal(id, action="send", text="npm test") # Run command
3. terminal(id, action="wait_text", pattern="PASS") # Wait for result
4. terminal(id, action="read") # Read output
Press Keys
# Press Enter
terminal(id, action="key", key="Enter")
# Ctrl+C to interrupt
terminal(id, action="key", key="KeyC", mods="ctrl")
# Arrow keys for navigation
terminal(id, action="key", key="ArrowUp")
# Tab completion
terminal(id, action="key", key="Tab")
# Escape (exit modes in vim, etc)
terminal(id, action="key", key="Escape")
Key names follow W3C standard: Enter, Tab, Escape, Backspace, Delete, Space, ArrowUp, ArrowDown, ArrowLeft, ArrowRight, Home, End, PageUp, PageDown, F1-F12, KeyA-KeyZ, Digit0-Digit9.
Type Without Executing
# Type partial input (no Enter)
terminal(id, action="type", text="git commit -m \"")
# Type slowly for effect
terminal(id, action="type", text="Hello", delay_ms=50)
Wait for Shell Prompt
# After running a long command
terminal(id, action="send", text="npm install")
terminal(id, action="wait_prompt") # Waits for $ or similar
terminal(id, action="send", text="npm start")
Wait for Screen to Stabilize
# For streaming output or animations
terminal(id, action="send", text="curl https://example.com")
terminal(id, action="wait_idle", stable_ms=1000) # Wait for 1s of no changes
Assertions
# Assert success message appears
terminal(id, action="expect", text="Build successful")
# Assert no errors
terminal(id, action="expect_not", text="ERROR")
Mouse Interactions
# Click at pixel position
terminal(id, action="click", x=100, y=200)
# Double-click to select word
terminal(id, action="double_click", x=100, y=200)
# Drag to select text
terminal(id, action="drag", from_x=50, from_y=100, to_x=200, to_y=100)
# Scroll down
terminal(id, action="scroll", delta_y=3)
Get Styled Cell Data (for TUI inspection)
# Get cell-level data with colors and formatting
terminal(id, action="cells")
# Returns cells with: char, x, y, fg, bg, bold, italic, underline, etc.
Screenshots
terminal(id, action="screenshot", output_path="/tmp/capture.png")
# Then use Read tool on /tmp/capture.png to view
Create New Terminal
# New window
new_terminal(type="window")
# New tab with command
new_terminal(type="tab", command=["python", "-i"])
Working with TUI Apps
Neovim
1. terminal(id, action="send", text="nvim file.py")
2. terminal(id, action="wait_text", pattern="file.py")
3. terminal(id, action="key", key="KeyI") # Enter insert mode
4. terminal(id, action="type", text="print('hello')")
5. terminal(id, action="key", key="Escape")
6. terminal(id, action="type", text=":wq")
7. terminal(id, action="key", key="Enter")
htop / btop
1. terminal(id, action="send", text="htop")
2. terminal(id, action="wait_idle") # Wait for UI to render
3. terminal(id, action="screenshot", output_path="/tmp/htop.png")
4. terminal(id, action="key", key="KeyQ") # Quit
Python Client
For scripting, use the ghostty-automator library directly:
from ghostty_automator import Ghostty
async with Ghostty.connect() as ghostty:
# Get first terminal
terminal = await ghostty.terminals.first()
# Run command and wait for output
await terminal.send("ls -la")
await terminal.wait_for_text("package.json")
# Assert text present
await terminal.expect.to_contain("src/")
# Take screenshot
await terminal.screenshot("/tmp/result.png")
Sync API also available:
from ghostty_automator.sync_api import Ghostty
with Ghostty.connect() as ghostty:
terminal = ghostty.terminals.first()
terminal.send("echo hello")
terminal.wait_for_prompt()
Tips
- Always discover first: Call
list_terminalsbefore assuming terminal IDs - Use wait actions: Don't assume commands complete instantly
- Read before sending: Check screen state to understand context
- Use
wait_promptafter commands: Ensures shell is ready for next command - Use
cellsfor TUI inspection: Get color and style information - Screenshot for verification: Visual confirmation of complex operations