Investigation into why PR links (e.g. PR #1846) are not clickable in Ghostty + zmx revealed that Claude Code does not emit OSC 8 hyperlink sequences. It only applies SGR underline styling (\e[4m) without an associated URI.
- Initial hypothesis: zmx or ghostty-vt's
TerminalFormatterstrips OSC 8 during serialization - Testing:
printf '\e]8;;https://example.com\e\\Click Me\e]8;;\e\\'works correctly in a live zmx session — clickable in Ghostty - VT dump analysis:
zmx history <session> --vtshowed OSC 8 sequences preserved for theprintftest output, but Claude Code's#1846only had\e[4m(underline) with no OSC 8 - Conclusion: ghostty-vt's serializer preserves OSC 8 correctly. Claude Code never emits it.
From zmx history ae-dev.cm-dapp-gateway --vt | cat -v:
printf test output (has OSC 8):
^[]8;;https://example.com^[\Click Me^[]8;;^[\
Claude Code PR link (no OSC 8, just SGR underline):
^[[4m^[[38;5;246m#1846^[[0m
- Claude Code: Should emit
\e]8;;{github_pr_url}\e\\#1846\e]8;;\e\\for PR links instead of just\e[4m#1846 - ghostty-vt / zmx: No changes needed — OSC 8 passthrough and serialization already work correctly
Patches were added to ghostty (snapshot.zig hyperlink table, formatter.zig OSC 8 emission) and zmx (build.zig.zon local path, build.zig hash field, main.zig try removal) during the investigation. These should all be reverted as they address a problem that doesn't exist.
build.zig.zon— revert.path = "../ghostty"back to the git URL + hashbuild.zig— revert the@hasFieldconditional back to direct.hashaccesssrc/main.zig— revertvt_stream.nextSlice()back totry vt_stream.nextSlice()
src/terminal/snapshot.zig— remove hyperlink table serialization/deserialization- VT formatter changes — remove OSC 8 emission logic