Skip to content

TUI: image clipboard paste silently ignored on Kitty/Ghostty (regression of #4077) #25806

Closed as not planned

Description

@djmittens

Summary

Ctrl+Shift+V in the opencode TUI silently ignores image/* MIME content on Wayland with Kitty / Ghostty (and likely WezTerm + others that don't pipe binary clipboard bytes through their paste action). This is a regression that's been re-reported repeatedly — most prominently in #4077 (closed by stalebot, not fixed; ~12 confirming reports across Linux/macOS/Windows). Filing a fresh issue with root-cause analysis + a concrete fix path since the previous one died from inactivity.

Reproduction

  1. Run opencode TUI inside Kitty (or Ghostty), no tmux required.
  2. Copy a screenshot to the clipboard via any Wayland-native tool:
    • grimblast copy area
    • hyprshot -s -m output -m active --clipboard
    • GNOME Screenshot
  3. In the opencode prompt, press Ctrl+Shift+V.

Expected: image saved as attachment, like opencode 1.0.x did and like alacritty currently does.
Actual: nothing happens. No toast, no error, no attachment.

Text paste works correctly in the same flow — only image MIME types are dropped.

Why it works in Alacritty and not Kitty

Alacritty's paste_from_clipboard action pipes whatever the system clipboard contains as raw bytes into the TTY (including PNG bytes on image clipboards). opencode receives binary in the bracketed paste sequence, detects PNG signature, attaches as image.

Kitty's paste_from_clipboard action is text-only by design (by maintainer's stated philosophy — terminals are text streams, applications should query MIME-typed clipboards via OSC 52 / OSC 5522 or remote control). Image-only clipboards produce zero terminal input on Ctrl+Shift+V. opencode never sees the bytes.

Ghostty + WezTerm follow the same model as Kitty. So this affects ~all modern non-Alacritty terminals.

Proof (binary inspection)

The wl-paste/xclip image-clipboard code path is already present in both opencode 1.4.3 and 1.14.28 binaries:

```js
// from /usr/bin/opencode (1.14.28), function VL():
if (D === "linux") {
let J = await EQ(["wl-paste", "-t", "image/png"], { nothrow: true });
if (J.stdout.byteLength > 0)
return { data: Buffer.from(J.stdout).toString("base64"), mime: "image/png" };
let H = await EQ(["xclip", "-selection", "clipboard", "-t", "image/png", "-o"], ...);
if (H.stdout.byteLength > 0)
return { data: ..., mime: "image/png" };
}
```

But `strace -fe trace=execve` on a running opencode TUI during a Ctrl+Shift+V paste with image on clipboard captures zero `wl-paste` invocations. So this function exists but isn't reached on the keyboard paste path. The trigger seems to fire only on a different code path (drag-drop?), leaving the keyboard paste flow relying on whatever bytes the terminal happens to type — which is empty for image clipboards in Kitty.

Proposed fix

When opencode receives a paste event (bracketed paste begin) AND the terminal is Kitty / Ghostty / WezTerm (detect via `KITTY_WINDOW_ID`, `TERM_PROGRAM`, etc.), opencode should:

  1. Proactively call the existing `VL()` (or equivalent) clipboard-image-read function regardless of what bytes arrived in the bracketed paste.
  2. If that returns image data → attach as image, suppress the (empty) bracketed-paste content.
  3. If it returns text or nothing → fall through to current bracketed-paste handling.

Even simpler: invoke `VL()` on every paste event before checking bracketed content. If the user pasted text it'll return text data (or fall through cheaply); if image, it'll return image. Cost: one wl-paste subprocess per paste, ~2ms.

For better efficiency on Kitty specifically: use kitty's OSC 5522 clipboard protocol to query `image/png` MIME directly via terminal escape sequence — no subprocess, fully in-band. This is also the path that works through SSH cleanly.

Workaround for users hitting this in the meantime

The community-converged workaround is a script bound to Ctrl+Shift+V in kitty that detects image clipboards, dumps to /tmp, and pastes the path via `kitty @ send-text`. Reference: https://micahstubbs.net/2026/Jan/15/kitty-image-paste-claude-code/

This is fine but it's a separate moving piece per user — solving it in opencode means everyone benefits without touching their terminal config.

Environment

Related

Happy to test patches.

Activity

  1. dontcrash commented on Jun 22, 2026

    @dontcrash

    Works if you install wl-clipboard fyi
    https://archlinux.org/packages/extra/x86_64/wl-clipboard/

  2. kernel-oops commented on Jul 15, 2026

    @kernel-oops
    Contributor

    On kitty/Wayland, image paste works for me using plain Ctrl+V, provided wl-clipboard is installed.

    The important distinction is:

    • Ctrl+Shift+V invokes kitty's terminal-level paste action, which is text-only.
    • Ctrl+V reaches OpenCode's input_paste handler, which calls Clipboard.read() and uses wl-paste to retrieve image/png.

    I tested this with an image copied from Chromium whose clipboard offered only:

    image/png
    chromium/x-source-url
    chromium/x-internal-source-rfh-token
    

    Ctrl+Shift+V did nothing, but plain Ctrl+V attached the image successfully.

    Images copied from applications such as Image Viewer can misleadingly appear to work with Ctrl+Shift+V because they also offer a textual file:// URI. Kitty pastes that URI as text, and OpenCode then recognizes the referenced image file.

    This therefore appears to be primarily a shortcut/documentation issue rather than missing kitty clipboard support. It might be worth documenting plain Ctrl+V as the image-paste shortcut, particularly for users accustomed to Ctrl+Shift+V in Linux terminals.

  3. github-actions commented on Sep 14, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions