Compare anything. Understand everything. Break nothing.
A universal CLI tool that compares files, folders, configs, documents, APIs, and dependencies—then explains what changed and what could break.
Traditional diff tools show you what is different. what-changed tells you why it matters:
┌─────────────────────────────────────────────────────────────────────────────┐
│ Traditional Diff │ what-changed │
├───────────────────────────────┼─────────────────────────────────────────────┤
│ < host: localhost │ [X] BREAKING: database.host changed │
│ > host: prod-db.example.com │ │
│ │ Impact: Database connection points to prod │
│ │ Could break: Local dev environments │
│ │ Risk Score: 9/10 │
└─────────────────────────────────────────────────────────────────────────────┘
| Feature | Description |
|---|---|
| Smart Detection | Auto-identifies 25+ file formats |
| Semantic Diffing | Understands structure, not just text |
| Risk Scoring | Predicts what might break (0-10 scale) |
| OCR Support | Extracts text from scanned PDFs & images |
| Git Integration | Compare commits, branches, and tags |
| Interactive TUI | Explore changes in a terminal UI |
| CI/CD Ready | Exit codes for automation pipelines |
pip install what-changed# Full installation with all formats
pip install what-changed[all]
# Individual extras
pip install what-changed[pdf] # PDF support (PyMuPDF)
pip install what-changed[ocr] # OCR for scanned docs (Tesseract)
pip install what-changed[openapi] # OpenAPI/Swagger specs
pip install what-changed[excel] # Excel spreadsheets
pip install what-changed[image] # Image comparison
pip install what-changed[sql] # SQL schema analysisgit clone https://github.com/aayushadhikari7/what-changed
cd what-changed
pip install -e ".[all]"# Compare any two files
what-changed compare old.json new.json
# Compare directories
what-changed compare ./v1 ./v2
# Show only breaking changes
what-changed compare config.yaml config.prod.yaml --breaking-only
# Interactive graph view
what-changed compare api-v1.yaml api-v2.yaml --graph
# Visual stats dashboard
what-changed compare before/ after/ --stats
# Git integration
what-changed git HEAD~1..HEAD
what-changed git main..feature-branch| Format | Extensions | What's Analyzed |
|---|---|---|
| JSON | .json |
Keys, values, nested structures |
| YAML | .yaml, .yml |
Full YAML including anchors |
| TOML | .toml |
Sections, tables, arrays |
| INI | .ini, .cfg |
Sections and key-value pairs |
| ENV | .env, .env.* |
Environment variables |
| Format | Extensions | What's Analyzed |
|---|---|---|
.pdf |
Pages, text, TOC, metadata, OCR for scanned docs | |
| Markdown | .md |
Headings, links, code blocks, sections |
| Plain Text | .txt |
Line-by-line diff |
| Format | Extensions | What's Analyzed |
|---|---|---|
| OpenAPI 3.x | .yaml, .json |
Endpoints, schemas, parameters, responses |
| Swagger 2.0 | .yaml, .json |
Full spec comparison |
| Format | Extensions | What's Analyzed |
|---|---|---|
| CSV | .csv |
Schema, columns, rows, statistics |
| TSV | .tsv |
Tab-separated values |
| Excel | .xlsx, .xls |
Multiple sheets, cells |
| Format | Files | What's Analyzed |
|---|---|---|
| Dockerfile | Dockerfile |
Base image, instructions, ports, health checks |
| Docker Compose | compose.yaml |
Services, volumes, networks |
| SQL | .sql |
Tables, columns, indexes, constraints |
| Ecosystem | Files | What's Analyzed |
|---|---|---|
| Node.js | package.json |
Dependencies, scripts, versions |
| Python | requirements.txt, pyproject.toml |
Packages, version constraints |
| Ruby | Gemfile |
Gems, sources |
| Rust | Cargo.toml |
Crates, features |
| Go | go.mod |
Modules, versions |
| Format | Extensions | What's Analyzed |
|---|---|---|
| Images | .png, .jpg, .gif, .webp |
Dimensions, metadata, OCR text extraction |
| Archives | .zip, .tar, .tar.gz |
File listing, content changes |
what-changed compare config.old.json config.new.json┌─────────────────────────────────────────────────────────────────────────────┐
│ Configuration Comparison │
│ A: config.old.json │
│ B: config.new.json │
└─────────────────────────────────────────────────────────────────────────────┘
[X] 1 breaking [!] 2 risky [o] 3 safe
┌─────────── Changes ───────────┐
│ config │
│ ├── database (2 changes) │
│ │ ├── - host <str> │
│ │ │ localhost │
│ │ │ -> prod-db.com │
│ │ └── ~ port <int> │
│ │ 5432 -> 5433 │
│ └── + cache (3 changes) │
│ └── enabled = true │
└───────────────────────────────┘
what-changed compare api-v1.yaml api-v2.yaml --graphNavigate changes with keyboard shortcuts:
j/kor arrows: NavigateEnter: Expand/collapseb: Show breaking onlyq: Quit
what-changed compare before/ after/ --statsShows ASCII charts with change distribution, risk breakdown, and file type statistics.
what-changed compare config.json config.prod.json --jsonwhat-changed compare src/ dist/ --summaryCompare any git references directly:
# Compare with previous commit
what-changed git HEAD~1..HEAD
# Compare branches
what-changed git main..feature-branch
# Compare tags
what-changed git v1.0.0..v2.0.0
# Compare specific file across commits
what-changed git HEAD~5..HEAD -p src/config.json
# Show only breaking changes
what-changed git main..develop --breaking-onlyAutomatically extracts text from scanned PDF documents using Tesseract OCR:
what-changed compare scanned_v1.pdf scanned_v2.pdf┌─────────────────────────────────────────────────────────────────────────────┐
│ PDF Document Comparison │
│ A: scanned_v1.pdf (OCR detected) │
│ B: scanned_v2.pdf (OCR detected) │
└─────────────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────── page_1 ──────────────────────────────────┐
│ -Invoice #12345 │
│ +Invoice #12345 - REVISED │
│ -Total: $450 │
│ +Total: $550 │
└─────────────────────────────────────────────────────────────────────────────┘
Compare images and extract text changes:
what-changed compare screenshot_old.png screenshot_new.pngRequirements: Install Tesseract OCR for your platform.
Changes are scored 0-10 based on potential impact:
| Score | Level | Examples |
|---|---|---|
| 8-10 | BREAKING | Removed endpoints, deleted dependencies, schema type changes |
| 5-7 | RISKY | Major version bumps, config value changes, deprecated features |
| 0-4 | SAFE | Added optional fields, new dependencies, comment changes |
| Change Pattern | Score | Why |
|---|---|---|
| API endpoint removed | 10 | Clients will fail |
| Required field added | 9 | Existing data won't validate |
| Database host changed | 9 | Connection failures |
| Dependency removed | 9 | Runtime errors |
| Major version bump | 7 | Breaking API changes |
| Port number changed | 6 | Connection issues |
| New optional field | 2 | Backward compatible |
| Comment updated | 1 | No runtime impact |
Perfect for CI/CD pipelines:
| Code | Meaning | Action |
|---|---|---|
| 0 | All changes safe | Deploy freely |
| 1 | Risky changes found | Review recommended |
| 2 | Breaking changes found | Block deployment |
| 3 | Error occurred | Check logs |
# In CI/CD pipeline
what-changed compare staging.env production.env --breaking-only
if [ $? -eq 2 ]; then
echo "Breaking changes detected! Blocking deployment."
exit 1
fiwhat-changed compare [OPTIONS] SOURCE_A SOURCE_B
Arguments:
SOURCE_A First source (file, directory, or URL)
SOURCE_B Second source (file, directory, or URL)
Options:
-s, --summary Brief summary only
-b, --breaking-only Show only breaking changes
-j, --json Output as JSON
-v, --verbose Show rule matches and scores
--no-color Disable colors
--graph Interactive TUI graph view
--stats Visual statistics dashboard
--help Show help message
what-changed git [OPTIONS] REF_SPEC
Arguments:
REF_SPEC Git reference (e.g., HEAD~1..HEAD, main..feature)
Options:
-p, --path PATH Compare specific file only
-b, --breaking-only Show only breaking changes
--help Show help message
what-changed detect FILE
Detect and display the file type.
from what_changed import compare
# Simple comparison
result = compare("old.json", "new.json")
print(f"Breaking changes: {result.breaking_count}")
print(f"Risky changes: {result.risky_count}")
print(f"Safe changes: {result.safe_count}")
for change in result.breaking_changes:
print(f" - {change.path}: {change.summary}")from what_changed.normalize import create_default_registry
from what_changed.diff import SemanticDiff
from what_changed.graph import GraphBuilder
from what_changed.rules import create_default_engine
from what_changed.explain import Explainer
# Full pipeline
registry = create_default_registry()
obj_a = registry.normalize("config.old.json")
obj_b = registry.normalize("config.new.json")
differ = SemanticDiff()
diff_result = differ.diff(obj_a, obj_b)
builder = GraphBuilder()
graph = builder.build(diff_result)
engine = create_default_engine()
rule_results = engine.apply(graph)
explainer = Explainer()
for exp in explainer.explain_graph(graph, rule_results):
print(f"{exp.risk_level.name}: {exp.change_summary}")what-changed handles edge cases gracefully:
| Scenario | Behavior |
|---|---|
| Password-protected PDF | Clear error message |
| Malformed JSON/YAML | Parse error with line number |
| Empty files | Shows structure changes |
| Binary files | Falls back to size comparison |
| Missing files | Clear "not found" error |
| Identical files | "No changes detected" |
| 100+ page PDFs | Paginated output (20 items max) |
| Unicode/Emoji content | Full UTF-8 support |
| Files without extension | Attempts content-based detection |
what-changed/
├── cli/ # Command-line interface (Typer)
├── detect/ # File type detection
├── normalize/ # Format-specific parsers
│ ├── config.py # JSON, YAML, TOML, INI, ENV
│ ├── pdf.py # PDF with OCR support
│ ├── openapi.py # OpenAPI/Swagger
│ ├── data.py # CSV, Excel
│ ├── docker.py # Dockerfile, Compose
│ ├── dependencies.py # package.json, requirements.txt
│ ├── image.py # Images with OCR
│ ├── sql.py # SQL schemas
│ └── archive.py # ZIP, TAR
├── diff/ # Semantic diff engine
├── graph/ # Change graph construction
├── rules/ # Risk scoring heuristics
├── explain/ # Human-readable explanations
├── output/ # Renderers (terminal, JSON)
│ └── formats/ # Format-specific renderers
├── tui/ # Interactive terminal UI
└── git/ # Git integration
- Clarity over cleverness — Readable, maintainable code
- Extensible by design — Easy to add formats and rules
- Deterministic results — No ML/AI, fully reproducible
- Offline-first — No external API calls
- Cross-platform — Windows, macOS, Linux
# Clone and install
git clone https://github.com/aayushadhikari7/what-changed
cd what-changed
pip install -e ".[dev,all]"
# Run tests
pytest
# Type checking
mypy what_changed
# Linting
ruff check what_changedMIT License — see LICENSE for details.
Built with care for developers who hate surprises in production.
Demo recorded with termgif
