---
title: "Getting started with OneDiff"
url: https://recursiveai.org/onediff/docs/getting-started/
description: "Install OneDiff 1.0.1 for .NET 10, diff and merge text, compare two documents into a verified change list, and write a redline as HTML, JSON or PDF. Pure…"
version: "1.0.1"
---

# Getting started with OneDiff

Install OneDiff 1.0.1 for .NET 10, diff and merge text, compare two documents into a verified change list, and write a redline as HTML, JSON or PDF. Pure C#, with no native code and no network access.

## Install

The packages target `net10.0`, so you need the .NET 10 SDK.

```shell
dotnet new console -o OneDiffStart
cd OneDiffStart
dotnet add package RecursiveAI.OneDiff --version 1.0.1
```

Five packages are on NuGet at 1.0.1, all on one version:

- **`RecursiveAI.OneDiff`**: the text core. Diff, patches and three-way merge, with no dependency beyond the .NET base class library.
- **`RecursiveAI.OneDiff.Documents`**: the comparison engine, HTML redlines and the JSON change list. It brings in the core and `RecursiveAI.OneFont`.
- **`RecursiveAI.OneDiff.Pdf`**: digital PDFs in; changes marked on the original pages, or a rendered redline PDF. It brings in `.Documents`, `RecursiveAI.OnePdf` and `RecursiveAI.OneRender.Pdf`.
- **`RecursiveAI.OneDiff.Ocr`**: scanned PDFs and images, read by a local OCR engine (`RecursiveAI.OneOcr`).
- **`RecursiveAI.OneDiff.Tool`**: the `onediff` command-line tool.

Word documents are not part of 1.0. In the README’s words: “Coming in later releases: Word documents in and tracked-changes DOCX out (`RecursiveAI.OneDiff.Word`, in this repository and not in the first release), spreadsheets, slides, and the OneNLP value recognizer (`RecursiveAI.OneDiff.Nlp`).” Until then an Office file is refused:

```text
NotSupportedException: No document source is registered for this input, which looks like an Office Open XML or other zip-based document. Support for Office documents (DOCX, XLSX and PPTX) is coming in a 1.x release. Meanwhile, export the documents to PDF and compare the PDFs (with RecursiveAI.OneDiff.Pdf).
```

## Diff, patch and merge text

Put this in `Program.cs` and run `dotnet run`:

```csharp
using OneDiff;
using OneDiff.Merge;

string oldText = "Deliver within 30 days.\nPay within 45 days.\n";
string newText = "Deliver within 21 days.\nPay within 45 days.\n";

// The words that changed, as Markdown
Console.WriteLine(Diff.ToMarkdownInline(Diff.Words(oldText, newText)));

// A unified patch, and applying it
string patch = Diff.Unified(oldText, newText, "a/terms.txt", "b/terms.txt");
Console.Write(patch);
Console.WriteLine($"applied: {Diff.ApplyUnified(oldText, patch).Text == newText}");

// A three-way merge: edits to different lines merge
string baseText = "one\ntwo\nthree\nfour\n";
string ours     = "ONE\ntwo\nthree\nfour\n";
string theirs   = "one\ntwo\nthree\nFOUR\n";
TextMerge merged = Diff.Merge(baseText, ours, theirs);
Console.Write(merged.Text);
Console.WriteLine($"conflicts: {merged.HasConflicts}");
```

```text
Deliver within <del>30</del><ins>21</ins> days.
Pay within 45 days.

--- a/terms.txt
+++ b/terms.txt
@@ -1,2 +1,2 @@
-Deliver within 30 days.
+Deliver within 21 days.
 Pay within 45 days.
applied: True
ONE
two
three
FOUR
conflicts: False
```

