Harness Notes

JSON

Image input

11 records ยท Updated 2026-10-15

How to give each harness a screenshot, mockup or diagram from its terminal, what it accepts, and whether the image survives in the saved session.

Getting an image in

QuestionCodex CLIchecked at 0.162.1Claude Codechecked at 2.1.299Cursor Agentchecked at 2026.10.12-d47ca18OpenCodechecked at 2.0.28pichecked at 1.2.0
Paste from the clipboard

Copy an image (or an image file in Finder or Explorer), then press Ctrl+V in the composer; Alt+V and Ctrl+Alt+V also work, and the shortcut list shows Ctrl+Alt+V under WSL. Codex reads the system clipboard, saves it as a temporary PNG and inserts an [Image #1] placeholder. Your terminal's own paste (Cmd+V, Ctrl+Shift+V) only sends text, so it attaches an image only if the pasted text is a path to an image file.

Under WSL, if the Linux clipboard has no image Codex runs PowerShell to fetch the image from the Windows clipboard.

Image paste does not work on Android/Termux, and over SSH it reads the clipboard of the machine running Codex, not your local one.

Ctrl+V is a reserved key: you cannot rebind it in tui.keymap.

Source

Yes. Press Ctrl+V to paste an image from the clipboard (also Cmd+V in iTerm2; Alt+V on Windows; on WSL both Ctrl+V and Alt+V work). The image appears as an [Image #N] chip at the cursor so you can refer to it in your text, and you can rebind the key through the chat:imagePaste action in ~/.claude/keybindings.json.

Linux needs xclip or wl-paste to read the clipboard; WSL2 falls back to PowerShell.

Over SSH the remote machine cannot see your local clipboard; copy the file across with scp and give Claude its path.

Source

Press Ctrl+V in the prompt to paste a clipboard image; it appears as an [Image #1] token. On macOS, a normal Cmd+V that delivers an empty paste (clipboard holds only an image) also attaches it, and a file copied in Finder attaches the actual image. In CLI 2026.10.12 the macOS reader takes PNG, JPEG or TIFF (TIFF is converted to PNG with sips); Linux paste works on Wayland and X11.

Windows clipboard support is listed in the January 2026 changelog, but image paste on Windows is not described separately.

Source

Press Ctrl+V (prompt.paste) to paste a clipboard image as an [Image N] chip. OpenTUI's host clipboard is asked for image/png first, then text. An empty bracketed paste from the terminal also triggers an image read. Press <leader>i (default leader ctrl+x) to preview the attached images.

Source

Press Ctrl+V in the editor (Alt+V on Windows and WSL; rebind via app.clipboard.pasteImage). Pi saves the clipboard image (PNG, JPEG, WebP or GIF; other formats such as BMP are converted to PNG) to a temp file and inserts that file's path into your prompt, and the agent opens it with its read tool. On Linux it uses wl-paste or xclip, on WSL it falls back to PowerShell for Windows screenshots, and in Termux only text can be pasted.

A pasted image arrives as a temp-file path in the prompt text, not as an attachment, so the model sees the pixels only after it reads that file.

If the clipboard holds files copied in Finder (macOS), Ctrl+V pastes their paths instead.

Source
Attach an image file

Start with codex -i shot.png "prompt" or --image a.png,b.png (comma-separated or repeated). Inside the TUI, paste or drag-and-drop a single image path (quoted, shell-escaped, file:// and Windows paths work) or pick a .png, .jpg, .jpeg, .gif or .webp file from the @ file search. Each becomes an [Image #N] attachment. An image path you just type as plain text is not attached; it stays text that the agent can open with view_image.

A pasted or dropped path only attaches if Codex can read the image's dimensions; otherwise it is inserted as text.

The top-level -i takes several values, so a prompt written right after it can be read as another image path. Put the prompt first or end the image list with --.

Source

Drag an image file onto the terminal, or paste or type its path (for example Analyze this image: /path/to/screenshot.png). A dragged or pasted image path is attached as an image straight away; a path Claude only sees as text, or an @path/to/image.png mention, is opened with the Read tool, which also hands Claude the pixels. There is no launch flag for attaching a local image to an interactive session.

A Read(...) deny rule that matches the path stops a pasted or dragged image from being attached.

Pasted and attached images are also saved to a per-session images/ folder in Claude Code's temp directory, so Claude can open or copy them as files.

Source

Drag an image file into the terminal, paste its path, or type @path/to/shot.png. In CLI 2026.10.12, a path that ends in .png, .jpg, .jpeg, .gif, .webp, .bmp, .tif, .tiff, .heic or .heif (quoted, ~/, absolute or file://) becomes an [Image #N] attachment. The hidden --image <path> launch flag only works in print mode (-p).

On macOS, screenshots dragged straight from the floating thumbnail can be unreadable (permission denied); the CLI suggests Cmd+Shift+Ctrl+4 and then pasting.

Only PNG, JPEG, GIF and WebP contents are accepted when the message is sent, so HEIC, BMP or TIFF files dropped in fail with an unsupported-type error.

Source

Paste or drag image paths into the prompt: one path, or up to 32 space-separated paths totalling 20 MiB, using the extensions .png, .jpg, .jpeg, .gif, .webp, .avif and .pdf (.svg goes in as text). @-mentioning a file attaches it by file:// URI, and the server detects images from their bytes. For scripted runs, use opencode run -f.

Source

At launch, pass @path arguments, e.g. pi @screenshot.png "What is wrong here?": image files are attached to the first prompt as real images. Inside the session, type @ to fuzzy-search a file or drag the file into a terminal that pastes its path; that puts the path in your prompt and the agent opens it with read.

Only @file launch arguments become image attachments; paths typed, completed or dropped in the editor stay text.

Source
Images in scripted runs

Yes: codex exec -i shot.png "Explain this error" (or --image a.png,b.png), and codex exec resume --last -i shot.png "follow-up" or codex exec fork <id> -i ... for later turns. Stdin is read only as prompt text, so you can't pipe image bytes. Pass image files with -i and the prompt as an argument or on stdin.

codex exec fork with -i but no prompt fails with Forking with images requires a prompt.

codex debug prompt-input -i shot.png "text" prints the model input Codex would build, without running a turn.

Source

Yes. The simplest route is to name the file in the prompt, as in claude -p "Describe the UI in ./screenshot.png", and Claude reads it with the Read tool. To send the image itself, use claude -p --input-format stream-json --output-format stream-json --verbose and write one JSON user message per line on stdin whose message.content holds an image block with base64 data. A plain-text -p prompt cannot carry image bytes.

Each stream-json message must be a single newline-terminated JSON line.

Reading an image path in -p needs Read permission for that path, for example via --allowedTools Read.

Source

The documented way is to put the path in the prompt, e.g. agent -p "Describe ./screenshot.png", and the agent opens the file with its read tool. CLI 2026.10.12 also has a hidden flag, --image <path> (repeatable), that attaches the image directly to a -p prompt. A text prompt is still required, because print mode exits with No prompt provided for print mode if it is empty.

--image is missing from agent --help and is labelled internal-only in the binary, so it may change without notice.

There is no documented stdin or stream-json input for images.

Source

opencode run -f shot.png "describe this" sends up to 100 files of 10 MiB each, inlined as data: URLs. A text message is required, and stdin only adds to the message text.

Source

Yes: combine @file arguments with -p/--print or --mode json, e.g. pi -p @mockup.png "Build this layout". Piped stdin is read as text and prepended to the prompt, so pipe the prompt and pass the image as @file. --mode rpc rejects @file arguments; send base64 images in RPC commands instead.

Source
Images through the SDK or API

App Server turn/start (and turn/steer) accepts input items { "type": "localImage", "path": "/abs/shot.png" } and { "type": "image", "url": "data:image/png;base64,..." } or { "type": "image", "fileId": "..." }, each with an optional detail of auto, high or original. The TypeScript SDK takes { type: "local_image", path } entries and passes them to codex exec --image. The Python SDK has LocalImageInput(path) and ImageInput(url).

Remote http(s) image URLs are rejected with remote image URLs are not supported; use an inline data URL instead, even though the App Server docs show an https:// example.

localImage paths are read on the machine running the app server. The TUI connected to a remote app server sends local images inline, up to 32 MiB per message.

ACP is available through the separate codex-acp adapter. It turns ACP image blocks into image items, and the turn fails if a block has an http(s) URI. It also rejects images when the current model is text-only.

Source

Yes, through the Agent SDK (TypeScript and Python) in streaming-input mode: yield a user message whose message.content is an array such as [{type: "text", text: "..."}, {type: "image", source: {type: "base64", media_type: "image/png", data: "<base64>"}}]. Single-message (plain string) prompts cannot attach images. If an image block's source is missing or malformed, Claude gets a text note such as [Image could not be processed: ...] and the session continues.

Claude Code has no built-in ACP server; the SDK and --input-format stream-json are the structured inputs.

Source

Over ACP (agent acp), the CLI advertises promptCapabilities.image: true and accepts { "type": "image", "data": "<base64>", "mimeType": "image/png" } blocks in session/prompt. The TypeScript and Python SDKs take agent.send({ text, images: [{ data, mimeType }] }) or { url }. The Cloud Agents API accepts prompt.images (up to 5, 15 MB each, PNG/JPEG/GIF/WebP).

In CLI 2026.10.12, ACP image blocks are passed through as raw bytes without the CLI's own resizing, and blocks that carry only a uri with no data arrive empty.

ACP also sends a cursor/generate_image notification when the agent generates an image.

Source

POST /api/session/{sessionID}/prompt (SDK session.prompt) takes { text, files: [{ uri, name?, description? }] } with uri set to an absolute file: URL or a data: URL. http(s) is rejected. ACP advertises image: true: image blocks with base64 data become attachments, while an image block that has only an http(s) URI is passed as a text link.

Source

RPC mode (pi --mode rpc) accepts an optional images array on prompt, steer and follow_up commands, each {"type":"image","data":"<base64>","mimeType":"image/png"}. In the SDK, call session.prompt(text, { images }), session.steer(text, images) or session.followUp(text, images) with the same ImageContent objects. Pi has no ACP surface.

Images sent with steer, follow_up, or a prompt that is queued during a run skip Pi's resize step and go to the provider as given.

Source

What is accepted

QuestionCodex CLIchecked at 0.162.1Claude Codechecked at 2.1.299Cursor Agentchecked at 2026.10.12-d47ca18OpenCodechecked at 2.0.28pichecked at 1.2.0
Formats, limits and resizing

PNG, JPEG, GIF and WebP are accepted. PNG, JPEG and WebP are sent unchanged when no resize is needed, and anything else, including GIF, is re-encoded as PNG. Images are scaled down to at most 2048 px on the long side and 2,500 32-px tiles, so roughly 1600x1600 for a square image, and the model is told the original and new sizes. With detail: original on models that support it, the limit is 6000 px and 10,000 tiles. There is no attachment count limit, and files over 1 GiB are refused.

An unreadable or unsupported file (for example SVG, BMP or HEIC) does not stop the turn. The model gets a text note saying the image is invalid or unsupported.

detail: low is not supported, and the image is replaced with a note asking for high, original or auto.

Clipboard pastes are always saved as PNG.

Source

PNG, JPEG, GIF and WebP are sent as images; macOS TIFF screenshots, WSL BMP clipboards and CMYK JPEGs are converted first. Claude Code downscales anything over 2000x2000 px and compresses pasted, attached and Read-tool images to the same token budget, re-encoding a still-over-500KB result as JPEG. Requests are capped at 32 MB, and when the API's per-request image count or Claude Code's total image size cap would be exceeded, the oldest images and PDFs are dropped in batches.

An image Claude Code cannot decode or resize is refused with a message telling you to convert it to PNG, JPEG, GIF or WebP.

PDFs are separate: Read takes up to 20 pages per call for PDFs over 10 pages, and the API limit is 100 pages / 20 MB.

Source

Images attached to a message must be PNG, JPEG, GIF or WebP (checked by file signature). In CLI 2026.10.12, attachments are scaled to fit 2048x2048 and re-encoded as JPEG (quality 80), with quality and size stepped down until the image is at most 5 MiB. Images the agent opens with its read tool are re-encoded as WebP at no more than 1280 px on the long side and 1 MiB.

The CLI sets no per-message image count limit; the Cloud Agents API allows at most 5 images per prompt.

Source

Partly

Only PNG, JPEG, GIF and WebP reach the model. AVIF, BMP and other binaries are accepted but left out of the request, and SVG is sent as text. Each attachment can be up to 20 MiB decoded. Images over 2000x2000 px or 5 MiB of base64 are scaled down and re-encoded as PNG or JPEG; set this under media.image (auto_resize, max_width, max_height, max_base64_bytes). If a request holds more than 25 MiB of images, the oldest are replaced with a placeholder until it is under 15 MiB.

v1's attachment.image config key is media.image in v2.

The media type is detected from the file bytes, so renaming a file does not change it.

Source

Files are detected by content as PNG, JPEG, GIF, WebP or BMP (BMP is converted to PNG). By default (images.autoResize: true) Pi shrinks images to fit 2000 x 2000 pixels and 4.5 MiB of base64, trying PNG and JPEG and lowering JPEG quality or dimensions until it fits, and tells the model the original size so it can scale coordinates. Per-model limits go in models.json under inputLimits.images.resize (maxWidth, maxHeight, maxBytes, jpegQuality); Pi does not enforce a count limit.

An image that cannot be converted or shrunk below the limit is dropped and replaced by a text note such as [Image omitted: could not be resized below the inline image size limit.].

Animated PNGs are not recognised as images.

Source
An image with no text

Yes in the TUI: attach or paste an image and press Enter with no text, and the message is sent as just [Image #1]. In App Server, a turn/start whose input contains only an image item is accepted, since only an empty list is refused. codex exec still needs a prompt argument or stdin text.

Source

Not documented

The terminal docs don't say whether a prompt holding only a pasted image is accepted; a paste does leave an [Image #N] chip in the prompt text. The VS Code extension explicitly lets you send an attached image without typing anything, and Remote Control accepts images sent without a caption.

Source

Partly

In the interactive CLI you can submit a prompt that contains only an attached image, but its [Image #1] placeholder is sent as the message text. Print mode (-p) rejects an empty text prompt even when --image is given. Over ACP, a session/prompt that contains only an image block is accepted.

Source

In the TUI, yes: the [Image N] label counts as prompt text, so paste and press Enter. A truly blank prompt is refused in a new session. opencode run needs a message, and the API's text field is required.

Source

Yes. pi @screenshot.png with no message sends the image with only a file-name tag, an RPC prompt with "message": "" and images is accepted, and in the terminal a pasted image path alone is a valid prompt. Pi drops the empty text part for OpenAI-compatible providers that reject it.

Source
Models that can't see images

If the model's catalog entry doesn't list image input, the TUI refuses the attachment with Model <name> does not support image inputs. Remove images or switch models. and keeps your draft. On a model switch, path pastes stop attaching. Images already in the history (or sent through exec or the API) are replaced with the text image content omitted because you do not support image input before each request, and view_image refuses to run.

If the model catalog can't be read, the TUI assumes the model supports images.

Source

Not documented

Claude Code runs Claude models, which all accept images, so there is no documented fallback for a model that can't see them. If the API refuses an image (too large, too many, or unprocessable), Claude Code swaps that image for a text placeholder or drops the oldest images and retries, and Claude no longer sees them.

Behaviour with a non-Claude model behind ANTHROPIC_BASE_URL or an LLM gateway is not documented.

Source

Not documented

Cursor does not document what happens when the selected model cannot read images. In CLI 2026.10.12, the CLI never checks the model's image support itself; images go to Cursor's backend with the request, and any refusal comes from there.

Source

The image is replaced by ERROR: Cannot read "<file>" (this model does not support image input). Inform the user., so the turn still runs and the model says it can't see it. The docs warn to pick a model with image input first.

Source

Pi replaces each image with (image omitted: model does not support images) (or (tool image omitted: ...) for tool results) before sending to a model whose input lacks image, and the read tool adds a note that the image will be omitted. The images stay in the session, so switching to a vision model later sends them again. pi --list-models shows which models take images, and images.blockImages: true withholds images from every model.

Source

Afterwards

QuestionCodex CLIchecked at 0.162.1Claude Codechecked at 2.1.299Cursor Agentchecked at 2026.10.12-d47ca18OpenCodechecked at 2.0.28pichecked at 1.2.0
Kept in the saved session

Yes. Each image is saved inline as a base64 data URL inside the session rollout under ~/.codex/sessions, so codex resume and codex fork send the same pixels again, still labelled with their original path. Local compaction keeps only the text of earlier messages and drops their images. OpenAI-hosted (remote) compaction can keep recent images within a 64,000-token retained-message budget.

--ephemeral sessions are not written to disk, so nothing is kept.

Rollouts with screenshots can get large because the bytes are stored inline.

Source

Partly

The session transcript (~/.claude/projects/<project>/<session>.jsonl) keeps every message, including image content, so --resume, --continue and forks reload it; the separate copies of pasted images in the temp images/ folder are deleted after cleanupPeriodDays. Images do not survive compaction: /compact or auto-compaction replaces them with a text summary, and in long sessions the oldest images are also dropped from requests once size or count limits are hit.

With --no-session-persistence or CLAUDE_CODE_SKIP_PROMPT_HISTORY nothing is written, so there is nothing to resume.

If Claude needs a dropped or compacted image again, share it again.

Source

Partly

Image bytes are stored with the user message in the local chat store, so /rewind puts a turn's images back in the prompt and --resume/--continue reload a conversation that still contains them. Since 2026.10.08, images attached to a message queued during an interrupted turn are sent on the next turn. Cursor does not document whether images survive /summarize; plain-text transcripts show them only as [Image].

Source

Partly

Attachments are stored as base64 in the session message, so resuming or forking keeps the pixels. After summary compaction, the kept recent conversation is converted to text and images become [image/png omitted], so the model can't see older images any more. Native (OpenAI Responses) compaction keeps recent attachments alongside an encrypted checkpoint.

Source

Partly

Image blocks are stored as base64 inside the session JSONL (user attachments and read/tool results), so pi -c, /resume and forks send the same pixels again. Compaction summarises older turns as text only, so images before the kept recent window are lost from context. A pasted image is saved only as its temp-file path in your message; its pixels persist only if the agent read the file.

Images are encoded once at their first resize; changing models later does not re-encode stored images.

Source
The agent opening images itself

Yes. The built-in view_image tool (feature view_image, on by default) lets the agent load any local image file by path and send its pixels to the model. On some models it can ask for detail: original to keep full resolution. There's no built-in screenshot tool, so the agent captures screenshots with a shell command (for example screencapture or Playwright) and then opens them with view_image.

The tool is unavailable on text-only models, and App Server clients see each use as an imageView item.

Source

Yes. The Read tool returns PNG, JPEG and other image files as visual content Claude can see, resized and recompressed to fit the model's limits, and reads PDFs page by page. Images returned by MCP tools (for example browser screenshots from Claude in Chrome or Playwright) are shown inline and also saved to the session's tool-results folder so Claude can crop or reuse the full-size file.

For fine detail in a large screenshot, ask Claude to crop the region first (for example with ImageMagick), since the copy it sees may be downscaled.

Read detects the format from the file bytes, not the extension; a non-image saved as .png is read as text.

Source

Yes. The read tool returns image pixels for .png, .jpg, .jpeg, .gif, .webp, .bmp and .ico files (and files detected as images by content), so you can just mention a path. In CLI 2026.10.12 the read tool re-encodes them as WebP at up to 1280 px and 1 MiB, and reports an error for files that cannot be decoded.

Attached and generated images show as inline previews in terminals that support inline images.

Source

Yes. read detects PNG, JPEG, GIF, WebP and PDF from file contents, reads up to 20 MiB, and passes them to the model after the same resize step. Images that can't be decoded or resized are left out with a note. There is no built-in screenshot tool, though the browser tool can capture pages.

Source

Yes. The built-in read tool opens JPEG, PNG, GIF, WebP and BMP files and returns them to the model as image attachments, resized with the same rules as prompt images. This is how pasted and dragged image paths reach the model, and MCP resources and tool results that contain images are passed on as images too.

Source

Notes and sources

Codex CLI
Claude Code
Cursor Agent
OpenCode
pi