Research: how should a pasted clipboard image present — inline pixels, a text pointer, or a per-tab images panel?

Date: 2026-11-08 Question: Paste-image PI-1/PI-2 (commits cb39a39, d9b8151) landed the full stack — clipboard image bytes → cache file → path pasted as text → full inline render at the cursor — and it works but is not presentable. Which presentation should DropTerm ship: the inline grid render, a text placeholder pointing elsewhere, or a status-bar chip opening a per-tab images panel — and what do the other terminals and terminal-adjacent apps actually do?

TL;DR

Ship the maintainer’s proposal (candidate C): keep the pasted path as the grid’s only trace, drop the full-size auto-render from the paste path, and add a per-tab images panel behind a conditional status-bar count chip. The precedent field is unanimous on the part that matters: none of the ten surveyed terminals pastes clipboard images at all — text-only everywhere — and the two products that do handle clipboard images at the GUI layer (Warp’s input editor, Claude Code in any terminal) both collapse the image to a compact chip/token and never put pixels into a scrollback. The one thing every consumer of a pasted image wants from the terminal is the file path (the Ghostty and Windows Terminal communities describe exactly DropTerm’s PI-1 as the clean solve), and the inline render — the part no peer ships — is also the part with the honest defects: evicted pixels leave blank cells (docs/images.md:51), a tall screenshot displaces the whole viewport, and the scrollback ends up holding terminal-dressed output that no program produced. The panel is not novel-afraid design either: iTerm2’s Toolbelt carries Paste History and Recent Directories lists with click/paste/type-path actions, and CopyQ/Klipper are the OS-level history-list analogs — a per-tab list with thumbnails and per-item actions has three independent precedents. DropTerm’s own band already has the exact chip this needs: the Scrolled chip is conditional (hidden when idle) and its click runs an action verb instead of copy (src/status_bar.rs:997).

What DropTerm has today

PI-1 and PI-2 are done (tasks/paste-image.md: cb39a39 “The read seam and the file path”, d9b8151 “The inline render”); PI-3 (config gate + docs) and PI-4 (retention + manual checklist) are not started. The state, by seam:

This record does not touch the terminal-images decision (2026-11-05): OSC 1337 and kitty placements of program-driven images stay grid cells end to end. What it rules is the one paste-driven placement — whether the terminal should spontaneously render pixels the user copied, on every paste, at full size.

Findings

1. No surveyed terminal pastes images — the paste action is text-only in all ten

