Bootty is a terminal automation CLI and daemon that wraps a PTY and a ghostty-vt terminal emulator. It exposes a small JSON protocol over a Unix socket so other tools can drive TUI apps and capture screen output.
Note
This project is almost entirely built with LLMs, used as a learning exercise. Use it with a hefty grain of salt.
zig build -Doptimize=ReleaseSafe install --prefix ~/.local
# binary will be at ~/.local/bin/bootty
bootty spawn --name editor
bootty type "vim file.txt"
bootty key Enter
bootty screenshot
bootty type ":q!"
bootty key Enter
bootty kill editor
Global flags:
bootty --json <command> ... Output raw JSON responses
bootty --version Print version and exit
Create a new terminal session with a PTY and virtual terminal. The daemon starts automatically on the first command if not already running.
bootty spawn [options] [shell] [args...]
--name, -n <name> Session name (default: auto-generated UUID)
--cols, -c <cols> Terminal width (default: 80)
--rows, -r <rows> Terminal height (default: 24)
--cwd, -d <path> Working directory
--env <KEY=VALUE> Set environment variable (repeatable)
--record <path> Record session to asciicast v2 file (.cast)
Session names must match [a-zA-Z0-9_-]{1,64}.
If no shell is given, the default login shell is used.
bootty spawn --name dev bash
bootty spawn --cols 120 --rows 40 /bin/sh -c "make && ./run"
bootty spawn --env EDITOR=vim --env LANG=en_US.UTF-8
bootty spawn --record /tmp/session.cast bash
The --record flag writes all PTY output to an
asciicast v2 file that
can be played back with asciinema play or embedded in web pages.
Send raw text to the terminal. Characters are written directly to the PTY.
Multiple arguments are joined with spaces. Use key instead for special
keys or modifier combos.
bootty type [--session <id>] [--paste] [--stdin] <text...>
--paste, -p Wrap text in bracketed paste sequences
--stdin Read text from stdin
bootty type "ls -la"
bootty type hello world # same as "hello world"
bootty type --paste "multi\nline\ntext"
echo "hello" | bootty type --stdin
Send one or more key presses. Each argument is a separate key event processed through the terminal's key encoder, respecting active modes (application cursor, kitty keyboard protocol, etc.).
bootty key [--session <id>] <key>...
Supported key names: Enter, Escape (Esc), Tab, Backspace,
Space, Delete, Insert, Home, End, PageUp, PageDown,
Up, Down, Left, Right, F1-F12. Single characters are sent as
UTF-8 text, so punctuation like : works too (quote ! in shells that
use history expansion).
Modifiers are joined with +:
bootty key Ctrl+C
bootty key Ctrl+Shift+A
bootty key Alt+Enter
bootty key Shift+Up
bootty key : q Enter # three separate key presses
bootty type ":q!" # send text directly
Capture the terminal screen contents.
bootty screenshot [--session <id>] [--format <fmt>]
Formats: text (default), json, html, vt.
bootty screenshot
bootty screenshot --format json
bootty screenshot --format html > output.html
bootty screenshot --format vt
Block until a pattern appears on screen or the timeout expires.
bootty wait [--session <id>] [--regex] [--timeout <ms>] [--row <n>] <pattern>
--regex, -e Use regex matching
--timeout, -t <ms> Timeout in milliseconds (default: 30000)
--row <n> Only check specific row (0-indexed)
Exit code is non-zero when pattern is not found (timeout).
bootty wait "Ready" --timeout 5000
bootty wait "Error: .*" --regex
bootty wait --row 0 "user@host"
Send a mouse click (press + release) at the given row and column (0-indexed).
bootty click [--session <id>] [--button <btn>] [--shift] [--ctrl] [--alt] <row> <col>
--button, -b <btn> Button: left, right, middle (default: left)
bootty click 10 20
bootty click --ctrl 0 0
bootty click --button right 5 10
Send a mouse drag (press at start, release at end).
bootty drag [--session <id>] <start_row> <start_col> <end_row> <end_col>
bootty drag 0 0 10 40
Scroll the terminal up or down.
bootty scroll [--session <id>] <up|down> [amount]
bootty scroll up 5
bootty scroll down 1
Resize the terminal.
bootty resize [--session <id>] <cols> <rows>
bootty resize 120 40
Send a signal to a session's child process without closing the session. Accepts signal names (TERM, HUP, SIGKILL) or numbers (15, 1, 9).
bootty signal [--session <id>] <signal>
bootty signal TERM
bootty signal 9 --session editor
bootty signal SIGSTOP
Show detailed information about a session.
bootty info [--session <id>] [name-or-id]
bootty info
bootty info editor
Close a session. Accepts a session name, UUID, or --session flag.
bootty kill [--session <id>] [name-or-id]
bootty kill editor
bootty kill --session 42ac2fff-33a6-1842-d9e9-c40d6b02044b
List all active sessions.
bootty list
Stop the daemon and close all sessions.
bootty shutdown
BOOTTY_SOCKET: absolute or relative path to the Unix socket.XDG_RUNTIME_DIR: used as the default directory for socket and logs when set.BOOTTY_LOG_PATH: if set, daemon logs are written to this file. If unset, logs are written to$XDG_RUNTIME_DIR/bootty.log(or/tmp/bootty.log).
The daemon runs in the background. If it fails to start or behaves unexpectedly, check the logs:
- Default location:
$XDG_RUNTIME_DIR/bootty.log(e.g.,/run/user/1000/bootty.log) - Fallback location:
/tmp/bootty.log
To force logging to a specific file:
export BOOTTY_LOG_PATH=/path/to/debug.log
bootty ...- The daemon listens on a Unix socket without authentication. Limit access to the socket path using filesystem permissions and avoid sharing it across users.
- The default socket path is in
/tmpifXDG_RUNTIME_DIRis unset. Consider settingBOOTTY_SOCKETorXDG_RUNTIME_DIRfor tighter control.
See docs/protocol.md for request/response schemas and streaming screenshots.
- Ghostty: https://github.com/ghostty-org/ghostty
- Prise: https://github.com/rockorager/prise
- pilotty: https://github.com/msmps/pilotty