Attach a file
How to put images, PDFs, text and Office documents onto a message — the paperclip, drag-and-drop, paste and keyboard shortcut — which file kinds are accepted or refused, the size caps, and what happens to each kind after Send.
What it is
You can attach images and documents to the next message you send by clicking the paperclip icon next to the composer textarea, dragging files anywhere onto the conversation window, or pasting from the clipboard (Ctrl+V — including screenshots). Attached files appear above the textarea as small preview chips (image thumbnails or a FileText icon for documents) before you send. When you hit Send, Omniscio packages the files into the message in the way Claude can actually consume — you don't have to think about which file type goes where.
Three file kinds are supported:
- Images (PNG, JPG, WebP, GIF, etc.) — Claude sees them via vision.
- PDFs — Claude sees them via vision and the file lands in the project folder so the agent can also
Readit as a regular file. - Text documents (
.md,.txt,.csv,.json,.html,.xml,.tsv,.log,.markdown,.ics) — saved into the project folder; the file's path is mentioned in the prompt so Claude canReadand edit it just like any project file.
Office formats — the modern .docx / .xlsx / .pptx, their macro-enabled twins .xlsm / .docm / .pptm, plus legacy binary .doc / .xls / .ppt, OpenDocument .odt / .ods / .odp, .epub, and .rtf — are all accepted. Omniscio extracts them to Markdown in the main process (extractOfficeText, which routes through the on-device anydoc reader for clean tables, with .xlsx on its own dedicated extractor) and injects the extracted .md path into the prompt so the agent can Read it. The Anthropic API has no native Office content block, so Omniscio does the extraction itself — nothing is blocked at attach time anymore.
The macro-enabled trio share the OOXML container with their non-macro twins, so they use the same extractors — a .xlsm reads through the .xlsx pipeline. Not supported: .xlsb (Excel's binary workbook — its sheets are .bin, not XML, so there is nothing to extract) and Apple .numbers. Those are refused with an "unsupported file type" toast rather than being attached in a form the model can't read; save as .xlsx and re-attach.
A file Omniscio can't take always says so. Every intake path — drop, paste, paperclip — names the files it turned away in a single batched toast. If you drop something and no chip appears, you'll get a warning telling you which file and why; silence never means "still working on it".
The deeper "what does Claude actually see for each attachment type" picture lives in chat-attachments.md. This page is for the user-action shape — getting files into the composer.
Also in the "Start session" dialog. The Start session dialog you open from a drip or alert inbox item now takes attachments too — click the paperclip, drag files in, or paste (Ctrl+V, including screenshots) into its prompt box, and the files ride along on the session's very first message. Same file kinds, preview chips, and size limits as below; it reuses the exact composer machinery (the shared usePromptAttachments hook), so nothing behaves differently — you just don't have to open the session first. Documents (PDF / .docx / .txt …) work here as well as images.
Where to find it
How to use it
- Click the paperclip in the small tinted tool zone on the left side of the composer (look for the
Paperclipicon, tooltip "Attach files"). The OS file picker opens. Pick one or more files. The picker'saccept=filter is best-effort — the OS may still let you select anything, and Omniscio re-validates after you confirm.- On a phone, the composer's action buttons show inline in the tinted zone to the left of the text box — the same as on desktop, just the ones you've turned on (no + menu to tap through). Choose which buttons appear — and hide ones you never use to free up room for typing — at Settings → Sessions → Composer buttons; switch them all off and the zone disappears entirely. As the text box grows tall, those icons stack into a vertical column so they stay tidy beside it instead of floating in the middle of the empty space.
- Or drag and drop. Drag any file (or multiple) anywhere over the conversation window — the whole panel highlights with a dashed accent border to confirm a valid drop target. Release. Same validation rules.
- Or paste from clipboard. Ctrl+V (or Cmd+V) inside the textarea works for both copied files (right-click a file → Copy → paste) and clipboard images (e.g. a screenshot you just took with PrtScn / Snipping Tool / macOS Cmd+Shift+5). Pasted images get an auto-name like
pasted-image.png. - (Or use the keyboard shortcut.) Default is Ctrl+U — bound to the
attachFilesaction. It opens the same OS file picker as the paperclip button. - Watch the chips appear. Above the textarea, each attached file shows as a 64×64 chip. Images are thumbnails — click one to open a full-size lightbox, then close it with the large X button in the top-right corner, by tapping anywhere outside the image, or with Esc (arrow keys cycle through if you have several). The close button is a big, high-contrast circle sized for touch, so on a phone you don't have to reach for the device Back button. PDFs and text docs show a
FileTexticon plus the filename. A smallXon the chip itself removes the attachment; you can also middle-click any chip — image or document — to remove it. However you remove one, it is undoable: a toast offers Undo, and Ctrl+Z brings the chip back in its original position (Ctrl+Y removes it again). Removing a chip is never a one-way door. - Type your message and Send. All attached files travel with that one Send. The chips clear after a successful send. If you hit Send with no text but at least one image (or document) attached, Omniscio inserts a placeholder prompt — the
DEFAULT_IMAGE_MESSAGEconstant, "Please analyze the user's image and infer their desire using the project docs, context, and your best abilities, to deliver what they want." — so Claude has something to act on; your typed prompt always overrides this.
Caps and limits:
- No count cap — attach as many images, PDFs, text docs, and pasted-text chips as you want. The IPC schema bounds extreme cases as defense-in-depth (20 images, 50 pasted-text chips per send) but you'll never hit those in normal use. The renderer-side
MAX_IMAGE_ATTACHMENTS = 4/MAX_DOC_ATTACHMENTS = 4caps were removed in 2026-04 alongside paste-as-attachment. - 30 MB per image, 32 MB per document, 2 MB per pasted-text chip — Anthropic's vision limit is 32 MB; Omniscio enforces 30 for images out of an abundance of caution. Oversized files are rejected with a toast.
- One toast per send batches every problem (Office blocked, oversized) into a single friendly warning so you don't get spammed.
- Right-click a chip (image only) for extra actions: Save As, Copy, Open in default viewer.
What happens to the files after Send:
- Images become inline
imagecontent blocks Claude reads with its vision capability — they are NOT saved to your project folder. Nothing has left Omniscio until you Send, so removing a chip (byX, middle-click, or Ctrl+Z) before sending is always reversible. - PDFs are sent inline as a
documentblock (vision-rendered) AND saved to<project-folder>/.claude/amc-attachments/<sessionId>/<filename>. So Claude can both see the PDF as pixels and open it as a file with theReadtool. - Text documents are saved to
<project-folder>/.claude/amc-attachments/<sessionId>/<filename>and the absolute path is prepended to your prompt asPlease examine the following file(s): <path>. Claude canReadand even edit the file in place — it's a real file in your project tree from that point on.
If your project folder isn't writable (read-only mount, permissions error), Omniscio falls back to saving documents under ${userData}/attachments/.claude/amc-attachments/<sessionId>/ and the prompt prefix uses that path instead. The file is still reachable; it just lives outside the project tree. (The .claude/amc-attachments segment is the same subdirectory the writer uses inside a project folder — only the root changes.)
A note about models that can't read the attachment
Some models are text-only or can't take every file kind — for example an image on DeepSeek V4 Flash (non-vision) or V4 Pro, or a PDF on Gemini. If you attach something the session's selected model can't use, an amber note appears above the attachment strip — "{model} can't use attached images — they won't be sent to the model." It's advisory only: sending always still works. The supported-set is data-driven in model-media-support.ts, which resolves per model, not per provider — DeepSeek V4.1 Flash and V4 Flash Vision read images fine even though the DeepSeek provider base is text-only.
How it behaves
How it works
The paperclip and the hidden file input live in SessionComposerToolbar.tsx; on desktop the paperclip opens the main-process native dialog (DIALOG_PICK_ATTACHMENTS in dialog-handlers.ts), whose "All supported" filter is the authoritative extension list, and the hidden <input accept=…> is the web/mobile fallback. The drag-and-drop handlers are mounted on the panel root <div data-ui-anchor="session-panel">, so the entire conversation window — header, message list, and composer — is one big drop target. The dashed accent overlay rendered above all children (pointer-events-none absolute inset-0 z-30) confirms a valid drop. The three input paths (handleFileSelect and handleDrop in useSessionAttachments.ts, handlePaste in useSessionPanel.ts) converge on the same validation pipeline: isBlockedOffice() first, then isAllowedMedia() from session-attachment-validation.ts, then validateAndReadFiles() which size-checks and base64-reads. Accepted files become pendingImages state — the chip strip in SessionPanel.tsx renders from that array.
isAllowedMedia fails closed: a file it doesn't recognise is rejected, never guessed at. There is deliberately no "came from the picker, so trust the accept= filter" shortcut — every OS dialog offers an "All files" escape hatch, so the filter was never authoritative, and defaulting an unknown file to image produced a broken <img> preview chip and shipped the bytes to the model stamped image/png. Every allow-list that decides this — the renderer sets, the ATTACHMENT_MIME_TYPES IPC enum, the send-time partition, the MIME→ext map, and the native dialog's filters — is generated from the single source in attachment-mime.ts so they cannot drift apart.
On Send, the pending attachments travel through SESSION_SEND_RESPONSE to session-service.ts sendResponse(), which calls partitionAttachments() from attachment-partition.ts to split images / PDFs / text docs / dropped. PDFs and text docs go through saveDocToWorkdir() in workdir-attachment-store.ts — atomic write with .tmp → rename, sanitized filename, symlink-escape defense via fs.realpath, and (2)/(3) suffix on collisions. Operator-attached doc paths and any auto-injected .claude/docs/ paths are deduped through a Set and prepended via buildPromptWithAttachments() in image-store.ts. The IPC schema also caps file size and MIME type at the boundary as defense-in-depth — see ipc-schemas.ts ATTACHMENT_MIME_TYPES. Full pipeline detail in chat-attachments.md.
Related
- chat-attachments.md — deeper internals: per-bucket handling, Anthropic API content blocks, save paths, retention sweep
- send-a-message.md — the Send pipeline that ships the attachments
- start-a-new-session.md — needs an open session before you can attach
- project-docs-auto-injection.md — files in
.claude/docs/auto-attach to every session's first message via the same prompt-prefix mechanism
Last verified 2026-10-06