This updates the Ghostty icon to be compatible with macOS Tahoe
(supports glass effects, light/dark, tinting, etc.). This icon is made
in the new Apple Icon Composer as the source format, and all other
formats are exported from it.
This commit also updates the icon for non-Apple platforms because the
icon is fundamentally the same and I don't see any reason to maintain
multiple icons of fundamentally the same design and style.
This commit also includes updates to the macOS app so that the About
Window and so on will use the new icon.
This PR integrates Ghostty on macOS with the [App
Intents](https://developer.apple.com/documentation/appintents) system.
The focus of this initial work was on enabling [Apple
Shortcuts](https://support.apple.com/guide/shortcuts/welcome/ios) on
macOS, but App Intents are the same underlying system that powers a
number of other Apple features such as Spotlight, Siri, Widgets, and
more. We don't do much with these latter ones yet, though.
Additionally, this PR begins to refactor and untangle some of our
libghostty API calls from macOS views. Presently, macOS views and view
controllers directly call into the libghostty API and own libghostty
data models. This tight coupling is kind of nasty because it tends to
also couple libghostty API calls to the main GUI thread when they don't
really have to be (they just have to not be concurrently accessed). This
becomes an issue because App Intents run on background threads. This PR
starts to extract out some of this business logic into standalone
classes, but we still force all execution onto the main thread during
the transition.
**Version requirement:** Most of the shortcuts will work on macOS 13,
but there are some that require macOS 14, and some functionality will
require macOS 26. We gracefully degrade in all scenarios (the
capabilities that are unavailable just don't show up on older systems).
> [!IMPORTANT]
>
> This bumps our build requirements on macOS to Xcode 26 and the macOS
26 SDK. **You can still build on macOS 15,** but you must be using the
Xcode 26 beta. This includes a README update about that.
## Why?
Apple Shortcuts is an extremely powerful scripting tool on Apple
platforms. It comes with a number of built-in capabilities such as
moving windows, taking screenshots, fetching secrets, and more. By
integrating with Apple Shortcuts, it allows Ghostty to become scriptable
to a certain extent while also being able to take advantage of this
large ecosystem.
It is a huge downside that Shortcuts is Apple-only and I still would
like to make Ghostty scriptable to some extent on Linux and other
platforms as well. This work doesn't preclude that goal, but gives us an
answer to a large subset of users (macOS users), which is great.
Beyond this, no terminals integrate with Apple Shortcuts except the
built-in Terminal. And even then, the built-in Terminal only exposes two
actions (run script and run script over SSH). I think there's a lot that
can be done by exposing more functionality and I'm excited to see what
people do with this.
Finally, I think Shortcuts is possibly a way we can do some GUI testing
on macOS. That remains to be explored but it seems promising.
## Capability
The initial set of Shortcut actions is shown in the screenshot below:

These can be combined with the built-in shortcuts to do some pretty
interesting things.
### Future
There are more capabilities I'd like to expose, but they require
changing core parts of Ghostty that I didn't want to mix into this PR.
## Security
Scripting Ghostty can be considered a security risk, since it allows
arbitrary command execution, reading terminal output, etc. Therefore,
Ghostty will ask for permission prior to allowing any Shortcut to remote
control it:
<img width="859" alt="image"
src="https://github.com/user-attachments/assets/62344248-9c2c-402d-80f6-3fe3910d23fd"
/>
This can be directly overridden using the new `macos-shortcuts`
configuration, which defaults to `ask` but can also be set to `deny` or
`allow` with self-explanatory behaviors.
This PR makes the build script use the correct SDK and version flag for
the iOS Simulator.
Without this PR, the terminal fails to initialize on the iOS Simulator:
```
Compiler failed to build request
metal error=Target OS is incompatible: library was not compiled for the simulator
error initializing surface err=error.MetalFailed
```
<details>
<summary>With the PR</summary>

</details>
Fixes#7635.
This wasn't working before but it just requires a restart of the machine
for the changes to take effect. The namespace runners have this prebuilt
so this should work now.
The other workaround was flaky for unknown reasons so I'd prefer to go
back to this.
This fixes an issue where pressing the red close button in a window or
the "x" button on a tab couldn't differentiate and would always close
the tab or close the window (depending on tab counts).
It seems like in both cases, AppKit triggers the `windowShouldClose`
delegate method on the controller, but for the close window case it
triggers this on ALL the windows in the group, not just the one that was
clicked.
I implemented a kind of silly coordinator that debounces
`windowShouldClose` calls over 100ms and uses that to differentiate
between the two cases.
This wasn't working before but it just requires a restart of the machine
for the changes to take effect. The namespace runners have this prebuilt
so this should work now.
The other workaround was flaky for unknown reasons so I'd prefer to go
back to this.
This fixes an issue where pressing the red close button in a window or
the "x" button on a tab couldn't differentiate and would always close
the tab or close the window (depending on tab counts).
It seems like in both cases, AppKit triggers the `windowShouldClose`
delegate method on the controller, but for the close window case it
triggers this on ALL the windows in the group, not just the one
that was clicked.
I implemented a kind of silly coordinator that debounces
`windowShouldClose` calls over 100ms and uses that to differentiate
between the two cases.
Resolves#7591
This moves our CI to build macOS on Sequoia (macOS 15) with Xcode 26,
including the new macOS 26 beta SDK. This includes tip releases. Stable
releases continue to use Xcode 15 and the stable SDK, in case we need to
make a release before macOS Tahoe is stable (though, if its late enough
in the cycle, we may even cut a full release with it).
Importantly, this will make our builds on macOS 26 use the new styling.
I've added a new job that ensures we can continue to build with Xcode 16
and the macOS 15 SDK, as well, although I think that might come to an
end when we switch over to an IconComposer-based icon. I'll verify then.
For now, we continue to support both.
I've also removed our `hasLiquidGlass` check, since this will now always
be true for macOS 26 builds.
Resolves#7591
This moves our CI to build macOS on Sequoia (macOS 15) with Xcode 26,
including the new macOS 26 beta SDK.
Importantly, this will make our builds on macOS 26 use the new styling.
I've added a new job that ensures we can continue to build with Xcode 16 and
the macOS 15 SDK, as well, although I think that might come to an end
when we switch over to an IconComposer-based icon. I'll verify then. For
now, we continue to support both.
I've also removed our `hasLiquidGlass` check, since this will now always
be true for macOS 26 builds.
We were depending on $GHOSTTY_RESOURCES_DIR for two reasons:
1. To locate our script-adjacent bash-preexec.sh script
2. To restrict our script's execution to environments in which
$GHOSTTY_RESOURCES_DIR is available (i.e. Ghostty-only shells)
For (1), we can instead determine our directory using $BASH_SOURCE[0].
This is slightly differently than our previous behavior, where we'd
always load bash-preexec.sh from the $GHOSTTY_RESOURCES_DIR hierarchy,
even if ghostty.bash from source from somewhere else on the file system
... but we never relied on that behavior, even in development.
For (2), there's no harm in source'ing this script outside of Ghostty,
and if that does become a concern, we can restore this condition or use
something more targeted based on those specific cases.
Historically, I believe (2) was in place to enable (1), so addressing
(1) removes the need for (2).
And lastly, none of the other shell integration scripts depend on
$GHOSTTY_RESOURCES_DIR.
We were depending on $GHOSTTY_RESOURCES_DIR for two reasons:
1. To locate our script-adjacent bash-preexec.sh script
2. To restrict our script's execution to environments in which
$GHOSTTY_RESOURCES_DIR is available (i.e. Ghostty-only shells)
For (1), we can instead determine our directory using $BASH_SOURCE[0].
This is slightly differently than our previous behavior, where we'd
always load bash-preexec.sh from the $GHOSTTY_RESOURCES_DIR hierarchy,
even if ghostty.bash from source from somewhere else on the file system
... but we never relied on that behavior, even in development.
For (2), there's no harm in source'ing this script outside of Ghostty,
and if that does become a concern, we can restore this condition or use
something more targeted based on those specific cases.
Historically, I believe (2) was in place to enable (1), so addressing
(1) removes the need for (2).
And lastly, none of the other shell integration scripts depend on
$GHOSTTY_RESOURCES_DIR.
This integrates with macOS accessibility APIs to expose Ghostty terminal
structure and content.
This is a very, very bare implementation and the terminal contents
currently reported are the _full screen and scrollback_ which is way too
much for realistic human accessibility use. The target use case for this
PR is to enable automated tooling (namely, AI screen readers). However,
this is all groundwork we'll need to iterate and improve the
accessibility work anyways.
To make this work, I also replatformed some of our hacky C APIs onto a
more robust `ghostty_surface_read_text` API that can now read arbitrary
ranges of the screen into C strings for consumers to use. This will be
useful in more places going forward (hint hint).
## Before
Accessibility tooling can't read anything, Ghostty has no attributes, no
contents, just shows up as a square.

## After
A lot of metadata, including the screen contents as text.

Also, split hierarchies are navigable:
https://github.com/user-attachments/assets/a7b2ffb7-dbeb-41b2-8705-9c3200812c4d