--- issueRef: "#155" version: 4 updatedBy: {"kind":"agent","agent_id":"a6c6ea12-bfc6-4bdc-8031-324102dfa34d"} updatedAt: 1786007117827 --- ## Objective Allow the user to paste an image directly from the clipboard into the custom agent chat composer (for example after a screenshot) and send it as a proper attachment. ## Dependency This ticket depends on #154 because clipboard image paste must reuse the durable agent/chat attachment pipeline rather than reintroduce a local-only workaround. ## User expectation The experience should feel close to Codex / Claude Code: - user focuses the custom chat composer; - presses paste after taking a screenshot or copying an image; - sees an attachment chip and, if practical, a lightweight preview; - sends the message normally; - the target agent can actually access the attached image in its sandbox. ## Product constraints - This is for the custom structured chat UI, not the raw PTY/TUI path. - The feature must ride on first-class attachments, not on embedding base64 in the prompt or on temporary browser-only objects. - If the message text is empty but an image attachment is present, product behavior should be explicitly decided: either allow send with attachment-only or require text. Recommendation: allow attachment-only send. ## UX scope Recommended MVP: - intercept paste on the custom chat composer textarea; - detect image MIME types from clipboard data (`image/png`, `image/jpeg`, potentially `image/webp` if stable); - materialize the image through the foundation pipeline from #154; - show an attachment chip with filename, MIME, and size if available; - show a thumbnail preview when cheap and reliable; - allow removing the pasted attachment before send; - send through the same structured attachment contract as picked files. Possible follow-ups, not required in this ticket unless cheap: - multiple pasted images in one operation; - drag-and-drop onto the composer; - richer preview lightbox; - file progress UI for large payloads. ## Edge cases - clipboard contains both text and image; - clipboard contains unsupported binary data; - paste permission / browser-webview limitations; - pasted image too large; - rapid repeated pastes; - session recovery / resend after structured session NOT_FOUND; - removing/replacing an attachment before send. ## Expected technical direction ### Frontend - handle `onPaste` on the composer; - inspect clipboard items and prefer image payloads when present; - route pasted binary data through the attachment creation/import API from #154; - keep attachment state typed and separate from message text; - render attachment chip/preview in the composer area; - keep keyboard behavior intact: Enter sends, Shift+Enter newline. ### Backend - no bespoke clipboard-only path; use the generic attachment pipeline from #154; - if a dedicated import endpoint is needed for raw bytes from the frontend, it should still create the same attachment entity/store record as picked files. ### Sandbox / runtime - the agent must read the resulting stored image through the managed attachment location; - no dependence on the clipboard source continuing to exist after paste. ## Acceptance criteria - Pasting an image into the custom chat composer creates a real attachment entry. - The composer shows the attachment before send and lets the user remove it. - Sending the turn makes the attachment available to the target agent through the first-class attachment pipeline. - The feature works for a typical screenshot flow on supported desktop targets. - Failure states are explicit and recoverable (unsupported clipboard content, too large, import failed). ## QA expectations - verify screenshot paste on the supported desktop platform(s); - verify pasted image is readable by the agent in practice, not just visible in UI; - verify send with attachment-only if product accepts it; - verify no regression on plain text send, picked-file attach, and session recovery. ## Quality bar No workaround such as: - adding a fake path string to the prompt without importing the file; - storing only a browser blob URL; - embedding the whole image inline in prompt text; - relying on arbitrary external paths that the sandbox may or may not read. This ticket is considered done only if the UX is good and the underlying file-access model is solid.