/blog/

2026 0411 A better remote project experience with Ghostty

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:

6:58:51
E0
Naragua
~
ssh micahrl@tagasaw Linux tagasaw.home.micahrl.com 6.12.74+deb13+1-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.74-2 (2026-03-08) x86_64 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Thu Apr 9 06:59:23 2026 from 100.112.192.27
7:01:48
E0
tagasaw
~
uptime | oscpb
7:02:01
E0
tagasaw
~
echo "Will hit cmd-v next..." Will hit cmd-v next...
7:02:25
E0
tagasaw
~
cat <<EOF heredoc> 07:02:01 up 18 days, 23:58, 2 users, load average: 0.48, 0.58, 0.62 EOF 07:02:01 up 18 days, 23:58, 2 users, load average: 0.48, 0.58, 0.62
7:02:41
E0
tagasaw
~

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:

7:21:01
E0
Naragua
~
printf 'I am currently in a tmux session:\n%s\n' "$(env | grep TMUX)" I am currently in a tmux session: TMUX=/private/tmp/tmux-501/default,15793,1 TMUX_PANE=%4
7:21:03
E0
Naragua
~
ssh callista@lima-dreadnaught
“You don’t think there’s anyone here, do you?”
Rorschach
, in
Blindsight
by Peter Watts
Last login: Fri Apr 10 07:18:42 2026 from 100.112.192.27
7:21:12
callista
~
$
ls -l total 4.0K -rw-r--r--. 1 callista callista 0 Mar 28 09:38 domainmap.txt drwx------. 1 callista callista 0 Mar 30 07:11
repos
/ lrwxrwxrwx. 1 root root 16 Mar 29 07:01
work
->
/mnt/aiworkspace
/
7:21:15
callista
~
$
cd work/dhd
7:21:17
callista
~/work/dhd
$
pwd /home/callista/work/dhd
7:21:18
callista
~/work/dhd
$
vsc . vscode://vscode-remote/ssh-remote+lima-dreadnaught/mnt/aiworkspace/dhd?windowId=_blank
7:22:41
callista
~/work/dhd
$
Naragua
1
1:ssh*

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
7:22:41
callista
~/work/dhd
$
vsc . | xxd 00000000:
1b
5d
383b
3b76
7363
6f64
653a
2f2f
7673
.
]8;;vscode://vs
00000010:
636f
6465
2d72
656d
6f74
652f
7373
682d
code-remote/ssh-
00000020:
7265
6d6f
7465
2b6c
696d
612d
6472
6561
remote+lima-drea
00000030:
646e
6175
6768
742f
6d6e
742f
6169
776f
dnaught/mnt/aiwo
00000040:
726b
7370
6163
652f
6468
643f
7769
6e64
rkspace/dhd?wind
00000050:
6f77
4964
3d5f
626c
616e
6b
1b
5c76
7363
owId=_blank
.
\vsc
00000060:
6f64
653a
2f2f
7673
636f
6465
2d72
656d
ode://vscode-rem
00000070:
6f74
652f
7373
682d
7265
6d6f
7465
2b6c
ote/ssh-remote+l
00000080:
696d
612d
6472
6561
646e
6175
6768
742f
ima-dreadnaught/
00000090:
6d6e
742f
6169
776f
726b
7370
6163
652f
mnt/aiworkspace/
000000a0:
6468
643f
7769
6e64
6f77
4964
3d5f
626c
dhd?windowId=_bl
000000b0:
616e
6b
1b
5d38
3b3b
1b
5c
0a
ank
.
]8;;
.
\
.
7:25:49
callista
~/work/dhd
$

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:

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.


  1. For which there is shamefully no official documentation on the web ↩︎

  2. 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. ↩︎

  3. 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. ↩︎

Responses

Webmentions

Hosted on remote sites, and collected here via Webmention.io (thanks!).

Comments

Comments are hosted on this site and powered by Remark42 (thanks!).