# Attachments — images and files in a message

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.

An on-device vision model reads images through its projector file. When a reply
was written without the conversation's images — the model reads text only, its
projector isn't on this device, or the projector failed to load — a note under
the reply says how many images it missed and why, and a projector that failed to
load can be tried again from there. See
[On-device models](/docs/features/embedded-models#when-the-vision-projector-loads).

## 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/features/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.

More in [Features](/docs/features): [Providers — bring your own LLM](/docs/features/providers) · [On-device models — run fully offline](/docs/features/embedded-models) · [Agents — the thing you build](/docs/features/agents) · [Tools — giving an agent more than the model knows](/docs/features/tools) · [Workspaces — keep your work in scopes](/docs/features/workspaces) · [Conversations — how a turn runs](/docs/features/conversations) · [Context management — what the model still sees](/docs/features/context-management) · [Background turns — replies that keep running](/docs/features/background-turns) · [Local-first & private by design](/docs/features/local-first) · [Sync — your data across your devices](/docs/features/sync) · [Sharing — move agents, tools and providers as a file](/docs/features/sharing) · [Marketplace — find and publish shared agents, tools and providers](/docs/features/marketplace) · [Running a Couchbase Edge Server](/docs/features/couchbase-edge-server) · [Spell checking — catch typos while you write](/docs/features/spell-check)

---

[Bring Your LM](/) · [Docs](/docs/features) · [Marketplace](/marketplace)

[Articles](/articles) · [Releases](/releases) · [Bundle Format](/marketplace/bundle-format) · [Marketplace Terms](/terms) · [App Privacy](/privacy) · [Website Privacy](/website-privacy) · [Open Source](/open-source) · [llms.txt](/llms.txt)
