A fast, standalone CLI tool for side-by-side visual PDF diffing, designed primarily to inspect and verify changes between a base resume/CV and an AI-tailored version while preserving 100% vector fidelity and text searchability. It is used by GitEmployed to inspect resume diffs before submission.
pdf-vdiff compares two PDF documents (such as your canonical base resume/CV and an AI-customized version for a job application) and generates a single side-by-side landscape PDF with IntelliJ/GitHub-style visual diff highlighting. It allows you to immediately spot reworded bullet points, added keywords, and omitted sections before submitting your application.
- 📄 100% Vector Fidelity: Embeds native PDF page objects directly—no lossy rasterization or blurry text.
- 🔍 Full Text Searchability: Diff output maintains searchable and selectable text layers.
- 🧠 Intelligent Hierarchical Diffing: Extracts text tokens with exact bounding boxes via PDFium, clusters lines and columns spatially, and computes Myers sequence diffs at word, line, or character granularity.
- 🎨 Multiple Color Themes: Choose between
intellij(default),github,classic, andhigh-contrastpalettes. - ⚡ Zero-Friction CLI: Automatically opens output in your system default PDF viewer (
--open), supports custom gutter widths, optional header banners, and structured exit codes. - 🛡️ Hardened Ingestion: Pre-flight dimension and page count validation, with PDFium V8 script execution explicitly disabled for security.
An example comparison of a base resume against a tailored resume is provided in the example/ directory:
example/resume_base.pdf— Base documentexample/resume_tailored.pdf— Modified / tailored documentexample/resume_diff.pdf— Generated side-by-side visual diff
To generate the diff for this example:
pdf-vdiff example/resume_base.pdf example/resume_tailored.pdf -o example/resume_diff.pdfTo automatically open the diff in your system viewer after generation:
pdf-vdiff example/resume_base.pdf example/resume_tailored.pdf -o example/resume_diff.pdf --openPre-built, self-contained binary archives bundled with Google's PDFium dynamic library, shell completions, and man pages are available on the GitHub Releases page for:
- macOS (Apple Silicon
aarch64& Intelx86_64) - Linux (x86_64 & AArch64 glibc)
- Windows (x86_64)
These archives require zero external dependencies or compiler toolchains: extract the archive and run ./pdf-vdiff directly (or place pdf-vdiff and its companion library libpdfium / pdfium.dll together in the same directory on your $PATH, such as ~/.local/bin). On macOS, if downloaded via a web browser, clear the quarantine attribute if prompted: xattr -d com.apple.quarantine pdf-vdiff libpdfium.dylib.
If you have cargo-binstall installed, you can fetch and install pre-compiled binaries in seconds without compiling from source:
cargo binstall pdf-vdiffNote
cargo-binstall installs only the executable binary into $CARGO_HOME/bin/. Like cargo install, running the binary requires Google's PDFium dynamic library on your system search path (e.g. brew install bblanchon/pdfium/pdfium-binaries on macOS) or via PDFIUM_LIB_PATH. For a completely self-contained installation with zero system dependencies, use the pre-compiled binary archives above or Nix Flakes below.
cargo install pdf-vdiffNote
Compiling via cargo install or building from source links to Google's PDFium dynamic library at runtime. Ensure libpdfium.dylib (macOS), libpdfium.so (Linux), or pdfium.dll (Windows) is available on your system search path (such as /opt/homebrew/lib or /usr/local/lib), or configure PDFIUM_LIB_PATH or PDFIUM_LIB_DIR. On macOS with Homebrew:
brew install bblanchon/pdfium/pdfium-binariesFor an out-of-the-box setup with zero external library configuration, use the pre-compiled binary packages or Nix Flakes below.
Add pdf-vdiff to your Cargo.toml:
cargo add pdf-vdiffOr manually:
[dependencies]
pdf-vdiff = "0.1.6" # x-release-please-versionProgrammatic usage in Rust:
use pdf_vdiff::{diff_documents, DiffGranularity, PageText};
// Diff page tokens with configurable granularity (Word, Line, Character)
let diff_result = diff_documents(&base_pages, &tailored_pages, DiffGranularity::Word);
println!(
"Detected {} difference(s) across {} page(s)",
diff_result.total_differences,
diff_result.pages.len()
);pdf-vdiff provides full Nix Flake support (requires Nix 2.4+ with flakes and nix-command enabled). You can run it instantly without manual installation or dependencies:
# Run directly from GitHub
nix run github:menil/pdf-vdiff -- base.pdf tailored.pdf --open
# Install to your global Nix profile ($PATH)
nix profile install github:menil/pdf-vdiffAdd pdf-vdiff as an input to include it in your developer shells or packages:
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
pdf-vdiff.url = "github:menil/pdf-vdiff";
pdf-vdiff.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { self, nixpkgs, pdf-vdiff, ... }:
let
system = "aarch64-darwin"; # or "x86_64-linux", etc.
pkgs = nixpkgs.legacyPackages.${system};
in {
devShells.${system}.default = pkgs.mkShell {
packages = [
pdf-vdiff.packages.${system}.default
];
};
};
}If you are developing inside this repository, enter the pre-configured developer shell:
nix-shell # or nix develop# Clone the repository
git clone https://github.com/menil/pdf-vdiff.git
cd pdf-vdiff
# Build release binary
cargo build --release
# Binary will be available at ./target/release/pdf-vdiffpdf-vdiff [OPTIONS] <BASE_PDF> <TAILORED_PDF>| Option / Flag | Description | Default |
|---|---|---|
<BASE_PDF> |
Path to the original / base PDF document | (Required) |
<TAILORED_PDF> |
Path to the modified / tailored PDF document | (Required) |
-o, --output <PATH> |
Target output PDF file path | <base_stem>_vs_<tailored_stem>_diff.pdf |
-f, --force |
Overwrite destination output file if it already exists | false |
--open |
Automatically open the generated diff in default PDF viewer | false |
--theme <THEME> |
Color palette (intellij, github, classic, high-contrast) |
intellij |
--granularity <MODE> |
Diff granularity (word, line, character) |
word |
--gutter-width <PT> |
Spacing in points between left and right pages | 24.0 |
--no-header |
Suppress the top header/metadata banner | false |
--max-pages <NUM> |
Maximum page count threshold to prevent unbounded processing | 250 |
-v, --verbose |
Enable verbose structural logging | false |
--generate-completions <SHELL> |
Generate shell completions (bash, zsh, fish, elvish, powershell) |
|
--generate-man |
Generate Section 1 roff man page to stdout | false |
-h, --help |
Print help information | |
-V, --version |
Print version information |
# Compare two documents and open immediately in system default PDF viewer
pdf-vdiff original.pdf modified.pdf --open
# Use GitHub color theme with line-level diff granularity
pdf-vdiff original.pdf modified.pdf --theme github --granularity line
# Custom output destination and overwrite if target exists
pdf-vdiff base.pdf tailored.pdf -o ./output/diff.pdf --force
# Remove the top metadata banner and adjust gutter width
pdf-vdiff v1.pdf v2.pdf --no-header --gutter-width 32.0Pre-built shell completions and Unix man pages are maintained in completions/ and man/:
Generate or source completions on the fly for your active shell:
# Bash (add to ~/.bashrc)
eval "$(pdf-vdiff --generate-completions bash)"
# Zsh (add to ~/.zshrc)
eval "$(pdf-vdiff --generate-completions zsh)"
# Fish (add to ~/.config/fish/config.fish)
pdf-vdiff --generate-completions fish | source- Unix Man Page: Installed automatically with package managers (
man pdf-vdiff), or view directly:- macOS:
pdf-vdiff --generate-man | mandoc - Linux:
pdf-vdiff --generate-man | man -l - - Direct file:
man man/pdf-vdiff.1
- macOS:
- TLDR Cheatsheet: Available in
man/pdf-vdiff.tldr.md.
| Code | Status | Description |
|---|---|---|
0 |
Identical Documents | No differences detected. Generates diff PDF without highlights and exits 0. |
1 |
Differences Found | Differences detected. Generates diff PDF with highlights and exits 1. |
2 |
Execution Error | Fatal error (missing file, invalid permissions without --force, parse error). |
A Justfile task runner is included for common development workflows:
# List available recipes
just
# Run test suite
just test
# Check formatting and linting
just lint
# Run all validations (tests, linter, format check, coverage)
just validateFor comprehensive guidelines on Nix environment setup, Git hooks, Beads issue tracking, and AI ignore policies, see the Development Guide.
This project is licensed under the MIT License.