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

# File edit diffs

> How Orchestra records every file a session changes, what it shows when a diff is unavailable, and how operators restore edits captured before the fix

Every file a session changes renders as a diff: inline in the conversation,
rolled up per file in the session's Changes tab, and on the session's full diff
page. This page covers how each turn's changes are recorded, the full diff,
what capture keeps, how the views stay honest when a diff is not available, and
the operator command that restores edits captured before 2026-10-19.

## Every file a turn changed

An agent's edit tool reports the edits it meant to make. Plenty of changes
come from elsewhere: a script the agent runs, a formatter, `sed -i`, a code
generator, `git checkout`. So Orchestra also reads the files themselves.

When a turn starts, the machine running the session takes a picture of the
repository, and it takes another when the turn ends. The difference is the
turn's record: every file that was created, edited, deleted or renamed, with
the whole file before and after and git's own line counts. In the
conversation it closes the turn as **N files changed during this turn**, with a
link to the full diff. A file no tool call already showed starts open; one an
edit tool showed starts folded, because its diff is right above.

Where a turn has a record, the Changes tab and the full diff use it for that
turn: real diffs of whole files, with real line numbers. A turn without one (a
session from before this, or a folder that is not a git repository) shows what
the edit tools reported, as before.

How the pictures are taken:

* Each picture is a git tree written from a private copy of the repository's
  index. Your own staging area, branch, stash and working tree are never
  touched, and files your `.gitignore` excludes are left out.
* It runs for every kind of session: one started from the web app on your
  machine, one started from the terminal client, a cloud run, and Claude Code
  in your terminal,
  where the prompt hook takes the first picture and the Stop hook the second.
* A picture takes tens of milliseconds on a repository of a few thousand
  files.
* Contents are redacted before they leave the machine (for terminal sessions,
  with your redaction packs) and again when they reach the log, like every
  other session event.
* A file over 1 MiB is listed with its line counts but without its contents.
  A turn carries at most 4 MiB of contents and lists at most 500 files; files
  past that are counted, not listed.

Anything that changes the repository while the turn runs is in its record,
including your own edits in an editor. That is why the row says "changed
during this turn" rather than claiming the agent wrote everything.

### Edits between turns

Edits you make while the agent is idle, after one turn ends and before your
next prompt, are recorded too. The tree each turn ends on is kept, so when the
next turn starts, the difference between the two is its own record. In the
conversation it shows as **N files changed between turns**, noting that the
agent wasn't working, and its changes appear in the Changes tab without the
agent's name on them.

A few limits:

* The first turn of a session has nothing before it to compare against, so
  edits made before the first prompt are not recorded.
* Edits after the session's last turn are not recorded: there is no next turn
  to compare against.
* In terminal Claude Code, the record is sent with the next turn's own record
  when that turn ends, so it shows up then rather than at the prompt.
* If you stop a terminal Claude Code turn with Esc, no Stop hook runs. Your
  edits before the next prompt then land in that next turn's record instead.

## The full diff

**Open full view** in a session's Changes tab, or **Full view** next to any
edit in the conversation, opens the session's full diff in a new browser tab.
It shows everything the session changed, laid out the way code review tools
show a pull request:

* The changed files are listed down the left, in folders, with each file's
  `+` and `−` counts. Type in **Filter changed files** to narrow the list, and
  click a file to jump to it. Opened from an edit, the page starts at that
  edit's file.
* Each file is a card. Its header stays at the top of the page while you read
  the file, with its counts, a five-square bar of how much was added and
  removed, its path (with a button to copy it), and how many edits it took.
* A file's edits are shown open, one after another, labeled **Edit 1 of 3**
  and so on. A failed, pending, truncated or binary edit says so in its place.
* **Split** shows the old and new side by side, and **Unified** shows them in
  one column. Your choice is remembered in this browser.
* **Viewed** folds a file away and counts toward "2 of 5 viewed" at the top.
  The mark is kept in this browser, and it clears itself if the file gets
  another edit, so new work is never hidden.

The full diff is shown only to people who can see the session.

## What capture keeps

Capture reads each agent's transcript and writes its tool calls to the event
log. A tool call's input is capped by size, measured on its JSON:

| Tool | Cap |
| - | - |
| File edits: Claude Code `Edit`, `MultiEdit`, `Write`, `NotebookEdit`; Codex `apply_patch`; OpenCode `edit`, `write`; the same tools in Orchestra-native sessions | 1 MiB (UTF-8 bytes) |
| A shell command that writes a file with a heredoc (see below) | 1 MiB (UTF-8 bytes) |
| Every other tool | 2,000 characters |

A file edit's input is the edit itself, so it is kept whole. The 1 MiB cap is
the size the write path already sends in one database statement (the event
batch and the transcript archive segment are both 1 MiB), well inside the API's
16 MiB request limit. The largest edit measured on real Claude Code transcripts
was 163 KB.

An edit over the cap is stored as a 2,000-character preview marked truncated.
It still names its file; it never renders as a diff.

## Line numbers

When Claude Code finishes a file edit, it reports the patch it applied, with
line numbers taken from the file itself. Capture keeps that patch with the
edit's result (up to 1 MiB, redacted like the edit), and every view draws the
edit from it: the hunk header and the line numbers are the ones you would see
in the file. A `Write` over an existing file is shown as a real diff against
the file it replaced, instead of every line as new. A `Write` that created a
file has no patch, and shows all of its lines as added.

The patch is part of the result, not the input, so an edit whose input was
truncated still shows its whole diff when its result carried a patch.

An edit without a patch (any edit captured before 2026-10-20, an edit whose
result has not arrived yet, and edits from OpenCode) only says which text was
replaced, not where it sits in the file. Its diff is drawn without line
numbers, and its header reads **Line numbers not recorded for this edit**,
rather than numbering lines from the top of the replaced text.

## Files written by a shell command

A turn's record catches every file a command wrote. Orchestra also ties a
file to the exact command that wrote it, when the command says so itself: a
shell heredoc, for example:

```bash theme={null}
cat > test.py <<'EOF'
for i in range(1, 11):
    print(i)
EOF
```

Orchestra reads that as a written file, the same as a `Write`: the command
keeps its line in the conversation and the file it wrote shows under it with a
link to the full diff. This also covers sessions captured before turn records
existed. A relative
path is resolved against a `cd /absolute/path` earlier in the same command.
The heredoc gives the new contents but not the old ones, so the change shows
the written lines without a line-level diff.

Only `cat > file` and `tee file` fed by a heredoc count. Orchestra does not
guess at writes whose contents are not in the command: appends (`>>`,
`tee -a`), `sed -i`, `echo ... > file`, a copy, a script that writes, or a
target named by a variable.

## What the views show when a diff is unavailable

A diff is unavailable when an edit was truncated at capture, or when its
content is binary or minified. Its line counts are then unknown, and Orchestra
never shows them as `+0 −0`:

* In the conversation, the edit's line says **truncated** or **binary** in
  place of counts.
* In the Changes tab, a file whose edits all have unknown lines shows no counts
  and says **truncated** or **binary**, in its row and in the file tree. A file
  that mixes counted and unknown edits shows its counts and how many edits
  were truncated.
* The session total says what it leaves out, for example
  `12 files changed +340 −58, not counting 3 truncated edits`, or
  `4 files changed, line counts unknown` when no edit could be counted.

A failed edit is different: its lines are known (none landed), so it is shown
as failed and left out of the counts.

In a large session the Changes tab first loads every file's counts, then each
file's diffs when you open it. A single edit too large to send to the browser
says so in place of its diff, and its lines are still counted.


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