◉ Pulse
mattj85 avatar
#52 today ▲ 47

mattj85/SpookiUI

Python Tool

A TUI configuration app for the Ghostly terminal for macOS/Linux

Created Jul 18, 2026
Stars
28
Today
+6
Forks
1
Quality
95/100
Momentum
40

README

Fetched from GitHub on Oct 30, 2026, 9:23 PM UTC · README.md

View original on GitHub

Third-party content — Open Source Pulse is not the owner of this repository.

This README belongs to mattj85/SpookiUI and its contributors. We fetch it directly from the project’s public GitHub repository and display it for reference only. All text, code, images and trademarks remain the property of their respective authors. See the repository for its license terms. Copyright / takedown policy.

SpookiUI

🌐 Website: spookiui.rooksnet.uk

A live configurator for the Ghostty terminal. Browse and edit every option Ghostty supports from an interactive terminal UI, and watch your changes apply live — when you run it inside a Ghostty window, the very terminal you're in repaints as you edit.

SpookiUI screenshot

./spookiui.py

Requires Python 3.8+ (standard library only — no pip installs) and the ghostty binary on your PATH (or in /Applications/Ghostty.app).


A note on how this is built

This started as a Claude project — a quick way to see the idea working. It didn't stay one. After 20-odd years writing software, I pulled it back to the keyboard and now maintain it by hand, the old-school way: I read every line, I own every line. Claude helped it exist; the craft since then is mine.

Installation

SpookiUI has no third-party Python dependencies — it's a single script that runs on the Python 3.8+ standard library. You can run it straight from the repo:

git clone https://github.com/mattj85/SpookiUI.git
cd SpookiUI
./spookiui.py

Or run the installer (macOS & Linux) to check prerequisites and put a spookiui command on your PATH:

./install.sh                     # installs to ~/.local/bin
PREFIX=/usr/local ./install.sh   # system-wide (may need sudo)

