Claude-skill-registry ghostty-terminal-automation
Automate Ghostty terminal sessions via MCP. Use when you need to send commands to terminals, read terminal output, capture screenshots, resize windows, open new tabs/windows, or interact with TUI apps like Neovim, htop, or any CLI tool running in Ghostty.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/ghostty-terminal-automation" ~/.claude/skills/majiayu000-claude-skill-registry-ghostty-terminal-automation && rm -rf "$T"
manifest:
skills/data/ghostty-terminal-automation/SKILL.mdsource content
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_terminalsList 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
terminalInteract with a specific terminal. Single supertool with 18 actions.
Required:
terminal_id, action
Input Actions
| Action | Params | Description |
|---|---|---|
| | Send command + Enter |
| , | Type text without Enter |
| , | Press key combination |
Mouse Actions
| Action | Params | Description |
|---|---|---|
| , , , | Click at position |
| , , | Double-click |
| , , , , | Drag operation |
| , , | Scroll terminal |
Screen Actions
| Action | Params | Returns |
|---|---|---|
| | |
| | |
| | |
Waiting Actions (Critical for Automation!)
| Action | Params | Description |
|---|---|---|
| , , | Wait for text/regex to appear |
| , | Wait for shell prompt |
| , | Wait for screen to stabilize |
Assertion Actions
| Action | Params | Description |
|---|---|---|
| , | Assert text is present |
| , | Assert text is NOT present |
Management Actions
| Action | Params | Description |
|---|---|---|
| - | Bring window to front |
| - | Close terminal |
| , | Change dimensions |
new_terminal
new_terminalCreate a new Ghostty window or tab.
| Param | Type | Description |
|---|---|---|
| or | Type of terminal to create |
| | Optional command to run |
Returns:
{terminal_id, title, pwd}
Core Workflow
- Discover terminals with
list_terminals - Read current state with
to see what's on screenaction="read" - Send commands with
action="send" - Wait for completion with
oraction="wait_text"action="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
before assuming terminal IDslist_terminals - Use wait actions: Don't assume commands complete instantly
- Read before sending: Check screen state to understand context
- Use
after commands: Ensures shell is ready for next commandwait_prompt - Use
for TUI inspection: Get color and style informationcells - Screenshot for verification: Visual confirmation of complex operations