Windows의 WSL 환경에 있는 Windows Terminal에서 Claude Code를 사용할 때, 이미지 복사 후 Ctrl+V를 눌러도 작동하지 않는 버그의 원인과 해결책을 다룹니다. WSLg의 구식 BMP 변환 문제, 클립보드 동기화로 인한 우회 방법 덮어쓰기, 그리고 Windows Terminal이 단축키를 선점하는 3가지 충돌 문제가 복합적으로 발생하기 때문입니다. 개발자는 이를 해결하기 위해 Windows용 이미지 변환 프로그램과 Linux 스크립트, 키 바인딩 추가 등의 임시 우회 방안을 제안했습니다.
번역된 본문
요약: Windows Terminal 내의 WSL 환경에서 Claude Code를 사용하고 계신가요? Windows에서 이미지를 복사해 Claude Code에 Ctrl+V를 눌러도 작동하지 않습니다. 세 가지가 망가져 있습니다: (1) WSL은 Windows 이미지를 Linux 측에 Claude Code가 읽을 수 없는 오래된 BMP 형식으로만 전달합니다. (2) WSL은 사용자가 적용한 수정 사항을 조용히 덮어써 버립니다. (3) Windows Terminal이 Claude Code가 단축키를 인식하기도 전에 Ctrl+V를 가로챕니다. 해결책은 이미지를 PNG로 변환하는 작은 Windows 프로그램, 이를 Linux 클립보드에 넣는 Linux 스크립트(WSL이 덮어쓴 후 한 번 더 강제 적용), 그리고 키 입력이 실제로 프로그램에 닿도록 하는 Claude Code용 추가 키 바인딩입니다.
Windows에서 이미지를 복사합니다. Windows Terminal에서 실행된 WSL 터미널 안에서 Claude Code를 엽니다. Ctrl+V를 누릅니다. 아무 일도 일어나지 않습니다. Windows 클립보드와 Claude Code의 채팅 입력 사이에서 세 가지 작은 문제가 발생한 것입니다. 각각의 문제는 개별적으로는 해롤 일이 없지만, 함께 작용하여 이미지 붙여넣기를 완전히 실패하게 만듭니다. 이 글에서는 그 원인과 업스트림 수정이 적용될 때까지 제가 직접 만든 우회 방법을 소개합니다.
실제로 무엇이 문제인가
Windows에서 Linux로의 클립보드 동기화는 오래된 이미지 형식만 지원합니다.
WSL에는 WSLg('g'는 그래픽을 의미)라는 내장 기능이 있습니다. 이 기능은 Windows와 Linux가 클립보드를 포함한 항목을 공유하여 경계를 넘어 복사 및 붙여넣기가 작동하도록 만듭니다. 텍스트의 경우에는 잘 작동합니다. 하지만 이미지의 경우 두 가지 치명적인 문제가 있습니다. 첫째, 이미지를 한 방향(Windows에서 Linux로)으로만 동기화합니다. Linux 앱에서 복사한 내용은 이미지 형태로 Windows에 다시 전달되지 않습니다. 둘째, WSLg가 Windows 이미지를 Linux로 보낼 때 단일하고 구식 형식인 희귀한 색상 인코딩('BI_BITFIELDS')을 사용하는 오래된 BMP 변형으로 변환합니다. 대부분의 소프트웨어 BMP 리더는 이를 처리할 수 없으며, Claude Code의 리더도 예외는 아닙니다. 전달된 데이터를 읽으려 시도하지만 유용한 것을 얻지 못하고 조용히 포기합니다. 오류도, 알림도, 눈에 보이는 실패도 없습니다. 이미지가 그냥 첨부되지 않을 뿐입니다. (이는 이미 알려진 버그입니다: claude-code#50552)
동일한 Windows-Linux 동기화가 우회 방법을 조용히 덮어씁니다.
이렇게 생각할 수 있습니다: '좋아, 이미지에 대해서는 WSLg를 우회하자. 내가 직접 Windows 클립보드를 읽어서 이미지를 PNG로 변환한 다음, PNG를 Linux 클립보드에 직접 넣겠어.' 그러면 Claude Code는 이미지를 찾을 때 PNG를 발견하고 붙여넣기가 작동할 것입니다. 클립보드에 항목을 넣기 위한 표준 Linux 명령어인 wl-copy도 있습니다. 그래서 정확히 그렇게 합니다: Windows 이미지 → PNG → wl-copy --type image/png. 작동합니다. 잠시 동안은요. 그리고 다시 작동을 멈춥니다.
WSL이 하는 일은 다음과 같습니다:
Linux 클립보드에 PNG를 넣습니다.
WSLg가 Linux 클립보드가 변경된 것을 감지하고 이를 충실히 Windows에 다시 동기화합니다. 이제 Windows 클립보드에는 'PNG'가 반영됩니다.
Windows 클립보드가 방금 변경되었습니다.
이로 인해 WSLg의 다른 절반, 즉 Windows의 변경 사항을 Linux로 푸시하는 절반이 실행됩니다. 문제 #1에서 알 수 있듯이, 이 절반은 BMP 푸시만 알고 있습니다. 따라서 Linux 측에 있던 정상적인 PNG는 방금 넣은 직후에 깨진 BMP로 덮어씌워집니다.
가장 잔인한 부분은, Windows 클립보드를 감시하도록 작성한 프로그램이 4단계가 일어나는 것을 전혀 감지하지 못한다는 것입니다. WSLg는 Windows 클립보드를 거치지 않고 Linux 클립보드에 직접 기록합니다. 따라서 감시 프로그램의 관점에서 볼 때, Linux 클립보드는 반응할 수 있는 아무런 단서도 없이 그냥 조용히 내용이 변이(mutate)해 버립니다.
Windows Terminal이 Claude Code보다 먼저 Ctrl+V를 가로챕니다.
위의 모든 문제를 해결하여 진짜 PNG가 Linux 클립보드에 안정적으로 올려졌다고 가정해 봅시다. Claude Code에서 Ctrl+V를 누릅니다. 여전히 아무 일도 일어나지 않습니다. 이유는 사용자가 입력하고 있는 프로그램인 Windows Terminal 자체가 Ctrl+V에 대한 고유한 의미를 부여하고 있기 때문입니다. 바로 'Windows 클립보드에서 텍스트 붙여넣기'라는 표준 단축키입니다. 따라서 Windows Terminal 내에서 Ctrl+V를 누르면:
Windows Terminal이 가장 먼저 키 입력을 봅니다.
Windows 클립보드의 내용을 텍스트로 터미널 입력에 붙여넣으려고(또는 붙여넣으려고) 시도합니다.
키 입력은 Linux 측으로 절대 전달되지 않습니다.
Claude Code의 이미지 붙여넣기 코드(내부적으로 chat:imagePaste라 명명됨)가 실행되지 않습니다.
터미널은 Linux 계층 바로 위에 있는 하나의 레이어입니다.
tl;dr Use Claude Code in WSL inside Windows Terminal? Copying an image in Windows and pressing Ctrl+V in Claude Code doesn't work. Three things break: (1) WSL only hands Windows images to the Linux side in an old BMP format Claude Code can't read; (2) WSL also keeps quietly overwriting your fixes a moment later; (3) Windows Terminal grabs Ctrl+V before Claude Code can see it. The fix is a small Windows program that converts the image to PNG, a Linux script that puts it on the Linux clipboard (and re-asserts once after WSL overwrites it), and one extra keybinding for Claude Code so the keystroke actually reaches the program. Copy an image in Windows. Open Claude Code inside a WSL terminal launched from Windows Terminal. Press Ctrl+V. Nothing happens. Three small things between the Windows clipboard and Claude Code’s chat input are broken. Each one is harmless on its own. Together they make image paste fail completely. Here’s what they are and the workaround I built until the upstream fixes catch up. What’s actually broken 1. The Windows-to-Linux clipboard sync only knows about an ancient image format WSL has a built-in piece called WSLg (the “g” is for graphics). Its job is to make Windows and the Linux side share things — including the clipboard, so copy-paste works across the boundary. For text, it works fine. For images, it does two things badly. First, it only syncs images in one direction: from Windows to Linux. Anything copied from a Linux app doesn’t flow back to Windows as an image. Second, when WSLg sends a Windows image over to Linux, it converts it into a single, dated format — a specific old BMP variant that uses an obscure colour encoding (“BI_BITFIELDS”). Most software’s BMP readers can’t handle it. Claude Code’s reader is one of those. It tries to read what arrives, gets nothing useful, and gives up — silently. No error, no toast, no visible failure. The image just doesn’t attach. (This is a known bug: claude-code#50552 .) 2. The same Windows-to-Linux sync silently overwrites your workarounds You might think: fine, I’ll bypass WSLg for images. Read the Windows clipboard myself, convert the image to PNG, push the PNG straight onto the Linux clipboard. Claude Code will then find a PNG when it looks for an image, and the paste will work. There’s even a standard Linux command for putting things on the clipboard: wl-copy . So you do exactly that — Windows image → PNG → wl-copy --type image/png . It works. For a moment. Then it stops working again. Here’s what WSL does to you: You put a PNG on the Linux clipboard. WSLg notices the Linux clipboard changed, and dutifully syncs it back to Windows. The Windows clipboard now reflects “PNG.” The Windows clipboard just changed. That fires WSLg’s other half — the half that pushes Windows changes over to Linux. As we know from problem #1, that half only knows how to push BMP. So your good PNG on the Linux side gets overwritten with the broken BMP, shortly after you put it there. The cruellest part: the program you wrote to watch the Windows clipboard never sees step 4 happen. WSLg writes to the Linux clipboard directly — it doesn’t go through the Windows clipboard to do it. So from your watcher’s point of view, the Linux clipboard just silently mutates , with nothing for you to react to. 3. Windows Terminal eats Ctrl+V before Claude Code sees it Suppose you fix everything above and a real PNG sits reliably on the Linux clipboard. Press Ctrl+V in Claude Code. Still nothing happens. The reason: Windows Terminal — the program you’re typing into — has its own meaning for Ctrl+V. It’s the standard “paste text from the Windows clipboard” shortcut. So when you press Ctrl+V inside Windows Terminal: Windows Terminal sees the keystroke first. It pastes (or tries to paste) the Windows clipboard as text into the terminal input. The keystroke never makes it down to the Linux side. Claude Code’s image-paste code (internally named chat:imagePaste ) never runs. The terminal is one layer above Claude Code. It eats the input before the program below can react. The fix Three small components, one per failure, laid out in the diagram below. clip-listener.exe — runs on Windows and encodes each clipboard image as a real PNG via Windows’ own GDI+. Sidesteps the BMP problem (#1). wsl-clip-bridge — runs in WSL, pushes the PNG onto the Linux clipboard with wl-copy , and re-asserts once half a second later if WSLg has overwritten our PNG with the broken BMP. Handles the silent clobber (#2). Alt+V keybinding in ~/.claude/keybindings.json — triggers Claude Code’s chat:imagePaste handler without going through Ctrl+V, which Windows Terminal would eat. Routes around #3. What changes when the bridge is installed. Without it (top), images flow straight to Claude Code as broken BMP and the paste fails. With it (bottom), a Windows listener encodes a real PNG and a Linux script puts it on the Linux clipboard, re-asserting once after WSLg's overwrite. The user presses Alt+V instead of Ctrl+V to bypass Windows Terminal. End to end: snip an image in Windows, press Alt+V in Claude Code, image attaches. The full source — the Go listener, the bash bridge, the install script, and a more detailed walkthrough — lives at github.com/rajveerb/wsl-clip-bridge . Try it yourself Prerequisites: WSL2 with WSLg (Windows 11, or a recent Windows 10 + WSL update), Go 1.20+ on the Linux side for cross-compiling the Windows binary. git clone https://github.com/rajveerb/wsl-clip-bridge.git cd wsl-clip-bridge sudo apt install wl-clipboard ./install.sh --with-autostart --with-keybinding That last command does four things: cross-compiles the Windows-side listener ( GOOS=windows GOARCH=amd64 ), drops the binaries into ~/.local/share/wsl-clip-bridge/ and ~/.local/bin/ , appends a snippet to ~/.bashrc that starts the bridge on every new WSL shell, and writes ~/.claude/keybindings.json with alt+v → chat:imagePaste . Open a fresh WSL terminal. The bridge starts in the background. Verify: # copy any image in Windows (Win+Shift+S) wl-paste -l # should print image/png Then in Claude Code, press Alt+V . The image attaches. The repo README walks through each step in more detail (running without the install script, stopping or uninstalling the bridge, debugging via the log). Whose problem is it? Four things contribute to the failure. The first problem above (“an ancient image format”) is really two separate issues, so the table splits them apart: # Failure Whose problem 1 WSLg only sends Windows images to Linux as image/bmp Microsoft (WSLg) 2 Claude Code can’t read the BMP it actually receives Claude Code — one-PR fix 3 WSLg overwrites the Linux clipboard from Windows, silently Microsoft (WSLg); only matters because of #1 and #2 4 Windows Terminal grabs Ctrl+V before WSL programs see it Microsoft (Windows Terminal); Claude Code could route around it #1 is hardcoded in WSLg’s clipboard bridge ( rdpclip.c in Microsoft’s Weston fork): exactly five Windows→Linux format mappings, and the only image one is CF_DIB → image/bmp . The strings image/png and image/jpeg don’t appear in the source. The upstream issue microsoft/wslg#833 has been open since September 2022. #2 is broader than the post above implies, and more fixable than I first thought. Claude Code bundles sharp as its image library, in its WebAssembly build. That build’s bundled libvips has no BMP loader — not just no BI_BITFIELDS variant, no BMP support of any kind. Claude Code does detect BMP on the clipboard and try to convert it via sharp(bmpBuffer).png().toBuffer() , but the call dies with “Input buffer contains unsupported image format.” Despite the user-facing implication that BMP is supported, sharp’s WASM build can’t read any BMP. The actual upstream fixes are: ship sharp’s native libvips build (which has BMP support); ship a small BMP→PNG converter that doesn’t go through sharp at all; or shell out to ImageMagick or GDI+ on detection failure. Any of these obsoletes this entire bridge. #3 isn’t hypothetical. The