Shell Integration

Some Ghostty features require integrating with your shell. Ghostty can automatically inject shell integration for bash, elvish, fish, nushell, and zsh.

Features

  • Do not confirm close for terminals where the cursor is at a prompt.
  • New terminals start in the working directory of the previously focused terminal.
  • Complex prompts resize correctly by allowing the shell to redraw -- rather than reflow -- the prompt line.
  • Triple-click while holding control (Linux) or command (macOS) to select the output of a command.
  • The cursor at the prompt is turned into a bar to represent more typical text editing.
  • The jump_to_prompt keybinding can be used to scroll the terminal window forward and back through prompts.
  • Alt+click (option+click on macOS) moves the cursor to the click location while at a prompt.
  • sudo can be automatically wrapped to preserve Ghostty terminfo (disabled by default)
  • ssh can be automatically wrapped to either transmit the Ghostty terminfo or set the TERM environment variable to xterm-256color to maximize compatibility (disabled by default)

Shell Integration Injection

Ghostty will automatically inject the shell integration code for bash, elvish, fish, nushell, and zsh.

Note

The version of Bash distributed with macOS (/bin/bash) does not support automatic shell integration. You'll need to manually source the shell integration script (as shown below). You can also install a standard version of Bash from Homebrew or elsewhere and set it as your shell.

Other shells do not have shell integration code written, but they will function fine within Ghostty, although some or all of the above-mentioned shell integration features may be unavailable.

Nushell provides many of these features itself (such as title and cursor handling), so its Ghostty integration focuses on Ghostty-specific features like sudo, ssh-env, and ssh-terminfo. Similarly, newer versions of Fish (4.0+) have built-in support for prompt marking so jump_to_prompt, prompt resizing, and prompt selection will work without shell integration.

Ghostty detects your shell using a simple string match on the basename of the command to execute. If you are using a supported shell with a different name, you can force the shell integration by setting the shell-integration configuration option:

shell-integration = fish

If you want to disable automatic shell integration:

shell-integration = none

Verify Shell Integration

To verify shell integration is working, look for the following log lines:

info(io_exec): using Ghostty resources dir from env var: /Applications/Ghostty.app/Contents/Resources
info(io_exec): shell integration automatically injected shell=termio.shell_integration.Shell.fish

If you see any of the following, something is not working correctly. The main culprit is usually that GHOSTTY_RESOURCES_DIR is not pointing to the right place.

ghostty terminfo not found, using xterm-256color
shell could not be detected, no automatic shell integration will be injected

Troubleshooting

For the automatic shell integration to work Ghostty must either be run from the macOS app bundle or be installed in a location where the contents of zig-out/share are available somewhere above the directory where Ghostty is running from.

On Linux, this should automatically work if you run from the zig-out directory tree structure (a standard FHS-style tree) or run from a properly installed location via -p (see build from source).

You may also manually set the GHOSTTY_RESOURCES_DIR to point to the zig-out/share/ghostty contents. To validate this directory the file $GHOSTTY_RESOURCES_DIR/../terminfo/ghostty.terminfo should exist. Setting this environment variable manually is a red flag that something else is wrong, though, and you should investigate further.

Manual Shell Integration Setup

Shell integration can also be manually sourced in your shell configuration. This ensures that shell integration works in more scenarios (such as when you switch shells within Ghostty).

Ghostty will automatically set the GHOSTTY_RESOURCES_DIR environment variable when it starts, so you can use this to (1) detect your shell is launched within Ghostty and (2) to find the shell-integration.

For example, for bash, you'd put this at the top of your ~/.bashrc:

# Ghostty shell integration for Bash. This should be at the top of your bashrc!
if [ -n "${GHOSTTY_RESOURCES_DIR}" ]; then
    builtin source "${GHOSTTY_RESOURCES_DIR}/shell-integration/bash/ghostty.bash"
fi

Note

Technically, the bash shell integration script could be sourced from anywhere, but some bash configurations may interfere with the shell integration. To avoid this, we recommend sourcing the script as early as possible in your shell configuration.

Each shell integration's installation instructions are documented inline:

