---
title: Attachments — images and files in a message
weight: 6500
extra:
  summary: "Attach an image or a text file to a message when the model can read it: what's supported, how the app gates the button on the model's own capabilities, and where the bytes go."
  status: Shipped
---

An attachment is an image or a text file you send alongside your message. The
model reads it as part of the turn — describing a screenshot, reviewing a log,
answering questions about a config file. What you can attach depends on the model
you brought: the app only offers what the model advertises it can read.

## Why it matters

A prompt is text, but the thing you actually want help with often isn't. An
attachment lets you hand the model the artifact itself — a photo, an error log, a
CSV — instead of retyping or describing it. And because the attach options are
driven by the model's advertised capabilities, the app never lets you send an
image to a model that would reject the whole turn for it.

## What you can attach

- **Images**, when the model advertises image input (vision): PNG, JPEG, GIF,
  WebP, BMP, AVIF, and SVG.
- **Text files**, when the model advertises file input: plain text and log files,
  source code in many languages, Markdown, JSON / JSONL, CSV / TSV, XML, YAML,
  HTML, and CSS.

Source-code files of every kind are read as plain text; the model still sees the
real filename, so it knows it's looking at, say, a Dart file rather than a Python
one.

## Attaching one

The composer's attach button opens a short menu. Which entries appear depends on
what the model accepts:

- **Add image…** / **Add file…** — pick from your device.
- **Take a photo** — capture with the camera. Phones only; desktop has no camera
  to reach for.
- **Paste from clipboard** — drop in an image you copied elsewhere. You can also
  insert an image straight from a keyboard that supports it.

Each attachment shows in the composer before you send — an image as a thumbnail,
a file as a document chip — and you can remove any of them before sending. The
attach button itself is hidden entirely when the model accepts neither images nor
files, so it's never a dead control.

## How the model receives it

- An **image** goes to the model inline with your message.
- A **file** goes as a native file part where the backend accepts one, and is
  otherwise folded into the message text so its contents still reach the model —
  either way the model reads the file.

If you switch a conversation to a model that _can't_ read an image already in it,
the turn still runs: the image is left out of the request and the app shows a
warning saying so, rather than failing the send. The point is that a model swap
never silently breaks a turn.

## Where attachments live

Attachment bytes are stored **encrypted on your device**, in a blob store
separate from the conversation database, and are cleaned up when you delete the
message or conversation that referenced them. This is the same local-first,
encrypted-at-rest handling the rest of your data gets — see
[Local-first & private by design](/docs/local-first/).

## What it doesn't do yet

- **Images and text files only.** There's no PDF, audio, or video attachment
  path today — a PDF is not among the pickable file types.
- **The model must advertise the capability.** If a provider doesn't report a
  model's input modalities, the app can't know it accepts images or files, so the
  attach options for those stay hidden even if the model would in fact accept
  them. Bring a provider that advertises what its models can read.
