Terminal capability probe leaks XTVERSION/DA1 replies to the screen at startup (ghostty)
Symptom
On every startup, Claude Code prints the terminal's own capability-query replies above the UI:
^[P>|ghostty 1.3.1-arch2^[\^[[?62;22;52c
These are Ghostty's answers to XTVERSION (ESC [ > 0 q) and DA1 (ESC [ c). They are echoed by the tty line discipline rather than consumed by Claude Code's parser.
Environment
- Claude Code 2.1.263
- Ghostty 1.3.1-arch2,
TERM=xterm-ghostty,COLORTERM=truecolor,TERM_PROGRAM=ghostty - Arch Linux, kernel 7.1.9
- No tmux/screen, no SSH — local terminal
Reproduction
script -q -c claude /tmp/cc.log # start, then /exit
cat -v /tmp/cc.log | head -c 400
Byte trace
Offsets are into the cat -v output of the recording:
130 ESC[?2004h ESC[?2031h ESC[?1004h ESC[<u ESC[>5u setup
218 ESC[>4m ESC[<u ESC[?1004l ESC[?2031l ESC[?2004l teardown -> cooked mode, echo on
234 ESC[>0q ESC[c probe sent in the gap
249 ESC P >|ghostty 1.3.1-arch2 ESC \ reply, echoed by line discipline
271 ESC[?62;22;52c reply, echoed
284 ESC[?2004h ESC[?2031h ESC[?1004h ESC[<u ESC[>5u setup again
330 ESC[?1049h alternate screen entered
7361 ESC[>0q ESC[c second probe, in raw mode - consumed correctly
Claude Code sets the terminal up, tears that setup back down, and writes the capability probe inside the resulting gap while the tty is in cooked mode with echo on. The second probe at 7361 is handled correctly, so the parser itself is fine — only the pre-raw-mode probe leaks.
Ruled out
- Hooks — all
SessionStarthooks emit zero bytes when run under a pty; reproduces with hooks removed. - Plugins — reproduces with
enabledPluginsempty. - Fullscreen renderer /
tuisetting — reproduces underCLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1, where the leak occurs at offset 234 andESC[?1049his never sent at all. - User settings generally — reproduces with an empty
{}project settings file, and with--setting-sources projectand no settings file present.
Startups that are gated behind a dialog (first-run onboarding, or the folder-trust prompt) do not leak: there the probe happens after raw mode is established and the replies are consumed normally. That appears to be the only difference between a leaking and a non-leaking start.
Suggested fix
Send the capability probe only while raw mode is active, or drain its replies before restoring cooked mode.