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

# v2 Diff File States

Author(s): [@benbrandt](https://github.com/benbrandt)

## Elevator pitch

> What are you proposing to change?

ACP v2 should replace the v1 `Diff` shape's ambiguous `oldText` / `newText`
fields with a structured diff content shape that can represent text patches,
non-text file changes, and file-level operations such as add, delete, modify,
move, and copy.

Every diff should carry structured file-change metadata. Text changes can also
carry renderable git patch text in an optional top-level `patch` field.

## Status quo

> How do things work today and what problems does this cause? Why would we change things?

ACP v1 represents a diff as a path plus old and new text:

```json theme={null}
{
  "type": "diff",
  "path": "/home/user/project/src/config.json",
  "oldText": "{\n  \"debug\": false\n}",
  "newText": "{\n  \"debug\": true\n}"
}
```

That shape has several problems:

* `newText: ""` cannot distinguish a deleted file from an empty file without an extra flag.
* Moves and copies have no direct representation.
* Binary files, symlinks, and directory entries do not have useful `oldText` and `newText` values.
* Clients have to reconstruct or parse a diff to render changes.
* The protocol cannot express whether a file path was added, deleted, modified, moved, or copied.

The v1 [Represent deleted files in diff](/rfds/diff-delete) RFD is a useful
stop-gap for deletes, but v2 can use a cleaner breaking shape instead of adding
more flags to the v1 structure.

## What we propose to do about it

> What are you proposing to improve the situation?

ACP v2 should make `ToolCallContent` diffs carry a required `changes` array and
an optional `patch` object.

Use `patch` for changes that have useful renderable patch text:

```json theme={null}
{
  "type": "diff",
  "changes": [
    {
      "operation": "modify",
      "path": "/home/user/project/src/config.json",
      "fileType": "text",
      "mimeType": "application/json"
    }
  ],
  "patch": {
    "format": "git_patch",
    "diff": "diff --git /home/user/project/src/config.json /home/user/project/src/config.json\n--- /home/user/project/src/config.json\n+++ /home/user/project/src/config.json\n@@ -1,3 +1,3 @@\n {\n-  \"debug\": false\n+  \"debug\": true\n }\n"
  }
}
```

The patch format should be `git_patch`. A single git patch can describe several
files, so the patch is top-level context for the whole `changes` array. Clients
can render the patch text directly for baseline compatibility, and can use
`changes` to identify affected paths and operations without parsing the patch.
Agents SHOULD provide `patch` whenever feasible. Clients MUST handle diffs
where `patch` is omitted or `null`.

Omit `patch` when patch text is not useful:

```json theme={null}
{
  "type": "diff",
  "changes": [
    {
      "operation": "modify",
      "path": "/home/user/project/assets/logo.png",
      "fileType": "binary",
      "mimeType": "image/png"
    }
  ]
}
```

Omitted and `null` `patch` values are equivalent and mean no renderable patch
text was provided.

The initial operation set should be:

* `add`
* `delete`
* `modify`
* `move`
* `copy`

`add`, `delete`, and `modify` use `path`. `move` and `copy` use `oldPath` and
`path`. All paths in protocol payloads are absolute.

The optional `fileType` field should describe the file entry when known:

* `text`
* `binary`
* `directory`
* `symlink`

The optional `mimeType` field should carry a MIME type when known. Omitted and
`null` values for `fileType` and `mimeType` mean the value is unknown.

## Shiny future

> How will things play out once this feature exists?

Clients can render text diffs without needing to synthesize patch text, and can
show file-level summaries without parsing patch syntax. Agents can report binary
updates, symlink changes, deletes, moves, and copies without forcing those cases
through text-only fields.

The v2 diff surface is also easier for SDKs to model because operations are
explicit enum variants rather than inferred states from optional text fields.

## Implementation details and plan

> Tell me more about your implementation. What is your detailed implementation plan?

1. Replace the v2 `Diff` struct's old text fields with a required `changes` array.
2. Add an optional `patch` field with `format` and `diff`.
3. Use `git_patch` as the ACP-defined patch format, and document that Agents SHOULD provide it whenever feasible.
4. Add structured `DiffChange` operation variants for add, delete, modify, move, and copy, with path fields owned by each operation variant.
5. Add optional `fileType` and `mimeType` fields for non-text and unknown file content.
6. Preserve custom or future operations where the receiver can safely store, replay, forward, or display a generic summary.
7. Update generated schema and v2 protocol docs.

## Frequently asked questions

> What questions have arisen over the course of authoring this document or during subsequent discussions?

### Why use git patch instead of unified diff?

Git patch is broadly supported, renderable as text, and can carry file-level
headers for multiple files. ACP can still add future patch formats if another
format becomes necessary, but v2 should define one default format first.

### Why is `patch` top-level instead of attached to individual changes?

Git patch text can describe several files and several operation kinds at once.
Keeping `patch` top-level makes it renderable context for the whole diff content
item, while `changes` remains the structured source for paths and operations.

### Should patch text be restricted to some operation variants?

No. Git patches can represent adds, deletes, modifies, moves/renames, copies,
and some binary changes. If an Agent has useful patch text for a set of changes,
it can include `patch`; otherwise it can omit it.

### Why is `patch` optional if Agents SHOULD provide it?

Some changes have no useful patch text, especially same-path binary updates and
symlink target changes. Patch generation can also fail or be unavailable in a
given Agent implementation. Keeping `patch` optional lets clients rely on
structured `changes`, while the SHOULD encourages better rendering when patch
text is practical.

### What kind of `modify` does not have a patch?

Mostly in-place non-text updates, such as a binary file update at the same path
or a symlink target change. Text modifications should normally use
`patch` so clients have renderable text.

### Why include both patch text and structured changes?

Patch text gives clients an immediate baseline rendering path. Structured
changes give clients operation and path metadata without requiring patch
parsing, which matters for summaries, file trees, permissions, and non-text
indicators.

## Revision history

* 2026-07-02: Initial draft
