I guess it’s time to update the Uses page.
Ghostty’s support for OSC52 remote copy and OSC8 clickable linkes improves the experience of working on projects over ssh. I’ve been a longtime macOS Terminal holdout, but these features pushed me over the edge to switch.
Remote copy and paste
For example:
I called the script that enables this oscpb, with pb for Paste Board,
like the macOS pbcopy(1) and pbpaste(1) commands1.
It’s really simple:
#!/bin/sh
set -e
encoded=$(cat | base64 | tr -d '\n')
printf '\033]52;c;%s\007' "$encoded"
Now I can do things like:
oscpb < file.txt
/some/command | oscpb
I only use this for copying data to the system clipboard, not pasting from it. Pasting is easy to do with cmd-v, but if you want to paste with OSC52, it requires confirmation for security reasons, and the UI around that is not fully baked. Sending and receiving data with OSC52 is also not very efficient as it must first be encoded to base64, so pasting directly into the terminal is strictly better.
For this to work, nothing in between the remote shell and your terminal must strip the OSC8 escape sequences.
- tmux:
set -g set-clipboard on - neovim: configure the built-in clipboard-osc52 plugin
Launching a local editor into a remote directory
I use this like a VS Code code command that works over ssh.
The remote version is not quite as good,
as it shows a link I click to launch the editor, rather than launching directly,
but it’s still a useful improvement over connecting from the VS Code UI.
It works like this:
That link near the bottom is clickable in Ghostty, and it opens VS Code if you’re on my tailnet and have SSH keys to the lima-dreadnaught host.
It’s different than clickable links to https:// addresses,
which are implemented as a regex and limited to HTTP URL schemes.2
OCS8 links include invisible characters that can indicate any link like vscode:// app links,
and can be totally different from the text like HTML links where Google links to https://google.com.
The full version I actually use is on GitHub, but the simplest version is just 5 lines:
#!/bin/sh
set -eu
cd "${1:-.}"
uri="vscode://vscode-remote/ssh-remote+$(hostname)$(pwd -P)?windowId=_blank"
printf '\033]8;;%s\033\\%s\033]8;;\033\\\n' "$uri" "$uri"Note that for this to work in a tmux session over ssh,
you’ll need tmux 3.4 or higher,
with these options in .tmux.conf3:
set -as terminal-features ',xterm-ghostty:hyperlinks'
set -g allow-passthrough on
Visualizing the control codes
Here is what it looks like running it inside TMUX over SSH. It appears to be a simple text URI, but if you look at the hex dump, you can see the control sequences that surround it.
hex dump
Addendum
OSC codes
Something that surprised me: there is no canonical list of these, even though people refer to them by number the way I have been doing in this post. The standard defines that OSC exists, but doesn’t define the individual features anywhere. The de-facto authority on this is apparently the xterm documentation.
References:
- xterm control sequences documentation.
- Ghostty VT Reference lists the OSC codes it supports
tmux and escape sequences
tmux is itself a terminal emulator, and it receives and interprets escape sequences itself. It is not just a dumb pipe, and for them to get from the remote program to Ghostty running on my workstation tmux must actively pass them along. (Some people oppose the use of terminal multiplexers like tmux for this reason.)
For OSC52 copy/paste commands,
tmux implements support via the set-clipboard option mentioned previously.
It doesn’t have any configuration option to pass along OSC8 clickable links, however,
so my vsc script has to wrap the OSC8 escape sequences with tmux escape sequences
instructing it to forward it along.
This does mean that there isn’t a clean solution for OSC8 clickable links that works for arbitrary layers of tmux-in-tmux, or for a local tmux session with an SSH session inside it.
Setting $TERM
The most annoying thing about using SSH or advanced terminal programs like tmux with Ghostty
is that most apps don’t understand Ghostty’s $TERM yet.
To fix this, I set shell-integration-features = ssh-terminfo,ssh-env in the Ghostty config.
This detects when I am running ssh,
attempts to send the ssh server a terminfo entry describing Ghostty,
and if that fails sets TERM=xterm-256color.
See also Terminfo in the Ghostty documentation.
-
For which there is shamefully no official documentation on the web ↩︎
-
As I learned when writing this blog post, another difference between the regex HTTP link autodetection and OSC8 links is that the former are passed through as regular text when copying and pasting HTML from Ghostty, but the latter are rendered as HTML links. ↩︎
-
I’ve found that reloading the tmux config is sometimes not enough, and so you may need to exit every tmux session on the host to kill the daemon before it’ll use these changes. ↩︎