> ## Documentation Index
> Fetch the complete documentation index at: https://graph.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Work with images and files

> Keep the images and audio MCP tools return, and pass them to other tools by reference.

When an MCP tool returns an image or audio, such as a browser screenshot, Dive stores the file and gives the agent a short reference to it instead of the bytes. The agent can pass that reference to another tool, and Dive hands the tool the file in the form it expects.

```toml config.toml theme={null}
[mcp.browser]
command = "npx"
args = ["-y", "@playwright/mcp"]
files = "path"

[storage.files]
backend = "s3"
endpoint = "https://s3.example.com"
bucket = "dive-files"
region = "us-east-1"
access_key_id = "${DIVE_S3_KEY_ID}"
secret_access_key = "${DIVE_S3_SECRET}"
```

## What a tool's result looks like

Dive stores every image and audio item in a tool's result: inline `image` and `audio` content, embedded resources with binary contents, and `resource_link` items whose MIME type is an image or audio, which Dive reads from the server. The result lists them under `files`, next to whatever text or structured content the tool returned:

```json theme={null}
{
  "text": "Captured https://example.com",
  "files": [
    {
      "ref": "blob:sha256-5d41402abc4b2a76b9719d911017c592a7c1d1d4b2fb7b1f9d1c1e1e2c1a3f4e.png",
      "mime": "image/png",
      "bytes": 48213,
      "width": 1280,
      "height": 800
    }
  ]
}
```

When the tool's result isn't an object, or already has its own `files` key, Dive puts it under `result` instead, as `{"result": …, "files": […]}`.

A reference names the file by its SHA-256 hash, so the same image stored twice is kept once. It stays the same wherever the file is kept, and threads and plan results that mention it keep working if you move file storage to another backend and copy the files across.

Deleting a thread removes the files no other thread refers to, except in S3 storage, where other machines may share the bucket. Files kept in S3 or in memory are copied to a local cache when a tool needs a path. The cache holds up to 512 MB and drops the least recently used files past that.

## Show a file in a reply

Every conversation agent is told about `files` and refs in its system prompt, after its own `system_prompt`. To show the user a file, an agent writes it into its reply as a markdown image with the ref as the URL:

```markdown theme={null}
The pricing page highlights the Team plan:

![The Acme pricing page](blob:sha256-5d41402abc4b2a76b9719d911017c592a7c1d1d4b2fb7b1f9d1c1e1e2c1a3f4e.png)
```

The desktop app draws the image in the message. In a terminal the markdown shows as written. The agent chooses which files to show, so a screenshot it only used to read the page stays in the tool's result.

## Pass a file to another tool

Any argument whose whole value is a reference is replaced before Dive calls the tool. A reference inside longer text is left as it is. Each server's `files` setting decides what the tool receives:

| `files` | The tool receives |
| - | - |
| `path` (default) | A path to the file on this machine. Files kept in S3 or in memory are copied to a local cache first. |
| `url` | A link the server can fetch: a presigned link valid for an hour when files are in S3, otherwise a `file://` URL. |
| `base64` | The file's contents, base64-encoded. |
| `off` | The reference text unchanged. |

Use `url` for a server running on another machine, which can't read your local paths, and `base64` for a server that only accepts file contents in its arguments. Most local servers take a path.

If Dive can't read a referenced file, the tool isn't called and the agent gets an error naming the reference.

## Files in your own tools

An [exec tool](https://graph.mintlify.site/tools/reference/tool-file/exec.md) takes files the same way. Give an input property `format: blob`, or an array whose `items` have it, and a reference passed there reaches the command as a local path:

```yaml tools/thumbnail.yaml theme={null}
version: 3
name: thumbnail
description: Shrinks an image to 256 pixels wide and returns the copy.
kind: exec
command: sh
args: ["-c", "sips -Z 256 \"$0\" --out \"$DIVE_OUT/thumb.png\" >/dev/null && echo '{}'", "{{input.image}}"]
input_schema:
  type: object
  required: [image]
  properties:
    image: { type: string, format: blob }
```

Files the command writes to the directory in `$DIVE_OUT` are stored when it exits successfully and listed under `files` in its result, each with a `ref`, just like a server's. `builtin__generate_image` returns the images it draws as references too, under `images`; see [Image models](https://graph.mintlify.site/getting-started/models.md#image-models).

## Where files are kept

Without a `[storage.files]` table, files follow `[storage].backend`: under `<data_dir>/blobs` for `file`, and in memory for `memory`, which keeps nothing between runs.

To keep files somewhere else, set `[storage.files].backend`:

* `file` keeps files under `<data_dir>/blobs`.
* `memory` keeps files only for the length of the run.
* `s3` keeps files in an S3 bucket, or a bucket on an S3-compatible server such as Garage or MinIO. Set `endpoint` for an S3-compatible server, and `region` to the region it expects. Keys go under `prefix` when you set one, so several stores can share a bucket.

Credentials expand `${NAME}` references like the rest of config.toml, so you can keep them in the OS credential store with `dive secret set DIVE_S3_SECRET`. When `access_key_id` and `secret_access_key` are omitted, Dive reads the standard `AWS_*` environment variables. If a referenced secret isn't set, Dive still starts. A tool call that receives a file then fails naming the missing variable, and files a tool returns are left out of its result, with a warning in the log.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.