Skip to main content

ZeroDiff

ci

Prove your rewrite behaves like the original — before you trust it.

AI agents can rewrite and migrate legacy code cheaply. The blocker is trust: the original has years of undocumented behavior baked in, and nobody wants to deploy a rewrite on an agent's word. ZeroDiff closes that gap with recorded evidence:

  1. Record — run the legacy code under real or driver traffic and capture every call at chosen function boundaries: inputs, outputs, and exceptions.
  2. Replay — run the same recorded inputs against the rewritten code (written by any agent, or any human — ZeroDiff doesn't care).
  3. Report — get every behavioral divergence as a machine-readable report with actionable hints an agent can fix in a loop, plus a human-readable summary. Exit codes make it a CI gate with zero glue.
$ zerodiff record -o traces -- python driver.py
  recorded 1,204 calls across 3 boundaries -> traces/

$ zerodiff replay -t traces --map "billing:billing_v2"
  replayed 1,204 recorded behaviors
  matched  1,198   diverged 6   -> zerodiff-report.json, zerodiff-report.md
  exit code 1

Quick start

pip install "zerodiff @ git+https://github.com/Hoos92/zerodiff"
# (or, from a checkout: pip install -e .)
zerodiff demo    # 30-second guided example: record a legacy function,
                # catch the silent change a rewrite introduced
zerodiff init    # scaffold zerodiff.toml + .gitignore for your project

Examples below are written for bash; in PowerShell, join the \-continued lines into a single line (or swap \ for a backtick).

Gate it in your existing test suite with one line:

from zerodiff.testing import verify_traces

def test_rewrite_matches_recorded_behavior():
    verify_traces()   # raises AssertionError with a divergence digest

CI systems that speak JUnit get first-class output too: zerodiff replay -t traces --junit-out zerodiff-junit.xml.

Record with zero source edits--include auto-instruments every public function of matching modules as they load:

zerodiff record --include billing -o traces -- python run_legacy_scenarios.py
zerodiff replay -t traces --map "billing:billing_v2"

Or mark boundaries explicitly when you want tighter control:

import zerodiff

@zerodiff.record                      # option A: decorate
def calc_price(order): ...

zerodiff.wrap("billing.pricing", "calc_price")   # option B: wrap from outside

Replaying an untrusted rewrite? --isolate runs every call in a worker subprocess: a rewrite that crashes the interpreter, calls os._exit, or hangs becomes a reported process_crash divergence instead of taking the harness down:

zerodiff replay -t traces --isolate --timeout 10

Agent-native workflows

ZeroDiff is vendor-neutral: it verifies code, not agents. Two doors into the same loop — bring your own agent CLI, or just bring an API key:

# door 1: BYO agent (Claude Code, Codex, Cursor CLI, your own script)
zerodiff migrate ... --agent "claude -p --permission-mode acceptEdits"

# door 2: built-in agent -- you pick the LLM, ZeroDiff does the rest
zerodiff migrate ... --llm anthropic:claude-sonnet-5      # ANTHROPIC_API_KEY
zerodiff migrate ... --llm openai:gpt-5                    # OPENAI_API_KEY
zerodiff migrate ... --llm openai-compatible:llama3.3 \
    --llm-base-url http://localhost:11434/v1              # Ollama/OpenRouter/vLLM

zerodiff llm-check --llm anthropic:claude-sonnet-5   # validate key+model in 2s
zerodiff insights    # mine your report + history for concrete next actions

# the upgrade safety net: prove a dependency bump changed nothing
zerodiff guard baseline --include yourpkg -- python driver.py
pip install -U somedependency
zerodiff guard check

The built-in agent is deliberately minimal and least-privilege: no shell, no tools, writes restricted to the mapped rewrite files, and its output still passes the quality gate and replay like anyone else's code. ZeroDiff itself still contains no model — the verifier stays deterministic.

# the whole verified migration in one command: record the legacy code,
# scaffold the rewrite, drive YOUR agent until every recorded behavior
# matches, finish with signed evidence
zerodiff migrate --include billing.pricing \
    --driver "python run_scenarios.py" \
    --map billing.pricing:pricing_v2 \
    --agent "claude -p --permission-mode acceptEdits" \
    --attest --key-file team.key

# unattended fix loop with any agent CLI
zerodiff loop -t traces --agent "claude -p --permission-mode acceptEdits"
zerodiff loop -t traces --agent "codex exec --full-auto {prompt_file}"

# MCP server: Claude Code / Codex / Copilot / Cursor call verification natively
claude mcp add zerodiff -- zerodiff mcp

There's also a GitHub Action that gates PRs on recorded behavior, and a Claude Code hook that blocks any edit which breaks it.

Agent-written code is additionally held to a built-in security/quality gate (docs/SAFE_CODING.md): the loop will not finish while the rewrite contains eval/exec, shell=True, interpolated SQL, hardcoded secrets, disabled TLS verification, or unsafe deserialization — behavioral fidelity alone is not enough. Standalone: zerodiff quality myfile.py.

Exit codes: 0 = every recorded behavior matched, 1 = divergences found, 2 = harness error. zerodiff-report.json is designed to be fed straight back to a coding agent; zerodiff-report.md is for humans.

What ZeroDiff does and does not claim

ZeroDiff is deliberately honest about its guarantees:

  • It proves equivalence over the recorded behaviors only — never over all possible behaviors. A passing report says "matched N of N recorded behaviors", not "the systems are identical". Coverage is only as good as the traffic you record.
  • Side effects are not intercepted in v1. A recorded function that writes to a database or calls the network will really do so again during replay. Record and replay side-effecting code only against disposable environments.
  • Objects ZeroDiff can't fully serialize are compared by type + repr digest and flagged as weak comparisons in the report, so trust is never overstated.
  • Traces contain real runtime data, which may be sensitive. The default .gitignore excludes trace directories; redaction scrubbers are available.

See docs/ARCHITECTURE.md for the full design and limitation notes.

Handling noise (timestamps, floats, UUIDs)

Real code is noisy. Configure per-boundary scrubbers in zerodiff.toml so irrelevant differences don't drown real ones:

[map]
"billing.pricing" = "billing_v2.pricing"

[scrub]
float_tolerance = 1e-9
builtin = ["uuid", "timestamp"]        # scrub UUID/ISO-timestamp strings
redact_fields = ["password", "*.api_token"]   # never written to disk at all

[scrub.boundaries."billing.pricing.make_receipt"]
ignore_fields = ["generated_at", "trace_id"]

redact_fields is applied at record time — redacted values never reach the trace files, not merely the report.

Demos

  • examples/legacy_pricing/ — a deliberately gnarly legacy pricing module, an equivalent modern rewrite, and a rewrite with five seeded behavioral bugs (all caught). Full loop in under a minute.
  • examples/migration_dateutil/ — a real PyPI package: the behavior of dateutil.easter (1,145 recorded behaviors) verified against a clean modern rewrite, with zero source edits. ZeroDiff caught the one class of divergence — 4 exception-message mismatches — that a human review would wave through. Write-up with numbers: docs/CASE_STUDY.md.
  • examples/validation_* — ten more real GitHub libraries (roman, inflection, humanize, word2number, python-slugify, num2words, python-stdnum, semver, humanfriendly, pytimeparse — the last four through the full zerodiff migrate pipeline with signed attestations). Program total: 11 libraries, 12,952 recorded behaviors, 11/11 clean-room rewrites wrong on first pass, all brought to 100%. Results: docs/VALIDATION.md.

Questions like "do I need an LLM for this?" (no) are answered in the FAQ.

Licensing

The core harness is MIT and always will be. Organization-grade assurance — signed tamper-evident attestations (zerodiff attest), verification history (zerodiff history) — is source-available under a commercial license: see COMMERCIAL.md for what's covered and docs/PRICING.md for the tiers.

Status

v0.14 — Python 3.8+, function-level boundaries, zero runtime dependencies, 251 tests.

The verb set is stable: record / replay / report (0.1–0.2, with zero-edit --include instrumentation and --isolate crash-safe replay), loop + mcp + the GitHub Action and Claude Code hook (0.3), init / demo / zerodiff.testing / JUnit output and the Enterprise attestation + history layer (0.4), migrate — the end-to-end verified migration pipeline (0.5), the security/quality gate (0.7), argument-mutation and stateful-code support with parallel replay (0.8), the built-in --llm agent (0.9), insights (0.10), and guard — the dependency-upgrade safety net (0.11).

0.12 renamed the project from Retrace to ZeroDiff. 0.13 and 0.14 were correctness audits of the harness itself: 0.13 fixed three cases where the differ reported a false match, and 0.14 fixed cases where a verdict was reported without the evidence to back it (a zero-behavior replay reading as a pass, attestations signing failed runs) — see the CHANGELOG.

Roadmap: HTTP service-level recording and side-effect interception.

MIT licensed.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zerodiff-0.15.0.tar.gz (96.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zerodiff-0.15.0-py3-none-any.whl (73.9 kB view details)

Uploaded Python 3

File details

Details for the file zerodiff-0.15.0.tar.gz.

File metadata

  • Download URL: zerodiff-0.15.0.tar.gz
  • Upload date:
  • Size: 96.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.8.5

File hashes

Hashes for zerodiff-0.15.0.tar.gz
Algorithm Hash digest
SHA256 8bcea92f8be1619b77ea1fb9a392c5c9bbe7ea90c330e8b7ebb7aceeec38ab45
MD5 25a1ec8ca65fbed749cb45a2ed492912
BLAKE2b-256 ff310620b58a2296009da29e2ce9622cb7ac446398abb2c88bea010b8ac79ecd

See more details on using hashes here.

File details

Details for the file zerodiff-0.15.0-py3-none-any.whl.

File metadata

  • Download URL: zerodiff-0.15.0-py3-none-any.whl
  • Upload date:
  • Size: 73.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.8.5

File hashes

Hashes for zerodiff-0.15.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9d43750a569f4d781ed67dfab91a3a1709d550898eebc53154296e3a2f35dd64
MD5 ee4732eca3d492e00a6c0d91464cffc8
BLAKE2b-256 f45f4744f138a21692f1d381518ced2fc5403be1793f8baf7b3f7247fc86c604

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page