Edits to the same or neighboring lines are a conflict, written with conflict markers in git’s `merge`, `diff3` or `zdiff3` style. See [Three-way merge](https://recursiveai.org/onediff/docs/merge/) and [Patches](https://recursiveai.org/onediff/docs/patches/).

## Compare two documents

Document comparison is in `.Documents`:

```shell
dotnet add package RecursiveAI.OneDiff.Documents --version 1.0.1
```

Save two versions of a short contract as `v1.txt` and `v2.txt`:

```text
1. Supply. The Supplier shall deliver the goods within 30 days of each order.

2. Payment. The Customer shall pay each invoice within 45 days of its date.
```

In `v2.txt`, change `30 days` to `21 days`. Then:

```csharp
using OneDiff.Documents;
using OneDiff.Documents.Serialization;

Comparison cmp = Comparison.Of("v1.txt", "v2.txt");

foreach (Change c in cmp.Changes.Where(c => c.IsSubstantive))
{
    Console.WriteLine($"{c.Kind}: {c.Old.Text} -> {c.New.Text}");
    if (c.OldValue is { } was && c.NewValue is { } now)
        Console.WriteLine($"  {c.Type}: {was.Canonical} -> {now.Canonical}");
}
Console.WriteLine($"complete: {cmp.Verification.Passed}");

// The output form follows the extension
cmp.SaveAs("redline.html");
cmp.SaveAs("changes.json");

Comparison again = ComparisonJson.Read(File.ReadAllBytes("changes.json"));
Console.WriteLine($"read back: {again.Changes.Length} changes, complete: {again.Verification.Passed}");
```

```text
Replace: 30 days -> 21 days
  Duration: 30 d -> 21 d
complete: True
read back: 1 changes, complete: True
```

The change is typed: a duration, with both values resolved. `complete` is the completeness check every comparison runs: the old document plus the changes gives the new one, and the new one minus the changes gives the old. Reading the JSON back runs the check again, so an edited file fails it. See [The compare model](https://recursiveai.org/onediff/docs/compare-model/) and [Change semantics](https://recursiveai.org/onediff/docs/semantics/).

## Redline PDFs

PDF input and output are in `.Pdf`:

```shell
dotnet add package RecursiveAI.OneDiff.Pdf --version 1.0.1
```

With two versions of a digital PDF, `v1.pdf` and `v2.pdf` (here, the two text files above saved as PDF):

```csharp
using OneDiff.Documents;
using OneDiff.Pdf;

PdfRedline.Register();   // once at startup

// Highlights on v2.pdf's own pages, with the old text in the pop-ups
Redline.Create("v1.pdf", "v2.pdf", "markup.pdf");

// A rendered redline: a new, tagged PDF laid out from the comparison
Comparison cmp = Comparison.Of("v1.pdf", "v2.pdf");
cmp.SaveAs("redline.pdf", PdfRedline.Rendered);
cmp.SaveAs("side-by-side.html", RedlineForm.HtmlSideBySide);

foreach (Change c in cmp.Changes.Where(c => c.IsSubstantive))
    Console.WriteLine($"{c.Kind}: {c.Old.Text} -> {c.New.Text}");
```

```text
Replace: 30 days -> 21 days
```

`markup.pdf` is `v2.pdf` with a highlight and its pop-up note; the page content is untouched. `redline.pdf` is a two-page tagged PDF: a summary of the changes by type, then the text with `30` struck through and `21` inserted. Every look the writers have is in [Samples and redline looks](https://recursiveai.org/onediff/docs/samples/).

A PDF with no text layer is refused rather than compared as empty:

```text
InvalidDataException: This PDF has no text layer, so it is probably a scan. Reference RecursiveAI.OneDiff.Ocr and call OcrRedline.Register() to read it by OCR.
```

## Scans

Scanned PDFs and images (PNG, JPEG, TIFF) are in `.Ocr`, which reads them with a local OCR engine:

```shell
dotnet add package RecursiveAI.OneDiff.Ocr --version 1.0.1
```

```csharp
using OneDiff.Documents;
using OneDiff.Ocr;

OcrRedline.Register();   // once at startup; reads scans and digital PDFs

Redline.Create("scan-v1.png", "scan-v2.png", "scan-markup.pdf");

foreach (Change c in Comparison.Of("scan-v1.png", "scan-v2.png").Changes)
    Console.WriteLine($"{c.Kind}: {c.Old.Text} -> {c.New.Text}, " +
                      $"confidence {c.OcrConfidence:0.00}, possible OCR error: {c.PossibleOcrError}");
```

```text
Replace: 30 days -> 21 days, confidence 0.98, possible OCR error: False
```

A change whose words were read with a confidence below 0.95 (the default threshold) is flagged as a possible recognition error; the flag never hides a change. Scans are Latin-script only, and in the README’s words, “In browser WebAssembly, reading scans with `RecursiveAI.OneDiff.Ocr` fails with a `TypeLoadException` from the image library it uses (OneImage).” See [Scans and images](https://recursiveai.org/onediff/docs/ocr/).

## The onediff tool

```shell
dotnet tool install --global RecursiveAI.OneDiff.Tool --version 1.0.1
onediff diff v1.txt v2.txt
onediff compare v1.pdf v2.pdf -o markup.pdf
```

```text
--- v1.txt
+++ v2.txt
@@ -1,3 +1,3 @@
-1. Supply. The Supplier shall deliver the goods within 30 days of each order.
+1. Supply. The Supplier shall deliver the goods within 21 days of each order.
 
 2. Payment. The Customer shall pay each invoice within 45 days of its date.
```

`onediff diff` exits 1 when the texts differ, as `diff` does. The other commands are `patch`, `merge`, `combine` (reviewers’ copies of one original) and `chain` (a series of versions); `onediff <command> --help` lists each one’s options.

## Next

- [Overview](https://recursiveai.org/onediff/docs/overview/): what OneDiff is, the packages and the happy path.
- [Migrating from DiffPlex](https://recursiveai.org/onediff/docs/migrating-from-diffplex/) and [from WmlComparer](https://recursiveai.org/onediff/docs/migrating-from-wmlcomparer/).
- [Results](https://recursiveai.org/onediff/docs/results/): every measured result, including the rows that lose.
