Skip to main content

diff-contract

Deterministic guardrails for AI-generated diffs — define what files can change, block violations.

pip install diff-contract
diff-contract check --contract .diffcontract.yml

The Problem

AI coding tools (Cursor, Claude Code, Codex) sometimes modify unrelated files, introduce changes outside the intended scope, or drift from the original structure. diff-contract sits between AI-generated code and your repo, enforcing deterministic constraints — not relying on another AI pass to review.

"Most tools either help generate code or review it after the fact, but there's no real control layer in between." — HN discussion, 2026

Quick Start

1. Install

pip install diff-contract

2. Define your contract

# .diffcontract.yml
version: 1
rules:
  - name: "Block core changes"
    deny:
      - "src/core/**"
      - "*.env"
    on_violation: block

  - name: "Allow feature X"
    allow:
      - "src/features/X/**"
      - "tests/features/X/**"
    on_violation: block

3. Check your diff

# Check current branch vs main
diff-contract check

# Check specific files
diff-contract check --files src/app.py src/utils.py

# JSON output (for CI)
diff-contract check --output json

4. GitHub Action

# .github/workflows/diff-contract.yml
name: diff-contract
on: pull_request

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: yunaremaia/diff-contract@main

Validate files (no git required)

Validate specific files against your contract without a git diff — ideal for pre-commit hooks:

diff-contract validate --files src/app.py tests/test_app.py
echo "src/foo.py" | diff-contract validate --from-stdin

Initialize a contract

Create a starter .diffcontract.yml:

diff-contract init                    # default Python project contract
diff-contract init --template react   # React/Next.js
diff-contract init --template django  # Django
diff-contract init --template rust    # Rust workspace
diff-contract init --template docs    # documentation-only

Ready-to-use templates for React, Django, Rust, and documentation-only projects are available in the examples/ directory.

Pre-commit hook

diff-contract ships a pre-commit hook. Add to your .pre-commit-config.yaml:

repos:
  - repo: https://github.com/yunaremaia/diff-contract
    rev: v0.1.0
    hooks:
      - id: diff-contract
        args: ["--contract", ".diffcontract.yml"]

SARIF Output (GitHub Code Scanning)

Generate SARIF 2.1.0 output for GitHub Code Scanning integration:

diff-contract check --sarif > diff-contract.sarif
diff-contract validate --files src/foo.py --sarif

GitHub Actions workflow:

- uses: yunaremaia/diff-contract@main
  with:
    format: sarif
    sarif-output: diff-contract.sarif

- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: diff-contract.sarif

SARIF output includes one rule per violation type. Block violations emit at error level, warnings at warning.

Exit Codes

Code Meaning
0 Clean — no violations
1 Block violation — file denied, outside allowed scope, or an aggregate limit exceeded with on_violation: block
2 Warning — non-blocking violation (e.g., large diff with on_violation: warn)

Rules

  • allow: File globs that are permitted (all others blocked)
  • deny: File globs that are denied (takes priority)
  • on_violation: block (exit 1) or warn (exit 2)
  • max_files / max_lines: optional aggregate size limits (see below)

Aggregate Limits

Path allow/deny rules constrain which files may change. max_files and max_lines constrain how large a change set may be. They are evaluated against the whole diff after per-file rules run.

Field Meaning
max_files Maximum number of changed files in the diff
max_lines Maximum total changed lines (added + deleted from git diff --numstat)

A rule may set either field, both, or neither. Limits are omitted by default (no size budget). When a limit is exceeded, the engine records an aggregate violation on the synthetic path <aggregate> and applies that rule's on_violation:

  • on_violation: block — fail the check (exit code 1). Use this to stop AI agents or CI from landing oversized diffs.
  • on_violation: warn — report the overshoot but continue (exit code 2 if there are no block violations). Use this as a PR-size nudge.

Typical uses:

  • Cap feature work so an agent cannot rewrite half the tree while implementing one ticket.
  • Keep documentation or bugfix rules tight even when the path globs are broad.
  • Warn on large diffs without blocking hotfixes.

Limits are compared against the entire change list, not only files that match that rule's allow/deny globs. A rule that only sets max_files / max_lines (no path patterns) is a global size guard.

Example

# .diffcontract.yml
version: 1
rules:
  - name: "Block core changes"
    deny:
      - "src/core/**"
      - "*.env"
    on_violation: block

  - name: "Feature development"
    allow:
      - "src/features/**"
      - "tests/features/**"
    max_files: 15
    max_lines: 400
    on_violation: block

  - name: "Large diff warning"
    max_files: 20
    max_lines: 600
    on_violation: warn

In this contract:

  • Changes under src/core/** or *.env are blocked.
  • Feature-area diffs may proceed only if they stay within 15 files and 400 lines; exceeding either budget is a block (exit 1).
  • Any diff larger than 20 files or 600 lines also produces a warning (exit 2 when nothing is blocked).

See examples/strict.yml for a fuller contract that combines deny rules with per-rule size budgets.

License

MIT

diff-contract

CI

Metadata

Release files for diff-contract 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for diff-contract 0.1.1
File Size Uploaded
diff_contract-0.1.1.tar.gz 17.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for diff-contract 0.1.1
File Interpreter ABI Platform
diff_contract-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 29.9 kB

Release files / diff_contract-0.1.1.tar.gz

Download URL diff_contract-0.1.1.tar.gz
Size 17.8 kB
Tags Source
SHA-256 checksum
How to use checksums
d865e67e8d639b0206a68f084aca780dd4f8ca1568f3173ac5311b4988ce3179
BLAKE2b-256 checksum
How to use checksums
85c757960a42d4344bf296d81711dfcf564dea32762e3981fb0b25fc9c7efed9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release files / diff_contract-0.1.1-py3-none-any.whl

Download URL diff_contract-0.1.1-py3-none-any.whl
Size 12.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5d475c61307a663c5fb8240eebb739e4375576218c4dd82fd7b3873d19841ce4
BLAKE2b-256 checksum
How to use checksums
022916378dc5623aec195eb8cbc7ac2dcb88bd5e38a7f1147d4cb2a50e39ad8c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page