---
title: "Comparing Versions"
description: "A bounded line diff between two captures that keeps provenance and never overstates an absence."
canonical_url: "https://archives.agntn.dev/guide/diff"
---
# Comparing Versions

> A bounded line diff between two captures that keeps provenance and never overstates an absence.

## The call

```ts
import { createArchive, diffArchivedContent, providers } from "@agntn/archives";

const archive = createArchive(providers.wayback());
const before = await archive.getContent("https://example.com", { timestamp: "2024" });
const after = await archive.getContent("https://example.com", { timestamp: "2026" });

const visible = diffArchivedContent(before, after);
const source = diffArchivedContent(before, after, { format: "raw" });
```

`diffArchivedContent` works on two captures already in memory. It does not fetch. Read both bodies first, then compare; the [Timeline](https://archives.agntn.dev/timeline) runs this on any two captures you tick.

## What it refuses

The helper throws rather than guess when:

- the captures come from different providers, or from Memento but different underlying archive hosts;
- the original URLs differ;
- either body is not text;
- `after` is not later than `before`.

Replay engines rewrite links, inject banners and normalise markup differently. Comparing a Wayback body with an Arquivo.pt body would show those differences as if the site had changed. One provider, one URL, chronological order: those are the conditions under which a diff means something.

## Options

<table>
<thead>
  <tr>
    <th>
      Option
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Meaning
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        format
      </code>
    </td>
    
    <td>
      <code>
        "text"
      </code>
    </td>
    
    <td>
      Compare visible text, or the decoded markup with <code>
        "raw"
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        context
      </code>
    </td>
    
    <td>
      3
    </td>
    
    <td>
      Unchanged lines kept around each hunk
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        timeout
      </code>
    </td>
    
    <td>
      1 000 ms
    </td>
    
    <td>
      Elapsed budget for the line diff
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        maxEditLength
      </code>
    </td>
    
    <td>
      10 000
    </td>
    
    <td>
      Edit distance ceiling before the diff gives up
    </td>
  </tr>
</tbody>
</table>

The two bounds exist because a diff between two large, unrelated bodies is quadratic. Hitting either throws; a caller that wants an answer anyway can raise them.

## What comes back

```ts
interface ArchivedContentDiff {
  before: ArchivedContentSummary; // url, timestamp, snapshot, mime, bytes, truncated, provider, archive?, selection?
  after: ArchivedContentSummary;
  patch: string; // unified diff
  additions: number;
  deletions: number;
  identical: boolean;
  partial: boolean; // either body was truncated before comparison
  format: "text" | "raw";
  context: number;
}
```

The summaries keep the exact capture dates and snapshot URLs, because the dates you asked for and the dates the archive resolved to are rarely the same. Asked for 2020 and got 2023? Then that summary carries `selection: "after"`, and `archives_diff` prints `(later than requested)` beside the date. A diff like that starts later than you think. `partial: true` means a body hit `maxBytes`; absence beyond that prefix is not proved, and a report built on the diff should say so.

## Over MCP

`archives_diff` does the fetching and the comparing in one call. With `provider=all` it tries providers in order until one can serve both captures; it never combines versions from two archives. The result text carries the resolved dates, both snapshot URLs, a SHA-256 of the complete patch, and a `continue` line for the next slice of a long patch. [Agents](https://archives.agntn.dev/guide/agents) covers the slice contract.


## Sitemap

See the full [sitemap](https://archives.agntn.dev/sitemap.md) for all pages.
