fix: apply Ghostty terminal colors via AppleScript from TTY-less subprocesses - #3
Open
mattschwarz wants to merge 1 commit into
Open
Conversation
…rocesses Claude Code (v2.1.139+) runs hook/tool subprocesses with no controlling terminal, so OSC color sequences to /dev/tty and via stdout are both dropped. Ghostty is AppleScript-scriptable: write the skin palette into its config file (delimited managed block) and trigger an out-of-band reload_config over Apple Events, which needs no TTY. No-op on non-Ghostty terminals and non-macOS. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
osascript), mirroring the iTerm2 approach in fix: apply iTerm2 terminal colors via AppleScript from Claude Code hook subprocesses #2.reload_configover Apple Events — no TTY required.Problem
Claude Code runs hook/tool subprocesses without a controlling terminal (deliberate, as of v2.1.139). Both standard color-delivery paths fail:
/dev/tty—Device not configured(no controlling terminal in the subprocess)ESCbyte before output reaches the emulator, so sequences arrive as inert textThis is the same root cause #2 fixes for iTerm2. This PR covers Ghostty.
Solution
Ghostty (1.3.1) ships an AppleScript dictionary (
NSAppleScriptEnabled,Ghostty.sdef) exposing aperform actioncommand.osascriptreaches Ghostty over Apple Events, bypassing the PTY entirely, so it works from any subprocess regardless of TTY availability.Ghostty's dictionary has no per-session color properties (unlike iTerm2), so colors are applied by writing them into Ghostty's config file and reloading:
osascript -e 'tell application "Ghostty" to perform action "reload_config" on (terminal 1 of front window)'activate.shwritesbackground,foreground,cursor-color, and the ANSIpalette = 0..7into a delimited managed block in${XDG_CONFIG_HOME:-$HOME/.config}/ghostty/config, preserving any user config outside the markers, then reloads.deactivate.shstrips the managed block (removing the file entirely if it held only our block) and reloads, restoring Ghostty defaults.Files changed
engine/activate.sh— write managed Ghostty color block + AppleScript reloadengine/deactivate.sh— remove managed block + AppleScript reload on reset/exitTesting
/skin mission-control— background → deep navy (#0B1120), foreground → amber (#FFB000), immediately./skin nebula— background → deep purple (#0E0520)./skin reset— colors restored to Ghostty defaults.Out-of-band path directly (works with no TTY attached):
osascript -e 'tell application "Ghostty" to perform action "reload_config" on (terminal 1 of front window)'Known limitations / notes
uname == Darwinand Ghostty env detection (TERM_PROGRAM=ghostty/GHOSTTY_RESOURCES_DIR). Other terminals: silent no-op.# >>> claude-skins/# <<< claude-skins; anything outside the markers is preserved.🤖 Generated with Claude Code