anthropics / anthropics/claude-code
Kitty graphics probe: iTerm2's i=less OK reply fails the response regex and is typed into the prompt as GOK
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 147k
- Forks
- 24k
- PR merge metrics
- PR metrics pending
Description
Symptom
Every new session in iTerm2 starts with GOK already typed in the prompt box:
> GOK█
Deterministic, not load-dependent: it happens on every startup, in every directory, with no tmux/screen and no SSH.
Environment
- Claude Code 2.1.275
- iTerm2 3.5.11,
TERM_PROGRAM=iTerm.app,TERM=xterm-256color,COLORTERM=truecolor - macOS 26.0 (Darwin 25.6.0), arm64
- No multiplexer, local terminal
Root cause
The three characters are the payload of iTerm2's answer to the inline-image capability probe, left unconsumed and then treated as typed input.
1. We send the kitty graphics query (id 31):
function T(e){ return x(e,y), b(`i=${e},s=1,v=1,a=q,t=d,f=24`, "AAAA") }
var S = 31;
function uEr(){ return { request: T(S), match: (e) => e.type === "kittyGraphics" && e.id === S } }
2. iTerm2 answers without the i= key. Captured off /dev/tty with termios in raw mode:
sent '\x1b_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\x1b\\'
reply b'\x1b_GOK\x1b\\'
For contrast, the other four probes in the same run all answer in the expected shape:
'\x1b[?u' -> b'\x1b[?0u'
'\x1b[>0q' -> b'\x1bP>|iTerm2 3.5.11\x1b\\'
'\x1b]11;?\x1b\\' -> b'\x1b]11;rgb:0000/0000/0000\x1b\\'
'\x1b[?6n' -> b'\x1b[?5;1;1R'
3. Our parser requires i=<digits>;, so the reply never becomes an event:
/\x1b_G(?:[^;]*,)?i=(\d+)[^;]*;(.*?)\x1b\\/s
No kittyGraphics event is produced, match never fires, the query stays queued, and the bytes fall through to the key decoder. That drops the \x1b_ introducer and the \x1b\ terminator and inserts the payload as text, giving G + OK.
The kitty spec does say the response echoes the id it was sent, so iTerm2 is the non-conforming side here and we are reporting it there too. A capability probe that mistypes into the user's prompt on a widely used terminal seems worth hardening regardless.
Reproduction
Open Claude Code in iTerm2 3.5.11 and look at the prompt line. To see the reply on its own:
import os, termios, tty, select
fd = os.open("/dev/tty", os.O_RDWR); saved = termios.tcgetattr(fd)
try:
tty.setraw(fd)
os.write(fd, b"\x1b_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\x1b\\")
print(os.read(fd, 256) if select.select([fd], [], [], 1)[0] else b"(no reply)")
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, saved); os.close(fd)
Expected
The probe reply is consumed or discarded. Nothing reaches the prompt buffer.
Suggested fixes
- Accept an
i=-less response. Make thei=group optional in the response pattern, and treat a bareOKas answering the outstanding graphics query. Only one is ever in flight, somatch'se.id === Scheck has no ambiguity to resolve. - Never route an unrecognized APC/DCS/OSC reply to the key decoder. An escape sequence we asked for and then failed to parse should be dropped, not typed. That would also have contained #78855, #78693 and #91530, which reach the same end state by different paths.
Secondary impact
The only other route to inline-image support is a name check against ["kitty", "ghostty"] (or kitty(>=0.28.0)) on the XTVERSION name, and iTerm2 reports iTerm2 3.5.11. So unforced, iTerm2 is always classified as not supporting inline images even though it does, which the probe result above demonstrates. Fixing the parse fixes both symptoms.
Workaround
export CLAUDE_CODE_FORCE_TERMINAL_IMAGES=1
This has to be exported by the shell before launch. Putting it in settings.json under env does not work, because that block is injected into child processes only and never into the process that runs the probe. Possibly worth a docs note of its own.
Related
#93004, #91530, #78855, #78693 are the same failure mode (probe replies reaching the input path or the screen) from timing and echo causes rather than a parse rejection.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by locating the kitty graphics response regex and the key-decoder path described in the issue, then reproduce the probe reply in iTerm2 using the provided Python snippet. Verify that the i=-less APC response is consumed or discarded and that no GOK reaches the prompt. Check the related probe failure paths if the parser change affects them.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100