The installer verifies Python 3.8+, checks for the ghostty binary (warning with install hints if it's missing), and symlinks spookiui.py into your bin directory. After it runs, spookiui and spookiui --help work from anywhere.

To reverse it, run the uninstaller (pass the same PREFIX you installed with):

./uninstall.sh                   # remove the `spookiui` command
PREFIX=/usr/local ./uninstall.sh # if you installed there
./uninstall.sh --purge           # also delete SpookiUI's cache + saved profiles

It only removes the symlink it recognises as its own (never a file it didn't create, and never a Homebrew install — use brew uninstall for that), and leaves your Ghostty config and the repo untouched.

Homebrew (macOS & Linux)

A Homebrew formula lives in homebrew/spookiui.rb. Once it's published to a tap repo named homebrew-spookiui, install with:

brew install mattj85/spookiui/spookiui

Homebrew installs are updated with brew upgrade spookiui; the in-app updater detects a Homebrew install and defers to it.

Why it exists

Ghostty is configured through a plain-text file (~/.config/ghostty/config) and cannot auto-reload on file change — you have to trigger a reload yourself. SpookiUI closes that loop: it writes the config file and triggers a Ghostty reload for you — clicking the Reload Configuration menu item on macOS, or sending the running process the SIGUSR2 signal it reloads on under Linux — so editing feels live. It runs on both macOS and Linux.

Every option is discovered dynamically from your installed Ghostty (ghostty +show-config --default --docs), so the tool always matches your version — nothing is hard-coded. On this machine that's ~200 options across 13 categories. Options that only apply to the other operating system (macOS-only settings on Linux, GTK/X11 settings on macOS) are hidden automatically so you only ever see what's relevant to the machine you're on.

The live loop

 you edit a value ─▶ SpookiUI writes the config file
                          │
                          ├─▶ validates it with `ghostty +validate-config`
                          │       (an invalid value is rejected & rolled back)
                          │
                          └─▶ reloads Ghostty ─▶ your terminal repaints
                                  (macOS: "Reload Configuration" menu item via
                                   AppleScript · Linux: SIGUSR2 to the process)
  • Safe: every change is validated by Ghostty itself before it's saved. Bad values never reach your config.
  • Reversible: a dated backup (config.spookiui.YYYYMMDD.bak) is made on the first change of the day, the TUI can revert an entire session with R, and you can wipe the config back to Ghostty's built-in defaults with X (a backup is still kept).
  • Live preview: while picking a theme, font, or enum value, each highlighted option is applied as you scroll — cancel and it snaps back to where you were.

Live reload by platform

Ghostty can't watch its config file for changes, so SpookiUI triggers the reload for you. How that happens — and what it needs — depends on your OS:

Platform How the reload fires Requirements
macOS Clicks the Reload Configuration menu item via AppleScript (osascript) Ghostty must be running; your terminal needs Accessibility permission (System Settings → Privacy & Security → Accessibility). Ghostty is located on PATH or at /Applications/Ghostty.app.
Linux Sends SIGUSR2 to the running Ghostty process(es), which Ghostty reloads on Ghostty must be running; pgrep (from procps/procps-ng, present on essentially every distro) is used to find it. No extra permission needed. Works on any distribution — detection is generic (sys.platform), with no distro-specific code.
Other No auto-reload — the file is still written and validated Trigger your own reload_config keybind in Ghostty to apply.

On Linux, Ghostty is found via PATH (shutil.which), falling back to /usr/bin/ghostty and /usr/local/bin/ghostty. Only Python 3.8+ (standard library) and the ghostty binary are required; live reload additionally needs pgrep and a running Ghostty instance.

If a reload can't be triggered (Ghostty isn't running, missing permission, or an unsupported platform), your change is still written and validated safely — SpookiUI just tells you to reload manually. A few options (e.g. language) can't be applied without a restart at all; the UI flags these as needs restart / new windows only so there are no surprises.

The TUI

 SpookiUI · live Ghostty configurator          AUTO-APPLY:ON · live
 Colors & Theme    │ ● theme            Catppuccin Mocha │ theme
 Font              │   background        #1e1e2e          │ type: theme
 Cursor            │   foreground        #cdd6f4          │ value: Catppuccin…
 Window            │ ● background-opacity 0.95            │ ─ docs ───────────
 …                 │   …                                  │ Set the color …
Key Action
↑/↓ or j/k move · Tab switch pane
→/Enter into options / edit the selected option
← back to categories
/ search all options by name or documentation
u reset the selected option to its default
a toggle auto-apply (live ↔ staged)
s save + reload now · r re-trigger reload
R revert everything to session start
X wipe config & restore all Ghostty defaults (backup kept)
U update SpookiUI in place to the latest release
p profiles — save / load / delete named configs · t toggles light↔dark
c config check (doctor) — health-check for issues
v utils — one-shot fixes (e.g. Fix SSH)
t treats — fun animated background shaders (all off by default)
d show everything you've changed
? help · q quit

When your terminal font is a Nerd Font, each category in the left column gets an icon (palette, font, cursor, apple/linux, …). SpookiUI detects this from Ghostty's font-family; if no Nerd Font is set it shows a one-time note on how to install one for your platform and then runs without icons. Force it either way with SPOOKIUI_ICONS=1 / SPOOKIUI_ICONS=0.

Editors are typed to each option:

  • booleans toggle instantly
  • enums / font open a searchable picker with live preview, listing every valid choice Ghostty documents (e.g. all 11 macos-icon styles)
  • theme opens the picker with a live colour card for the highlighted theme — its 16-colour palette and a foreground-on-background sample, rendered right beside the list so you see a theme before applying it
  • bounded numbers (opacity, minimum-contrast, …) open a visual slider — ←/→ to adjust, PgUp/PgDn for larger jumps, Home/End for the ends, all previewed live
  • other numbers step with ↑/↓ or +/-, or type a value
  • colors / text take a typed value (#rrggbb or a named color); colours show a swatch, and colour options preview the active palette in the detail pane
  • keybindings open a guided builder — toggle modifiers (super/ctrl/ alt/shift, where super is ⌘ on macOS), press or pick the key, and choose the action from Ghostty's own action list; the result is validated before it's added
  • other lists (palette, env, font fallbacks, …) get an add/edit/delete editor. It only ever saves your entries — Ghostty's own defaults are listed below them, read-only, and c copies one down into your list to tweak

Auto-apply off stages your edits in memory instead of touching disk; press s to write + reload them all at once.

On macOS you can also restyle the app icon from here: pick a macos-icon style (official, blueprint, chalkboard, microchip, glass, holographic, paper, retro, xray, …) and, with custom-style, tweak macos-icon-frame plus the macos-icon-ghost-color / macos-icon-screen-color (which get live swatches). See the icon gallery at https://noahskelton.github.io/ghostty-icons/.

Profiles & the config doctor

Profiles are named snapshots of your whole config — press p in the TUI (or use spookiui profile …) to save the current setup, then load it back later. Save a light and a dark profile and the t key (or spookiui profile toggle) flips between them instantly. Loading a profile is validated and backs up your current config first, like every other change. Profiles live in $XDG_DATA_HOME/spookiui/profiles (~/.local/share/… by default), outside Ghostty's own config dir so it never reads them.

spookiui doctor (or c in the TUI) health-checks your config and reports: invalid settings, unknown/typo'd options, options set more than once (dead lines), settings that just repeat a default, and keybind triggers bound twice or shadowing a Ghostty default. Findings are grouped by severity; it exits non-zero when there are errors, so it drops cleanly into a pre-commit hook for dotfiles.

Utils — one-shot fixes

The Utils category (last entry in the left pane, or press v anywhere) collects small, one-shot maintenance actions that aren't Ghostty config options. Highlight an action to read what it does; press Enter/→ to run it.

Fix SSH

Ghostty tells programs it is xterm-ghostty (via the TERM variable). When you SSH into another machine, that host looks xterm-ghostty up in its own terminfo database — and most remote boxes have never heard of it. The remote shell then misbehaves: garbled or dead keys, missing colour, broken clear/tput, or the classic Error opening terminal: xterm-ghostty.

Fix SSH adds one line to your shell rc (~/.zshrc or ~/.bashrc, whichever matches your login shell):

alias ssh="TERM=xterm-256color ssh"

so the ssh command runs with xterm-256color — a terminfo entry essentially every host already ships. Your local Ghostty session keeps its full xterm-ghostty features; only the outbound SSH connection is downgraded to the universally-understood value. Nothing on the remote host is changed.

It's safe and idempotent: it first scans your shell rc files (.zshrc, .bashrc, .bash_profile, …) and does nothing if the alias is already there; otherwise it appends the line and syntax-checks the file. Because a running shell can't be modified from outside, it then tells you to source the file or open a new terminal for the alias to take effect. To undo, delete the alias line. (A more thorough alternative is copying Ghostty's terminfo to each host, but this alias is the quick fix that needs no remote access.)

Run it from the CLI too:

./spookiui.py fix-ssh            # add the alias if it's missing
./spookiui.py fix-ssh --check    # report whether it's present; change nothing
./spookiui.py fix-ssh --explain  # print the full what/why, then exit

Treats — fun background shaders

The Treats category (press t anywhere, or find it in the left pane) bundles a handful of nostalgic, animated background shaders. Ghostty can run a ShaderToy-style GLSL shader behind the terminal grid; a treat is one SpookiUI writes for you into <ghostty-config-dir>/shaders/spookiui/ and toggles on via custom-shader.

Current treats:

  • Matrix Rain — falling green glyph columns, cmatrix-style
  • Pipes — a neon homage to the Win95 3D Pipes screensaver
  • Mystify — bouncing, colour-trailing polygons (the Windows Mystify saver)
  • Plasma — a rolling demoscene / After Dark plasma field
  • Lava Lamp — slow rising metaball blobs (a 70s lava lamp / Bubbles saver)
  • Fireworks — rockets bursting into fading, gravity-pulled sparks
  • Chomper — a chomping wedge eats a row of pellets, chased by a ghost (a nod to the 1980 maze arcade classic)
  • Barrels — barrels tumble down slanted girders (a wink at the 1981 platform arcade classic)
  • Jumper — a hero hops beneath scrolling question-blocks (a nostalgic nod to side-scrolling platformers)

Seasonal packs:

  • Ghosts (Halloween) — friendly cartoon ghosts drift by, bobbing and fading
  • Spooky Eyes (Halloween) — pairs of glowing eyes blink open in the dark
  • Cobwebs (Halloween) — faint spider webs shimmer across the corners
  • Snow (Winter) — soft snowflakes drift down across a few depth layers

The game-inspired treats (Chomper / Barrels / Jumper) are drawn from plain shapes only — they evoke the vibe of those classics without using any game artwork, in the same "homage" spirit as the Pipes and Mystify treats. SpookiUI gently points out the pack that fits the season (e.g. the Halloween treats in October) in the treats list and overlay — nothing is auto-enabled.

They're designed to stay out of your way:

  • All off by default — nothing is enabled unless you ask.

  • One at a time — only a single treat can be active; enabling one turns off whichever was on, so background effects never stack.

  • Text stays legible — every treat composites additively through a tight luminance mask, so only the darkest background pixels are tinted; your text, cursor, and borders are left alone. Brightness is kept deliberately low.

  • Light on resources — SpookiUI sets custom-shader-animation = true, which animates only the focused window. Open (and focus) another terminal and the treat pauses in the ones you're no longer looking at, so at most one window is ever animating. Each treat is also deliberately cheap — one texture fetch and small, fixed per-frame work.

  • Non-destructive — treats are namespaced under shaders/spookiui/, so any custom-shader you added yourself is preserved, and toggling follows the same validate → back up → write → reload → rollback discipline as every other edit.

  • Adjustable vibrancy — a single 0–100% control fades the active treat's animation up or down (100% is the tuned default, 0% is invisible). Pick the Vibrancy row in the treats overlay to open the slider (or press v), or use treats vibrancy <0-100> from the CLI. It's a global preference, so it applies to whichever treat you turn on.

  • Dim unfocused windows — the treat animation only ever plays in the focused window; this setting controls what the others show. On, unfocused windows dim + desaturate so the active one stands out (a tiny no-op shader handles it even with no treat running); off, they show the plain terminal. Toggle it from the Dim unfocused row in the overlay or treats dim on|off, and it persists across sessions. Requires a Ghostty build that exposes the focus shader uniform.

Toggle them in the TUI (Space/Enter, v for vibrancy), or from the CLI:

./spookiui.py treats list                 # show treats, vibrancy, dim, and which one is on
./spookiui.py treats enable matrix-rain    # make this the active treat (replaces any other)
./spookiui.py treats disable pipes         # turn the active treat off
./spookiui.py treats only plasma           # same as enable — one treat at a time
./spookiui.py treats clear                 # turn the treat off
./spookiui.py treats vibrancy 60           # fade the animation to 60% (blank prints current)
./spookiui.py treats dim off               # stop dimming unfocused windows (blank prints current)

Scriptable CLI

Everything the TUI does is also available non-interactively:

./spookiui.py list [category]      # list options (* = changed from default)
./spookiui.py list [category] --all # include options for the other OS
./spookiui.py get   <key>          # print an option's current value
./spookiui.py doc   <key>          # show an option's documentation + choices
./spookiui.py set   <key> <value>… # set (writes + reloads live); repeat value for lists
./spookiui.py set   <key> <v> --no-reload   # write without reloading
./spookiui.py reset --yes          # clear config & restore all Ghostty defaults (backup kept)
./spookiui.py version              # print version & check GitHub for a newer release
./spookiui.py update               # update in place to the latest release (git pull or download)
./spookiui.py profile save <name>  # snapshot the current config as a named profile
./spookiui.py profile load <name>  # apply a saved profile (validated, backed up)
./spookiui.py profile list         # list saved profiles  (also: show / delete / toggle)
./spookiui.py profile toggle       # flip between the 'light' and 'dark' profiles
./spookiui.py doctor               # health-check the config (duplicates, unknown keys, keybind clashes…)
./spookiui.py fix-ssh              # fix garbled SSH sessions (adds a TERM=xterm-256color ssh alias)
./spookiui.py fix-ssh --check      # report whether the SSH alias is present; change nothing
./spookiui.py treats list          # fun background shaders (also: enable / disable / only / clear)
./spookiui.py reload               # trigger a live reload
./spookiui.py validate             # validate the current config
./spookiui.py themes               # list installed themes
./spookiui.py fonts                # list monospace font families
./spookiui.py path                 # print the config file in use

Examples:

./spookiui.py set theme "Catppuccin Latte"
./spookiui.py set font-size 15
./spookiui.py set font-family "JetBrains Mono" "Symbols Nerd Font"   # primary + fallback
./spookiui.py doc background-opacity

Notes & limitations

  • Live reload works on macOS and Linux (and degrades safely elsewhere) — see Live reload by platform above for the per-OS mechanism and requirements.
  • Edits to single-value options are made in place, preserving your file's comments and layout. New options and list options are written under a clearly-marked # added by SpookiUI section.
  • The config path is auto-detected ($XDG_CONFIG_HOME/ghostty/config, then ~/.config/ghostty/config, then the macOS app-support path).

Updates

On startup SpookiUI quietly checks GitHub for a newer release. If one exists, the TUI shows a UPDATE vX.Y.Z badge in the header (and press U to update on the status line); the help screen (?) always shows your current version. Run spookiui version any time to check on demand.

The check is best-effort and non-blocking — it runs on a background thread, times out quickly, and stays silent if you're offline or GitHub is unreachable. The result is cached for a day (under $XDG_CACHE_HOME/spookiui/) so it never hammers the API. To turn it off entirely, set SPOOKIUI_NO_UPDATE_CHECK=1.

Updating in place — no git pull needed

Press U in the TUI, or run spookiui update. No update server is involved — GitHub is the source, and SpookiUI is a single file, so updating just swaps that file:

  • Git checkout (the default install.sh layout) → it runs git pull for you.
  • Standalone copy → it downloads the latest release's spookiui.py, verifies it compiles, then atomically replaces the file (keeping a .prev backup). A truncated or bad download can never leave you with a broken tool.
  • No write permission (e.g. installed system-wide as root) → it tells you the exact command to run instead of failing silently.

Restart SpookiUI afterwards to run the new version.

Maintainers: notifications and updates only pick up a version once a matching GitHub Release is published — see RELEASING.md for the bump-and-release flow.

License

MIT — see LICENSE.

Rendered by GitHub from the repository’s README. Scroll to read the full file.
First trending

Jul 19, 2026

first spotted on the list

Best rank

#9

highest position reached

Appearances

3

times on the trending list

Quality score

95

out of 100

Momentum

40

trend strength indicator

Star velocity

0.27

stars per day since creation

Activity — last 60 days

daily counts, collected every 6 hours
  • Stars
  • Forks
  • Merged PRs
  • Issues
  • Closed issues

Collecting activity data since launch — check back in a few days.

Star history

total stars per snapshot
15202530mattj85/SpookiUI · Jul 19, 3 AM UTC: 17 starsmattj85/SpookiUI · Jul 19, 8 AM UTC: 22 starsmattj85/SpookiUI · Jul 19, 1 PM UTC: 28 stars3 AM8 AM1 PM

Rank history

position on trending · lower is better
#1#10#20#30#40#50#60Jul 19, 3 AM UTC: rank #9Jul 19, 8 AM UTC: rank #57Jul 19, 1 PM UTC: rank #523 AM8 AM1 PM

3D card for your website

Live HTML card with a glass surface and pointer tilt. Paste the iframe on any website.

<iframe src="https://www.notionpulse.cc/embed/mattj85/SpookiUI" width="420" height="240" style="border:0;max-width:100%;background:transparent" loading="lazy" title="mattj85/SpookiUI — trending on Open Source Pulse"></iframe>

Stars badge

Show current stars in your README or profile. Auto-updates every 6 hours.

mattj85/SpookiUI stars badge
Markdown
[![mattj85/SpookiUI](https://www.notionpulse.cc/api/badge/mattj85/SpookiUI.svg)](https://www.notionpulse.cc/repo/mattj85/SpookiUI)
HTML
<a href="https://www.notionpulse.cc/repo/mattj85/SpookiUI"><img src="https://www.notionpulse.cc/api/badge/mattj85/SpookiUI.svg" alt="mattj85/SpookiUI stars badge" /></a>

Repository of the Day

#9 Repository of the Day

Repository of the Week

#9 Repository of the Week

Repository of the Month

#9 Repository of the Month