jdd is a CLI for recording and navigating diff-over-time changes to a JSON object โ a JSON time machine.
jdd is a TUI for exploring changes to a JSON object over time. When find yourself tracking down distributed system changes, debugging configuration drift, or investigating incident root causes, jdd can help you see what changed, when it changed, and uncovery why it changed:
- History of a JSON object (via recording, streaming, or pre-recorded history)
- Navigate forward and backward in time
- View diffs between each point in time
- Inspect object content at any point in time
- Filter changes by object content
- Jump to line number / change index
brew install hcgatewood/tap/jdd# Place jdd into PATH and make executable, something like...
curl -fsSL https://raw.githubusercontent.com/hcgatewood/jdd/main/jdd -o /usr/local/bin/jdd
chmod +x /usr/local/bin/jdd
# ...and then install dependenciesjdd history.jsonl# Poll in-place
jdd --poll "cat obj.json"
# Watch in-place
jdd --watch obj.json
# Stream
kubectl get pod YOUR_POD --watch -o json | jdd# Poll in-place + record changes
jdd --poll "cat obj.json" --save history.jsonl
# Watch in-place + record changes
jdd --watch obj.json --save history.jsonl
# Stream + record changes
kubectl get pod YOUR_POD --watch -o json | jdd --save history.jsonl# Browse history with multiple files as successive versions
jdd v1.json v2.json v3.json# Tail an ongoing recording
jdd -f history.jsonl
# Sponge a history/stream before browsing
cat history.jsonl | jdd --no-follow# Inspect an object via JSON paths (similar to jnv, jid)
jdd obj.json Subcommands: dive (alias: hist) is the JSON-over-time navigator, surf (alias: insp) is the single-JSON inspector.
Navigate successive versions of a JSON object.
Usage: jdd [COMMAND] [FILE...] [OPTIONS]
Args:
COMMAND The jdd command to run (dive, surf). If omitted, guessed from FILE extension and options.
FILE Input file(s). If omitted, reads from stdin. If multiple files, treat as successive versions.
Commands:
(no command) Guess command from FILE extension
dive|hist Navigate successive versions of a JSON object, via streaming or stored JSONL file.
surf|insp Explore a single JSON object via interactive query preview.
help Show this help message.
Options:
--info Show more info, like the file being processed.
Dive options:
--save SAVE_FILE Record history: specify SAVE_FILE to save observed history of changes (default: temporary file; recommendation: .jsonl extension).
--watch COMMAND Watch mode: watch FILE for in-place changes to get new JSON object versions, appending to browsed history. (Alias: -w)
--poll COMMAND Poll mode: run COMMAND periodically to get new JSON object versions, appending to browsed history. (Alias: -p)
--interval N Poll mode interval in seconds between COMMAND executions (default: 5). (Alias: --int, -i)
--follow Follow: keep reading new entries as they are appended to FILE (default if no FILE is given). (Alias: -f)
--no-follow Sponge: disable follow mode. (Alias: --sponge)
--all Disable uniqueness filter: include all consecutive entries, even if they're identical (if using FILE and --bare, also prevents creating an intermediate file).
--no-preprocess Skip preprocessing: don't preprocess each entry into a single line (configure preprocessor via JDD_PREPROCESSOR). (Alias: --bare)
--tag OBJECT_PATH Add a tag: specify JSON path to use as tag for each entry.
Dive keybindings:
Ctrl-/ Help (this message -- q to quit).
Ctrl-N/Down Down.
Ctrl-P/Up Up.
Ctrl-J/Ctrl-D Page down.
Ctrl-K/Ctrl-U Page up.
Ctrl-L Preview page down.
Ctrl-H Preview page up.
Ctrl-F Jump to first entry.
Ctrl-G Jump to last entry.
Ctrl-V Jump to previous match.
Ctrl-B Jump to next match.
Ctrl-T Jump to best match.
Ctrl-R Toggle raw view.
Ctrl-W Clear query.
Ctrl-Y Copy current JSON entry to clipboard.
Ctrl-O Output current JSON entry to stdout and exit.
Tab Toggle 'goto' mode for jump to line number.
Enter Open in fx for further inspection.
Environment variables to customize behavior; generally they can be set to the name of an installed tool or a command string.
JDD_DIFFERdiff engine: jsondiffpatch (default), jd, json-diff, jsondiff, gojsondiff, difftasticJDD_INSPECTORsingle-object inspector: fx (default), jless, jdd surf, jnv, jidJDD_PREVIEWERpreview engine: jq (default:jq --color-output .), jaqJDD_PREPROCESSORoptional preprocessor for each item: jq (default:jq --sort-keys --compact-output --unbuffered .), jaq, dasel, jjJDD_COPIERclipboard copier: pbcopy (default), xclip, etc.JDD_SHOW_FILEshow file name in fzf header (default: unset)JDD_NO_HELPdon't show help keybinding in dive (default: unset)JDD_DEBUGenable debug logging (default: unset)- Additional tools: fzf, gron, mlr
I mainly use jdd to track changes to Kubernetes objects.
kubectl get pod MY_POD --watch -o json | jdd# kis opens jdd for downloaded K8s Insights data.
#
# Usage: kis insights.csv
function kis {
cat "${1:-/dev/stdin}" \
| mlr --icsv --ojsonl + put '$* = json_parse($UpdatedObject)' \
| jq --sort-keys --compact-output '
select(.kind != "Event")
| del(.metadata.resourceVersion)
| del(.status.conditions?[]?.lastTransitionTime)
| del(.status.conditions?[]?.lastUpdateTime)
| del(.status.placementStatuses?[]?.conditions?[]?.lastTransitionTime)
| del(.status.placementStatuses?[]?.conditions?[]?.lastUpdateTime)
' \
| jdd --tag '.metadata.generation' --sponge
}