Terminal Clipboard-image paste Source
iTerm2 Text-only. Paste Special is text-shaped (escape special characters, paste slowly “in batches of 16 bytes with a 125ms delay”); Paste History “shows recently pasted strings” iterm2.com 3.0 menu-items docs (fetched 2026-11-08); Ghostty #10478, Mitchell Hashimoto (Ghostty maintainer), 2026-03-10: “Fwiw I can’t get Cmd+V to work in any macOS terminal I’ve tried yet… Terminal, iTerm2, Kitty (ctrl+v works fine in all). EDIT: works in Warp.”
WezTerm Text-only. PasteFrom(source) pastes “the specified clipboard”; no mime selection anywhere. Issue #7272 “Pasting Images” (opened 2025-09-30) closed with no implementation wezterm.org PasteFrom docs; wezterm/wezterm#7272 (both fetched 2026-11-08)
kitty Text-only paste (paste_actions are text-shaped). kitten clipboard reads/writes the clipboard including images — but as a CLI pipe (“kitten clipboard -g picture.png”), never a paste-into-terminal path sw.kovidgoyal.net/kitty/kittens/clipboard/ (fetched 2026-11-08)
Ghostty Text + file URLs only. Root cause read from source by a contributor: getOpinionatedStringContents() in NSPasteboard+Extension.swift “only handles file URLs and strings… raw PNG/TIFF image data… falls through both branches and returns nil. That is why the paste silently does nothing.” A proposed fix (PR #11571, 2026-03) is exactly PI-1’s shape: “check for image data… write it to a temp file, and return the escaped path” ghostty-org/ghostty discussion #10478 (fetched 2026-11-08)
Windows Terminal Text-only; the request (discussion #19397, opened 2025-09-30, unanswered) proposes DropTerm’s exact design: “paste a temp file path that point to the image is enough… We just need a standard way to implement” microsoft/terminal discussion #19397 (fetched 2026-11-08)
rio Text-only paste; image rendering ships (all three protocols) but clipboard image paste does not exist rio repo/search, no image-paste feature in tracker (checked 2026-11-08)
Konsole Text-only (“Pasting images doesn’t work on Konsole”, issue Dec 2025; a KDE Brainstorm post states PNG paste is unsupported by design even though Konsole renders Sixel/iTerm2/kitty images) KDE forum/issue tracker via search (issue not fetched directly — see Unverified)
Alacritty Text-only; the paste path has never carried anything but text alacritty config docs; nothing in the tracker (checked 2026-11-08)
xterm.js Text-only by construction: the browser paste event on xterm.js’s hidden textarea “only delivers text, not image data” (issue #1411) xtermjs/xterm.js#1411 (fetched via search, 2026-11-08)
Hyper Text-only; no image-paste feature or issue in the tracker vercel/hyper issue search (checked 2026-11-08)

Two facts sharpen the table. First, the Ctrl+V image paste that works “in iTerm2/kitty/Terminal” in the wild is Claude Code reading the clipboard itself when it sees a bare ^V — Windows Terminal collaborator j4james, 2025-10-11: “I suspect Claude Code may be reading the image directly from the clipboard with an OS API call, and that’s triggered when you press a certain keyboard shortcut… on Windows you need to use Alt+V” (terminal #19397). The terminal is never the reader. Second, Warp is the sole GUI-layer exception, and it routes images to its own input editor, never to a grid: the 2026 changelog reads “Added support for attaching images to prompts in Warp’s TUI” and “Fixed Ctrl-V in the TUI to paste text when the clipboard does not contain an image” (2026.07.23), “Restored image pasting into CLI agents when macOS provides TIFF clipboard data” (2026.09.23) — docs.warp.dev/changelog/2026 (fetched 2026-11-08).

Consequence: DropTerm’s PI-1 — the terminal reads the image, writes a file, pastes the path — is ahead of every peer, and it is precisely what the peer communities ask their maintainers for (Ghostty PR #11571, terminal #19397, and the Ghostty thread’s “just save to $TMPDIR and write the path into the PTY — would solve this cleanly”). The read/file/path half of the module is past-preserving and precedent-confirming; only the presentation of the result is unsettled.

2. The one precedent that ships clipboard images (Warp) shows compact chips, never pixels in scrollback

Warp’s docs describe copy-paste as an attachment route: “Copy and paste images directly (e.g. right-click an image > ‘Copy image’ or copy from a file manager) into Warp”, formats “.jpg, .jpeg, .png, .gif, and .webp”, consumed as agent context with automatic resizing (“Warp will intelligently resize images before passing them as context”) — docs.warp.dev, “Images as Context” (updated 2026-10-26, fetched 2026-11-08). Warp owns an input editor, so the image becomes a compact object in that editor — the community and issue tracker describe them as “image chips” (warpdotdev/warp #6648, 2025-06) — and a 2025 issue records the older behavior Warp replaced: “Dropping an image now shows ‘Switch to Agent Mode to paste images’ instead of inserting the file path” (user-reported issue, Aug 2025). Warp notably never renders a pasted clipboard image into its terminal grid, despite shipping all three image-render protocols (terminal-images.md §4).

Claude Code, the consumer DropTerm’s module explicitly targets (“the Claude Code contract”, SPEC-paste-image.md), is the second chip precedent, and its docs state the shape exactly: “Ctrl+V or Cmd+V (iTerm2) or Alt+V (Windows and WSL) — Paste image from clipboard — Inserts an [Image #N] chip at the cursor so you can reference it positionally in your prompt” — code.claude.com/docs/en/interactive-mode (fetched 2026-11-08). In the Ghostty thread, users show what that chip is backed by: Claude Code writes its own cache file and the chip links it — “it appears as [[Image #1]](file:///Users/q/.claude/image-cache/f048…/1.png)”, while the pi-mono agent “displays a full path, e.g., /var/folders/.../pi-clipboard-a9b5d55c….png” (#10478, comment 2026-02-28). Every shipped example therefore keeps the text stream short and puts the bytes in a named, durable file — the same division DropTerm already built.

3. Editors that paste images insert a file plus a reference — the path is the placeholder

The common shape across all of them: a generated name (image-1.png, pi-clipboard-<uuid>.png, DropTerm’s paste-YYYYMMDD-HHMMSS-<n>.png), a file in a managed location, and a short text marker that references it. None of them makes the marker a bare invented token without a file, and none embeds pixels into the text stream. DropTerm’s bare-path marker (OQ-5) sits inside this family — it is the terminal-flavored version of VS Code’s inserted reference, with the honesty property that a shell can consume it directly.

4. The panel precedents: iTerm2’s Toolbelt lists, and the OS clipboard managers

So the maintainer’s panel has three independent precedents — a terminal-native dock of per-session history lists with click-to-act items (iTerm2), and two OS-level clipboard history panels with per-item actions (CopyQ, Klipper). What none of them does is show thumbnails: iTerm2’s lists are text, CopyQ’s and Klipper’s are list rows (CopyQ renders image items as previews per its README/issues; Klipper’s HTML handbook documents no thumbnails). A thumbnail-grid panel would exceed every precedent; a list panel with small previews matches CopyQ.

5. The grid-integrity facts about inline paste renders

6. Status-bar indicators: the conditional chip with an action verb is an established shape

Design candidates, evaluated

A. Status quo — path as text plus full inline render. Grid integrity is the best of the four mechanically (cells all the way down), and it is what shipped. Rejected as the resting state on the evidence: it is the only behavior in the surveyed field that auto-renders clipboard pastes (every peer renders only program-requested images — Finding 1); the pixels evict to blank cells while the file survives (Finding 5); the render displaces the viewport by the image’s own height (Finding 5); and it doubles the representation of one paste (pixels in scrollback, path on the command line) where every precedent keeps exactly one compact marker plus one file (Findings 2-3).

B. Placeholder-only — a short marker, viewing elsewhere. Grid-clean and precedent-matched on the marker (Finding 3), but “elsewhere” is unspecified, and for a terminal that means the user must find ~/.cache/dropterm/paste/ in a file manager. The editor precedents survive path-only because the file lands inside the user’s project (VS Code’s workspace copy); an XDG cache dir with a 7-day sweep has no such visibility. Rejected without a panel.

C. Status-bar chip + per-tab images panel; the grid keeps the path. Precedent: three independent list-panel models (iTerm2 Toolbelt, CopyQ, Klipper — Finding 4) plus Warp/Claude Code’s chip-keeps-grid-compact rule (Finding 2). Grid integrity: the grid holds only text — every concern in Finding 5 disappears while the mechanism’s honesty (cells, not overlays) is unaffected, since OSC/kitty rendering is untouched. Feasibility, seam by seam: the ledger is a small per-tab append (path, stamp, dimensions) written by the existing handler (src/app.rs:3266-3272 already holds the bytes and the returned path); thumbnails decode lazily from the cache PNGs with the image crate and render through libcosmic’s image primitives (the same handles the grid placement pipeline uses — terminal-images.md “What DropTerm has today”); the panel surface has two proven seams (the settings drawer at app level, or the completion menu’s with_layer panel in src/terminal/widget.rs:1146-1230 — and the suggest-menu-layering record names the Overlay-trait escalation for mouse-interactive surfaces); the chip is a new SegmentId riding DROP_ORDER with click_jumps-style verb routing (src/status_bar.rs:997), hidden at zero count per the exit-chip rule, with the paste confirmation riding the Copied report pattern (:118). Discoverability: the chip is the count, the panel is the list, the path in the grid points at the file — three routes to the same object.

D. Hybrid — a bounded inline preview (a few rows) plus the panel. Technically cheap: resolve_placement already accepts cell-unit width/height, so place_pasted_image could place a 3-row-fitting render instead of auto sizing (engine.rs:1950). It preserves instant visual confirmation and bounds the viewport cost but not the eviction-blank one, and it still spends scrollback on non-output. No peer ships even this for pastes; the nearest analog is xterm.js’s image addon treating a marker as the honest end state — its storage is bounded and “placeholder-on-eviction” replaces pixels with markers (terminal-images.md §7). Deferred, not the default.

Recommendation

Adopt candidate C, in this order of pieces:

  1. The grid keeps the bare path, unchanged. OQ-5’s ruling stands and gains field support: the path is the marker family’s terminal member (VS Code inserts a path reference, pi displays its temp path — Finding 3), and it is the one marker a shell or an AI CLI can consume as-is, which is the module’s stated purpose. No wrapper token: [Image #1] works for Claude Code because Claude Code is the reader of its own input; a shell is the reader of DropTerm’s paste, and a token it cannot parse is noise.
  2. Remove the auto-render from the paste handler (the place_pasted_image call at src/app.rs:3271; keep the engine entry for the deferred preview). This supersedes the working spec’s premise that “the inline render is the visible confirmation” (SPEC-paste-image.md, Objective and OQ-5) — the visible confirmation moves to the band (piece 3). The terminal-images decision is untouched: program-driven OSC/kitty placements keep rendering into cells exactly as docs/images.md documents.
  3. A conditional band chip: N img (or icon + count) when the tab has pasted images, absent at zero, click opens the panel, dropped lowest-priority under width pressure. Paste itself confirms transiently through the Copied-report mechanism — one chip, one pulse, no scrollback disturbance.
  4. A per-tab images panel: a list (CopyQ’s shape) of that tab’s pasted images with small thumbnails decoded lazily from the cache files, each row carrying the actions the precedents imply — open (the OpenHyperlink precedent, src/app.rs:3247-3251 via open::that_detached), copy path (clipboard::write), copy image back to the clipboard (a data-control image/png write through wl-clipboard-rs — the focus-free write path clipboard-ownership built, and the remote-friendly complement to the SSH caveat: bytes travel where a local path cannot), re-paste the path, and remove (delete the cache file and the ledger row, bounded by PI-4’s retention). Panel surface (drawer vs in-widget overlay) is a spec-phase choice between two proven seams; a mouse-interactive panel with thumbnails leans toward the app-level drawer, per the suggest-menu-layering record’s “when the menu wants mouse” rule.
  5. Ordering note: this record lands before PI-3/PI-4, so paste_image_enabled (the config gate) and the retention sweep should ship governing the new shape — the gate’s documented scope (“an image clipboard pastes nothing”) is unaffected by where the render went.

Rejected alternatives:

Relations to existing records: builds on terminal-images (2026-11-05, unchanged — this record rules only the paste-driven placement), the status-bar records (conditional-chip vocabulary, DROP_ORDER, the action-verb precedent), clipboard-ownership (the data-control write path the panel’s copy-image action reuses), and panel-visibility/settings-sidebar (the drawer seam). It supersedes the working spec’s render-confirmation premise only; records and shipped OSC behavior are untouched.

Unverified / open questions

Sources