ShellIntegration
bash${GHOSTTY_RESOURCES_DIR}/shell-integration/bash/ghostty.bash
elvish${GHOSTTY_RESOURCES_DIR}/shell-integration/elvish/lib/ghostty-integration.elv
fish"$GHOSTTY_RESOURCES_DIR"/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish
nushell$GHOSTTY_RESOURCES_DIR/shell-integration/nushell/vendor/autoload/ghostty.nu
zsh${GHOSTTY_RESOURCES_DIR}/shell-integration/zsh/ghostty-integration

For shell-specific details see shell-integration/README.md.

Switching Shells with Shell Integration

Automatic shell integration as described in the previous section only works for the initially launched shell when Ghostty is started.

If you switch shells within Ghostty, i.e. you manually run bash or you use a command like nix-shell, the shell integration will be lost in that shell (it will keep working in the original shell process).

To make shell integration work in these cases, you must manually source the Ghostty shell-specific code as shown in the previous section.

SSH Integration

Ghostty uses xterm-ghostty as its TERM value, but most remote hosts don't yet ship Ghostty's terminfo entry. See Terminfo for background on the problem and the manual remedies.

The ssh-env and ssh-terminfo shell integration features attempt to address this automatically. Both are disabled by default and can be enabled via shell-integration-features:

shell-integration-features = ssh-env,ssh-terminfo
  • ssh-env sets TERM=xterm-256color for the remote session and forwards COLORTERM, TERM_PROGRAM, and TERM_PROGRAM_VERSION via SendEnv so the remote shell can still detect that it's running inside Ghostty.
  • ssh-terminfo attempts to install Ghostty's terminfo entry on the remote host the first time you connect, using infocmp locally and tic remotely. Successful installations are cached locally so subsequent connections skip the install step. The cache can be inspected and managed with the ghostty +ssh-cache CLI action.

When both features are enabled, Ghostty tries to install the terminfo entry first and falls back to xterm-256color if installation fails.

How It Works

Both features work by defining a shell function named ssh that wraps the real ssh binary. When you type ssh in your interactive shell, this function runs first, configures TERM and any other environment or ssh options that are needed, and then invokes the real ssh binary on your behalf.

This mechanism is simple and requires no changes to your ~/.ssh/config, but it has an important limitation: shell functions are not inherited by child processes. The ssh wrapper only applies to ssh invocations made directly from your interactive shell.

Limitations

The ssh shell function will not be used in the following cases:

  • Scripts run as ./script.sh or sh script.sh. Each script runs in a new non-interactive shell that does not inherit the function. Source the script into your current shell instead (e.g. source script.sh or . script.sh) so it runs in the same shell process where the function is defined.
  • Wrapper tools that spawn ssh themselves, such as aws ec2-instance-connect ssh, gcloud compute ssh, mosh, rsync -e ssh, git over ssh, scp, and sftp. These invoke ssh (or an ssh-like binary) directly and never consult your shell's function table.
  • Non-interactive shells and subshells more generally, including Makefile recipes, cron jobs, and command substitutions in other programs.

Manual ~/.ssh/config Configuration

If you need TERM and environment forwarding for cases the shell wrapper can't cover (see above), you can configure SetEnv and SendEnv directly in ~/.ssh/config, which applies to every ssh invocation regardless of how it was launched:

# ~/.ssh/config
Host example.com
  SetEnv TERM=xterm-256color
  SendEnv COLORTERM TERM_PROGRAM TERM_PROGRAM_VERSION

Note

SetEnv requires OpenSSH 8.7 or newer. See Terminfo for more on the terminfo side of this problem, including how to copy Ghostty's terminfo entry to a remote host manually.

Note

If the remote host already has the xterm-ghostty terminfo entry installed, a SetEnv TERM=xterm-256color stanza will unnecessarily downgrade TERM. Only use this for hosts that lack the terminfo entry.

Remote sshd Configuration

The ssh-env feature uses SendEnv to forward COLORTERM, TERM_PROGRAM, and TERM_PROGRAM_VERSION to the remote host, but SendEnv is only a request. The remote sshd will silently drop any variable that isn't listed in its AcceptEnv directive. If you want these variables to reach the remote session, the remote sshd_config needs something like:

# /etc/ssh/sshd_config on the remote host
AcceptEnv COLORTERM TERM_PROGRAM TERM_PROGRAM_VERSION

This is a property of the remote host, not Ghostty, and many managed or hardened servers will not have it configured. TERM itself is always forwarded by ssh and is not affected by AcceptEnv.