Skip to main content
Author(s): @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:
{
  "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 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:
{
  "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:
{
  "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