Skip to content

Commit da899f4

Browse files
authored
Merge pull request #467 from jparise/ssh-action
ssh: document the new +ssh CLI action
2 parents 1349209 + a878b3e commit da899f4

4 files changed

Lines changed: 223 additions & 109 deletions

File tree

docs/features/shell-integration.mdx

Lines changed: 9 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ description: |-
2323
while at a prompt.
2424
- `sudo` can be automatically wrapped to preserve Ghostty terminfo
2525
(disabled by default)
26-
- `ssh` can be automatically wrapped to either transmit the Ghostty
27-
terminfo or set the `TERM` environment variable to `xterm-256color`
28-
to maximize compatibility (disabled by default)
26+
- `ssh` can be automatically wrapped to set up the remote terminal
27+
environment correctly. See [SSH](/docs/features/ssh) for details
28+
(disabled by default).
2929

3030
## Shell Integration Injection
3131

@@ -156,105 +156,10 @@ the Ghostty shell-specific code as shown in the previous section.
156156

157157
## SSH Integration
158158

159-
Ghostty uses `xterm-ghostty` as its `TERM` value, but most remote hosts
160-
don't yet ship Ghostty's terminfo entry. See
161-
[Terminfo](/docs/help/terminfo#ssh) for background on the problem and
162-
the manual remedies.
159+
The `ssh-env` and `ssh-terminfo` shell integration features wrap `ssh`
160+
in your interactive shell so that Ghostty's [`+ssh`](/docs/features/ssh)
161+
CLI action is invoked transparently. This sets up the remote terminal
162+
environment so applications running over `ssh` work correctly.
163163

164-
The `ssh-env` and `ssh-terminfo` shell integration features attempt to
165-
address this automatically. Both are disabled by default and can be
166-
enabled via
167-
[`shell-integration-features`](/docs/config/reference#shell-integration-features):
168-
169-
```ini
170-
shell-integration-features = ssh-env,ssh-terminfo
171-
```
172-
173-
- **`ssh-env`** sets `TERM=xterm-256color` for the remote session and
174-
forwards `COLORTERM`, `TERM_PROGRAM`, and `TERM_PROGRAM_VERSION` via
175-
`SendEnv` so the remote shell can still detect that it's running inside
176-
Ghostty.
177-
- **`ssh-terminfo`** attempts to install Ghostty's terminfo entry on the
178-
remote host the first time you connect, using `infocmp` locally and
179-
`tic` remotely. Successful installations are cached locally so subsequent
180-
connections skip the install step. The cache can be inspected and
181-
managed with the `ghostty +ssh-cache` CLI action.
182-
183-
When both features are enabled, Ghostty tries to install the terminfo
184-
entry first and falls back to `xterm-256color` if installation fails.
185-
186-
### How It Works
187-
188-
Both features work by defining a shell function named `ssh` that wraps
189-
the real `ssh` binary. When you type `ssh` in your interactive shell,
190-
this function runs first, configures `TERM` and any other environment or
191-
`ssh` options that are needed, and then invokes the real `ssh` binary
192-
on your behalf.
193-
194-
This mechanism is simple and requires no changes to your `~/.ssh/config`,
195-
but it has an important limitation: **shell functions are not inherited
196-
by child processes.** The `ssh` wrapper only applies to `ssh` invocations
197-
made directly from your interactive shell.
198-
199-
### Limitations
200-
201-
The `ssh` shell function will _not_ be used in the following cases:
202-
203-
- **Scripts run as `./script.sh` or `sh script.sh`.** Each script runs
204-
in a new non-interactive shell that does not inherit the function.
205-
Source the script into your current shell instead (e.g.
206-
`source script.sh` or `. script.sh`) so it runs in the same shell
207-
process where the function is defined.
208-
- **Wrapper tools that spawn `ssh` themselves**, such as
209-
`aws ec2-instance-connect ssh`, `gcloud compute ssh`, `mosh`,
210-
`rsync -e ssh`, `git` over `ssh`, `scp`, and `sftp`. These invoke
211-
`ssh` (or an `ssh`-like binary) directly and never consult your
212-
shell's function table.
213-
- **Non-interactive shells and subshells** more generally, including
214-
`Makefile` recipes, `cron` jobs, and command substitutions in other
215-
programs.
216-
217-
### Manual `~/.ssh/config` Configuration
218-
219-
If you need `TERM` and environment forwarding for cases the shell wrapper
220-
can't cover (see above), you can configure `SetEnv` and `SendEnv`
221-
directly in `~/.ssh/config`, which applies to every `ssh` invocation
222-
regardless of how it was launched:
223-
224-
```ssh-config
225-
# ~/.ssh/config
226-
Host example.com
227-
SetEnv TERM=xterm-256color
228-
SendEnv COLORTERM TERM_PROGRAM TERM_PROGRAM_VERSION
229-
```
230-
231-
<Note>
232-
`SetEnv` requires OpenSSH 8.7 or newer. See
233-
[Terminfo](/docs/help/terminfo#ssh) for more on the terminfo side of this
234-
problem, including how to copy Ghostty's terminfo entry to a remote host
235-
manually.
236-
</Note>
237-
238-
<Note>
239-
If the remote host already has the `xterm-ghostty` terminfo entry
240-
installed, a `SetEnv TERM=xterm-256color` stanza will unnecessarily
241-
downgrade `TERM`. Only use this for hosts that lack the terminfo entry.
242-
</Note>
243-
244-
### Remote `sshd` Configuration
245-
246-
The `ssh-env` feature uses `SendEnv` to forward `COLORTERM`,
247-
`TERM_PROGRAM`, and `TERM_PROGRAM_VERSION` to the remote host, but
248-
`SendEnv` is only a _request_. The remote `sshd` will silently drop any
249-
variable that isn't listed in its `AcceptEnv` directive. If you want
250-
these variables to reach the remote session, the remote `sshd_config`
251-
needs something like:
252-
253-
```sshd-config
254-
# /etc/ssh/sshd_config on the remote host
255-
AcceptEnv COLORTERM TERM_PROGRAM TERM_PROGRAM_VERSION
256-
```
257-
258-
This is a property of the remote host, not Ghostty, and many managed or
259-
hardened servers will not have it configured. `TERM` itself is always
260-
forwarded by `ssh` and is not affected by `AcceptEnv`.
164+
See [SSH](/docs/features/ssh) for full details, including how to use
165+
`+ssh` directly outside of an interactive shell.

docs/features/ssh.mdx

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
---
2+
title: SSH
3+
description: |-
4+
Ghostty's `+ssh` CLI action is a drop-in `ssh` wrapper that prepares
5+
the remote session for Ghostty before exec'ing the real `ssh`
6+
binary.
7+
---
8+
9+
`ghostty +ssh` is a drop-in `ssh` wrapper. It prepares the remote
10+
session for Ghostty, then exec's the real `ssh` binary with your
11+
arguments forwarded verbatim:
12+
13+
```sh
14+
ghostty +ssh -- user@example.com
15+
```
16+
17+
You can use it as an alias so that every `ssh` invocation in your
18+
shell goes through `+ssh`:
19+
20+
```bash
21+
alias ssh='ghostty +ssh --'
22+
```
23+
24+
Or you can let Ghostty's [shell integration](#shell-integration) wrap
25+
`ssh` for you automatically.
26+
27+
Run `ghostty +ssh --help` for the full flag reference.
28+
29+
## Features
30+
31+
### Environment Forwarding
32+
33+
The `--forward-env` flag (default `true`) requests `SendEnv`
34+
forwarding of `COLORTERM`, `TERM_PROGRAM`, and `TERM_PROGRAM_VERSION`
35+
so the remote shell can detect that it's running inside Ghostty.
36+
37+
For the forwarded variables to reach the remote session, the remote
38+
`sshd` must list them in its `AcceptEnv` directive. See
39+
[Remote `sshd` Configuration](#remote-sshd-configuration) below.
40+
41+
Disable with `--forward-env=false`.
42+
43+
### Terminfo Install
44+
45+
Ghostty uses `xterm-ghostty` as its `TERM` value, but most remote
46+
hosts don't yet ship Ghostty's terminfo entry. See
47+
[Terminfo](/docs/help/terminfo#ssh) for more information.
48+
49+
The `--terminfo` flag (default `true`) installs Ghostty's terminfo
50+
entry on the remote host the first time you connect, using `tic` on
51+
the remote. When the install succeeds (or the host is already cached),
52+
`TERM` is set to `xterm-ghostty` for the remote session.
53+
54+
If the install fails (for example, `tic` isn't available on the
55+
remote), `+ssh` logs a warning and falls back to `TERM=xterm-256color`,
56+
which is a widely-supported entry that preserves color and most
57+
terminal capabilities on the remote.
58+
59+
Disable with `--terminfo=false`.
60+
61+
### Install Cache
62+
63+
Successful terminfo installs are recorded in a local cache, keyed by
64+
`user@hostname`, so subsequent connections to the same host skip the
65+
install step. The cache is managed by the
66+
[`+ssh-cache`](#the-+ssh-cache-cli-action) action.
67+
68+
Passing `--cache=false` to `+ssh` bypasses both the read and the
69+
write for a single invocation, without touching the cache. This is
70+
useful for scripting ("always reinstall") and for debugging issues.
71+
72+
### Alternate `ssh` Executable
73+
74+
By default `+ssh` exec's the first `ssh` on your `PATH`. The
75+
`--ssh=PATH` flag points it at a specific client instead:
76+
77+
```sh
78+
ghostty +ssh --ssh=/opt/homebrew/bin/ssh -- user@example.com
79+
```
80+
81+
This is useful when you have an alternate OpenSSH build or wrapper
82+
client that you want `+ssh` to use. The path must resolve to an
83+
executable; if it doesn't, `+ssh` fails rather than silently falling
84+
back to the `PATH` `ssh`.
85+
86+
## The `+ssh-cache` CLI Action
87+
88+
`ghostty +ssh-cache` manages the terminfo cache used by `+ssh`:
89+
90+
```sh
91+
# List every cached host.
92+
ghostty +ssh-cache
93+
94+
# Check whether a single host is cached.
95+
ghostty +ssh-cache --host=user@example.com
96+
97+
# Manually mark a host as cached (e.g. after installing terminfo by hand).
98+
ghostty +ssh-cache --add=user@example.com
99+
100+
# Force the next connection to reinstall terminfo on a host.
101+
ghostty +ssh-cache --remove=user@example.com
102+
103+
# Clear the entire cache.
104+
ghostty +ssh-cache --clear
105+
106+
# Set the cache expiration period (default: entries never expire).
107+
ghostty +ssh-cache --expire-days=30
108+
```
109+
110+
`--remove` is the recommended way to force a reinstall on a single
111+
host: drop the cache entry, and the next successful connection
112+
re-populates it. Use `+ssh --cache=false` when you want to bypass the
113+
cache entirely.
114+
115+
Cache entries are always keyed as `user@hostname`, where `user` is the
116+
ssh user (defaulting to your local `$USER`) and `hostname` is the
117+
resolved remote host (post-`HostName`, post-`ProxyJump`) rather than
118+
an alias from `~/.ssh/config`.
119+
120+
Run `ghostty +ssh-cache --help` for the full flag reference.
121+
122+
## Shell Integration
123+
124+
Ghostty's [shell integration](/docs/features/shell-integration) can
125+
wrap `ssh` in your interactive shell so that `ghostty +ssh` is invoked
126+
transparently. This is disabled by default and can be enabled via
127+
[`shell-integration-features`](/docs/config/reference#shell-integration-features):
128+
129+
```ini
130+
shell-integration-features = ssh-env,ssh-terminfo
131+
```
132+
133+
- **`ssh-env`** enables environment forwarding (passes
134+
`--forward-env=true` to `+ssh`).
135+
- **`ssh-terminfo`** enables the remote terminfo install (passes
136+
`--terminfo=true` to `+ssh`).
137+
138+
The wrapper is a small shell function named `ssh` that translates
139+
these feature flags into the right `+ssh` command-line options and
140+
then forwards your args.
141+
142+
### Limitations
143+
144+
Because the wrapper is a shell function, it **is not inherited by
145+
child processes**. The wrapper will _not_ be used in the following
146+
cases:
147+
148+
- **Scripts run as `./script.sh` or `sh script.sh`.** Each script runs
149+
in a new non-interactive shell that does not inherit the function.
150+
Source the script into your current shell instead (e.g.
151+
`source script.sh` or `. script.sh`) so it runs in the same shell
152+
process where the function is defined.
153+
- **Wrapper tools that spawn `ssh` themselves**, such as
154+
`aws ec2-instance-connect ssh`, `gcloud compute ssh`, `mosh`,
155+
`rsync -e ssh`, `git` over `ssh`, `scp`, and `sftp`. These invoke
156+
`ssh` (or an `ssh`-like binary) directly and never consult your
157+
shell's function table.
158+
- **Non-interactive shells and subshells** more generally, including
159+
`Makefile` recipes, `cron` jobs, and command substitutions in other
160+
programs.
161+
162+
For these cases, invoke `ghostty +ssh` directly, or configure
163+
`~/.ssh/config` as described below.
164+
165+
## Manual `~/.ssh/config` Configuration
166+
167+
For cases the shell wrapper can't cover, you can configure `SetEnv`
168+
and `SendEnv` directly in `~/.ssh/config`, which applies to every
169+
`ssh` invocation regardless of how it was launched:
170+
171+
```ssh-config
172+
# ~/.ssh/config
173+
Host example.com
174+
SetEnv TERM=xterm-256color
175+
SendEnv COLORTERM TERM_PROGRAM TERM_PROGRAM_VERSION
176+
```
177+
178+
<Note>
179+
`SetEnv` requires OpenSSH 8.7 or newer. See
180+
[Terminfo](/docs/help/terminfo#ssh) for how to copy Ghostty's terminfo entry
181+
to a remote host manually.
182+
</Note>
183+
184+
<Note>
185+
If the remote host already has the `xterm-ghostty` terminfo entry installed, a
186+
`SetEnv TERM=xterm-256color` stanza will unnecessarily downgrade `TERM`. Only
187+
use this for hosts that lack the terminfo entry.
188+
</Note>
189+
190+
## Remote `sshd` Configuration
191+
192+
Environment forwarding uses `SendEnv`, which is only a _request_. The
193+
remote `sshd` will silently drop any variable that isn't listed in its
194+
`AcceptEnv` directive. If you want `COLORTERM`, `TERM_PROGRAM`, and
195+
`TERM_PROGRAM_VERSION` to reach the remote session, the remote
196+
`sshd_config` needs something like:
197+
198+
```sshd-config
199+
# /etc/ssh/sshd_config on the remote host
200+
AcceptEnv COLORTERM TERM_PROGRAM TERM_PROGRAM_VERSION
201+
```
202+
203+
This is a property of the remote host, not Ghostty, and many managed
204+
or hardened servers will not have it configured. `TERM` itself is
205+
always forwarded by `ssh` and is not affected by `AcceptEnv`.

docs/help/terminfo.mdx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,10 @@ everywhere, but in the meantime there are two ways to resolve the situation:
7272
SetEnv TERM=xterm-256color
7373
```
7474

75-
Both variants can be automated by Ghostty's shell integration via the
76-
`ssh-terminfo` and `ssh-env` features. See
77-
[SSH Integration](/docs/features/shell-integration#ssh-integration) for
78-
details, including important limitations around when the automation
79-
applies.
75+
Ghostty can automate both variants. See [SSH](/docs/features/ssh) for
76+
details on the `ghostty +ssh` CLI action and the `ssh-env` /
77+
`ssh-terminfo` shell integration features, including important
78+
limitations around when the automation applies.
8079

8180
<Note>
8281
The `tic` command on the server may give the warning `"<stdin>", line 2,

docs/nav.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,11 @@
175175
"path": "/shell-integration",
176176
"title": "Shell Integration"
177177
},
178+
{
179+
"type": "link",
180+
"path": "/ssh",
181+
"title": "SSH"
182+
},
178183
{
179184
"type": "link",
180185
"path": "/applescript",

0 commit comments

Comments
 (0)