Skip to main content

A Python library for scripting Ghostty

Project description

ghosttpy

A Python interface for scripting Ghostty on macOS via AppleScript.

Requirements

  • macOS
  • Python >= 3.13
  • Ghostty >= 1.3.0 (when AppleScript support was introduced)

Install

pip install ghosttpy

Or with uv:

uv add ghosttpy

Quick start

from ghosttpy import Ghostty

g = Ghostty()
w = g.new_window(working_directory="/tmp")
term = w.selected_tab.focused_terminal
term.input("echo hello\n")

Accessing w.name or term.working_directory queries Ghostty to read the current state.

Object model

Ghostty's scripting hierarchy is Ghostty > Window > Tab > Terminal. Each object has a stable id and can be compared or used in sets.

g = Ghostty()

g.windows           # all open windows
g.front_window      # the frontmost window
g.name              # "Ghostty"
g.version           # e.g. "1.3.1"
g.frontmost         # True if Ghostty is the active app
g.is_running        # True if the Ghostty process is running

w = g.front_window
w.tabs              # tabs in this window
w.terminals         # all terminals across all tabs
w.selected_tab      # the active tab

tab = w.selected_tab
tab.index           # 1-based position in the tab bar
tab.selected        # True if this tab is active
tab.focused_terminal
tab.terminals       # terminals (split panes) in this tab

term = tab.focused_terminal
term.name
term.working_directory

Creating windows, tabs, and splits

w = g.new_window()
tab = w.new_tab()
right = term.split("right")   # returns the new Terminal
below = term.split("down")

Split directions are "right", "left", "down", and "up" (or use the SplitDirection enum).

Close any object with .close(). Bring a window to the front with w.activate(), select a tab with tab.select(), or focus a terminal with term.focus().

Configuration

Windows, tabs, and splits accept keyword arguments to configure the terminal surface:

w = g.new_window(font_size=14.0, working_directory="/tmp")
tab = w.new_tab(command="/bin/bash", environment={"EDITOR": "vim"})
new_term = term.split("right", initial_input="ls\n", wait_after_command=True)

Available options: font_size, working_directory, command, initial_input, wait_after_command, environment.

To reuse the same configuration across multiple calls, pass a Surface object:

from ghosttpy import Surface

cfg = Surface(font_size=14.0, working_directory="/tmp")
w1 = g.new_window(config=cfg)
w2 = g.new_window(config=cfg)

Terminal input

input() sends text as if pasted. send_key() sends individual key events.

term.input("ls -la\n")
term.send_key("c", modifiers="control")
term.send_key("enter")
term.send_key("a", modifiers=["control", "shift"], action="release")

perform() executes a Ghostty action string and returns whether it succeeded:

term.perform("copy_to_clipboard")
term.perform("reset")

Mouse events are also available:

term.send_mouse_position(x=100.0, y=200.0)
term.send_mouse_button("left button")
term.send_mouse_scroll(x=0, y=-3.0, precision=True)

Window management

Read or set a window's geometry:

from ghosttpy import Bounds, Point, Size

w.bounds                        # Bounds(left, top, right, bottom)
w.bounds = Bounds(0, 0, 960, 540)

w.position                      # Point(x, y)
w.size                          # Size(width, height)

w.move_to(100, 100)
w.resize_to(800, 600)

Tiling

Tile a window into a predefined screen region with ScreenRegion:

from ghosttpy import ScreenRegion

w.tile(ScreenRegion.left_half)
w.tile(ScreenRegion.top_right, gap=10)

Available regions:

Halves Quarters Thirds Fourths Sixths
left_half top_left left_third first_fourth first_sixth
right_half top_right center_third second_fourth second_sixth
top_half bottom_left right_third third_fourth third_sixth
bottom_half bottom_right left_two_thirds last_fourth fourth_sixth
right_two_thirds left_three_fourths fifth_sixth
right_three_fourths last_sixth

There is also full, which is equivalent to maximize().

Maximize, center, and grid

w.maximize()
w.center()

# Tile all windows in an auto-sized grid
g.tile_windows()

# Tile specific windows in a 3-column grid with gaps
g.tile_windows([w1, w2, w3], columns=3, gap=10)

All layout methods accept an optional screen parameter. When omitted, they use the main display.

Screen geometry

scr = g.main_screen()      # Screen for the primary display
scr.origin                  # Point -- top-left corner of usable area
scr.size                    # Size -- usable width and height (excludes menu bar and Dock)
scr.bounds                  # Bounds -- computed from origin and size

all_screens = g.screens()   # list[Screen] for every display

Raw AppleScript

For anything the library doesn't wrap, two escape hatches are available:

# Runs inside `tell application "Ghostty" ... end tell`
g.tell('get name of front window')

# Runs raw AppleScript with no wrapping
g.run('tell application "Finder" to get name of front window')

Error handling

Failed AppleScript calls raise GhosttyError, which includes the error message and an optional numeric code:

from ghosttpy import GhosttyError

try:
    term.perform("nonexistent_action")
except GhosttyError as e:
    print(e, e.code)

Enums

String arguments like "right", "press", and "left button" are accepted everywhere, but typed enum alternatives are available if you prefer:

  • SplitDirection -- right, left, down, up
  • InputAction -- press, release
  • MouseButton -- left, right, middle
  • ScrollMomentum -- none, began, changed, ended, cancelled, may_begin, stationary

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ghosttpy-0.1.1.tar.gz (20.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ghosttpy-0.1.1-py3-none-any.whl (10.8 kB view details)

Uploaded Python 3

File details

Details for the file ghosttpy-0.1.1.tar.gz.

File metadata

  • Download URL: ghosttpy-0.1.1.tar.gz
  • Upload date:
  • Size: 20.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ghosttpy-0.1.1.tar.gz
Algorithm Hash digest
SHA256 baa9fbde602b352bd8e00b64eda2d7f3002c67d2b2ec19b1187e56ddbcf8544a
MD5 2aca4b88d1b3c147552dbe842e5ffdc8
BLAKE2b-256 fab5dab83631b301b527514734119e193e6eb707fc8dc0d03bd3ee9719a55074

See more details on using hashes here.

Provenance

The following attestation bundles were made for ghosttpy-0.1.1.tar.gz:

Publisher: publish.yml on DylanModesitt/ghosttpy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ghosttpy-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: ghosttpy-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 10.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ghosttpy-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 91acdcf3655b4f8a5abd2631a0b34250162e6e299759ba7be440c3dac09cd0c0
MD5 c264c73a2c5fc73bc2ec77f46b393ed0
BLAKE2b-256 11372ad211b953ad2ff421afeee10ff91d46049306fc8539ca79ece4c8913b13

See more details on using hashes here.

Provenance

The following attestation bundles were made for ghosttpy-0.1.1-py3-none-any.whl:

Publisher: publish.yml on DylanModesitt/ghosttpy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page