Semantic diff for JSON, YAML, TOML, and NDJSON: a structured, agent-friendly change-list instead of line noise.
Project description
dotdiff
Semantic diff for JSON, YAML, TOML, and NDJSON. Compares two documents
structurally (not line by line) and prints a path-addressed change list
instead of textual noise. The sibling of dotpick:
dotpick extracts fields, dotdiff tells you what changed.
Install
cargo install dotdiff
Usage
dotdiff old.json new.json # text on a TTY, JSON when piped
dotdiff config.yaml config.json # cross-format works
cat new.json | dotdiff old.json - # `-` reads stdin
$ dotdiff old.json new.yaml
~ user.plan "free" -> "pro"
- user.trialEnds "2026-07-01"
+ user.seats 5
~ items[0].qty 1 -> 3
Output is the ~/+/- change list on a TTY, and structured JSON when piped:
$ dotdiff old.json new.json | jq .
{"identical": false, "changes": [
{"op": "changed", "path": "user.plan", "old": "free", "new": "pro"}
]}
Paths use dotpick's dotpath vocabulary
(user.plan, items[2].qty, ["quoted key"]), so you can feed a changed path
straight back into dotpick to inspect it.
Matching list items by key
By default arrays compare by position, so reordering a list reports everything
after the move as changed. Pass --array-key <field> to match objects in a list
by an identity field instead - order-independent, and far less noise:
# Without: a reordered list looks like 4 changes.
# With --array-key id: just the one real change.
$ dotdiff old.json new.json --array-key id
~ items[id=1].qty 1 -> 3
Formats
JSON, YAML, TOML, and NDJSON are detected per file (by extension, then content);
force both sides with --format. NDJSON is compared as an array of records, so
--array-key matches records across two streams. Everything is loaded into one
model, which is why cross-format diffing works.
Exit codes
| code | meaning |
|---|---|
0 |
identical |
1 |
differences found (the report is on stdout - not an error) |
2 |
an input could not be read or parsed |
3 |
usage error |
Exit 1 is a data state, not a failure (the diff/grep convention), so
dotdiff is scriptable as a gate: dotdiff a.json b.json && echo unchanged.
For agents (clispec)
dotdiff follows The CLI Spec: structured output on
stdout, structured error envelopes on the last line of stderr, a schema
subcommand whose output validates against clispec.dev/schema/v0.2.json
(checked by the test suite), and the exit-1-on-differences contract declared as
an outcome. It is read-only (mutating: false).
dotdiff schema
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dotdiff-0.1.0.tar.gz.
File metadata
- Download URL: dotdiff-0.1.0.tar.gz
- Upload date:
- Size: 29.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
98d728bf5e56ca069bc71552b4db4911b20fc581307f42ef221b3a34669aa3b9
|
|
| MD5 |
7db9736c99f35a57612abc2ae868b8cd
|
|
| BLAKE2b-256 |
3a18f33ae68da39804eca822a6c8f917d66850a78b00092dbd792a1d3eeb329b
|
File details
Details for the file dotdiff-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: dotdiff-0.1.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 649.6 kB
- Tags: Python 3, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8870a7f55f15941c708aef2a6e2af63de646d301e2a7ac4744e7378d7f3f2202
|
|
| MD5 |
69d245698f7f2845dd0a3597a68c1967
|
|
| BLAKE2b-256 |
15546acddc49708a3ea56002081dd2bd3cdb12cb76d20d12a9665ac1aba1f047
|
File details
Details for the file dotdiff-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: dotdiff-0.1.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 605.3 kB
- Tags: Python 3, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aee487655c31f94ec31f2f7397c1752a13573f72af112a65d967a17ab4cb1dbd
|
|
| MD5 |
a69f66ff855e4f6d7720c2c850dba478
|
|
| BLAKE2b-256 |
66e15fc7ffc01cd1fa1aa23eca957a8210dd82fb8f2e5cbb2e3a106769ce490e
|
File details
Details for the file dotdiff-0.1.0-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: dotdiff-0.1.0-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 588.2 kB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8bf5b4d3679f898595180fdfdb9c66b559f51b530420dc57560f08cfc759388b
|
|
| MD5 |
5fcb3c086e33ce3f54cc3fa520299fb7
|
|
| BLAKE2b-256 |
d868db768e809fb411bf65883cecec4b4a0585e7919e358b4db4af6525bd867e
|
File details
Details for the file dotdiff-0.1.0-py3-none-macosx_10_12_x86_64.whl.
File metadata
- Download URL: dotdiff-0.1.0-py3-none-macosx_10_12_x86_64.whl
- Upload date:
- Size: 630.3 kB
- Tags: Python 3, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ae2e80eb8859e0b3a60268e0843af0f34880b44b37a886fa5f55224f051b201e
|
|
| MD5 |
8cfa254d83949760ca5e074244906bfb
|
|
| BLAKE2b-256 |
b70ec8d7684bd529524c8adaaebed92b4af6bce109d71b5ed16816cab81710ba
|