{"id":50968167,"url":"https://github.com/DrBaher/compare-cli","last_synced_at":"2026-07-06T19:00:37.889Z","repository":{"id":358476849,"uuid":"1241500403","full_name":"DrBaher/compare-cli","owner":"DrBaher","description":"Clause-aware drift detection between two contract versions — a pre-signature gate for legal teams and agent pipelines. Deterministic single-file Node CLI. Part of the eight-CLI contract-ops suite — cli.drbaher.com","archived":false,"fork":false,"pushed_at":"2026-06-07T10:22:25.000Z","size":20256,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-07T10:24:48.222Z","etag":null,"topics":["agent-first","clause-aware","cli","contract-ops","contracts","diff","drift-detection","legal","legal-tech","local-first","mcp","pre-signature"],"latest_commit_sha":null,"homepage":"https://cli.drbaher.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DrBaher.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-17T13:20:29.000Z","updated_at":"2026-06-07T10:22:28.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/DrBaher/compare-cli","commit_stats":null,"previous_names":["drbaher/compare-cli"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/DrBaher/compare-cli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrBaher%2Fcompare-cli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrBaher%2Fcompare-cli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrBaher%2Fcompare-cli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrBaher%2Fcompare-cli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DrBaher","download_url":"https://codeload.github.com/DrBaher/compare-cli/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DrBaher%2Fcompare-cli/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35202786,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-06T02:00:07.184Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-first","clause-aware","cli","contract-ops","contracts","diff","drift-detection","legal","legal-tech","local-first","mcp","pre-signature"],"created_at":"2026-06-18T23:00:24.284Z","updated_at":"2026-07-06T19:00:37.854Z","avatar_url":"https://github.com/DrBaher.png","language":"JavaScript","funding_links":[],"categories":["MCP Servers for Legal"],"sub_categories":["Multilingual \u0026 Regional Legal Models"],"readme":"# compare-cli\n\n[![npm version](https://img.shields.io/npm/v/compare-cli.svg)](https://www.npmjs.com/package/compare-cli)\n[![CI](https://github.com/DrBaher/compare-cli/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/DrBaher/compare-cli/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Node ≥ 20](https://img.shields.io/node/v/compare-cli.svg)](https://nodejs.org/)\n\n\u003e Clause-aware drift detection between two contract versions. Pre-signature\n\u003e gate for legal teams and agent pipelines. Single-file Node CLI, two runtime\n\u003e deps, deterministic by design, no LLM tier in v1.\n\u003e\n\u003e Part of the **contract-ops CLI suite**: [**template-vault-cli**](https://github.com/DrBaher/template-vault-cli) (storage) → [**draft-cli**](https://github.com/DrBaher/draft-cli) (fill placeholders) → [**nda-review-cli**](https://github.com/DrBaher/nda-review-cli) (review, redline, negotiate) → [**docx2pdf-cli**](https://github.com/DrBaher/docx2pdf-cli) (DOCX → PDF) → [**sign-cli**](https://github.com/DrBaher/sign-cli) (signing + audit). **compare-cli** is the pre-signature drift gate. [Showcase site](https://cli.drbaher.com/).\n\n```sh\ncompare negotiated.docx ready-to-sign.pdf\n# exit 0 = safe to sign\n# exit 2 = substantive drift, DO NOT sign without review\n# exit 3 = cosmetic / typographic drift only (informational)\n# exit 4 = clauses moved, content identical\n```\n\n\u003e Part of the contract-ops CLI suite.\n\u003e [**draft-cli**](https://github.com/DrBaher/draft-cli) (fill placeholders) →\n\u003e [**nda-review-cli**](https://github.com/DrBaher/nda-review-cli) (review, redline, negotiate) →\n\u003e [**docx2pdf-cli**](https://github.com/DrBaher/docx2pdf-cli) (DOCX → PDF) →\n\u003e [**sign-cli**](https://github.com/DrBaher/sign-cli) (signing + audit).\n\u003e Storage: [**template-vault-cli**](https://github.com/DrBaher/template-vault-cli).\n\u003e Drift detection: **compare-cli** (this CLI).\n\u003e [Showcase site](https://cli.drbaher.com).\n\n\u003e **Agent pipelines:** see [`mcp/README.md`](./mcp/README.md) for `compare-cli-mcp`, the MCP server wrapping this CLI. Three tools (`compare_files`, `compare_with_negotiation`, `compare_demo`), stdio transport, JSON-first responses. Design contract: [`docs/mcp.md`](./docs/mcp.md).\n\n---\n\n## Why\n\nYou negotiated a contract over several rounds with counterparty's counsel.\nA few days later their paralegal sends you a `ready-to-sign.pdf`. Is the\nPDF the same text you agreed to, or did something quietly shift between\n\"final version\" and \"version we put in the signing envelope\"?\n\n`compare-cli` answers that question with an exit code your CI can gate on:\n\n- **Exit 0**: every clause matches. Safe to sign.\n- **Exit 2**: substantive drift — a clause's text changed, a clause was\n  added, or a clause was removed. The exact change is in the report. **Do\n  not sign without review.**\n- **Exit 3**: cosmetic-only (whitespace, curly quotes, em-dashes) or\n  typographic-only (case, `$1,000` vs `$1000`, Oxford comma) drift.\n  Informational; the agreement didn't change.\n- **Exit 4**: clauses moved but content is identical. Order shifted; the\n  agreement didn't change.\n\nThe CLI works on `.docx`, `.pdf`, `.md`, and plain text — including\ncross-format comparisons (negotiated `.docx` vs ready-to-sign `.pdf`).\n\n## Install\n\n```sh\nnpm install -g compare-cli\n```\n\nOr run without installing:\n\n```sh\nnpx -p compare-cli@latest -- compare --demo\n```\n\n(The package is `compare-cli`; the installed command is `compare`. The\n`-p … -- compare` form tells `npx` which package to fetch and which bin\nto run, since the two names differ.)\n\nRequires Node ≥ 20. (Pinned by `pdfjs-dist@^5.7.284`, which we share with [sign-cli](https://github.com/DrBaher/sign-cli).)\n\n## Run this\n\n```sh\ncompare --demo\n```\n\nRuns against two bundled fixtures (a negotiated NDA and a candidate where\nthe term silently shifted from \"two (2) years\" to \"three (3) years\") and\nexits **2**. You see the headline contract — substantive drift detected,\nreport written, exit code asserted — without authoring a file.\n\n```sh\ncompare --demo --json\n```\n\nSame comparison, structured JSON output to stdout.\n\n## Where to go next\n\n| If you are… | Start here |\n|---|---|\n| **A new user** evaluating the gate | [Run this](#run-this) above, then the [End-to-end transcript](#end-to-end-transcript) |\n| **An LLM agent** driving the CLI | [AGENTS.md](AGENTS.md) → `compare --catalog json` → `compare \u003cbase\u003e \u003ccandidate\u003e --json` |\n| **Gating in CI** | `compare --check` (exit-code only) or `--sarif` for code-scanning |\n| **Wiring via MCP** | the `compare-cli-mcp` package — see [docs/mcp.md](docs/mcp.md) |\n| **Adding a new CLI to the suite** | The [build-a-CLI playbook](https://cli.drbaher.com/build-a-cli) — the conventions every suite CLI follows |\n\n## End-to-end transcript\n\n```sh\n# You negotiated this:\ncat \u003e negotiated.md \u003c\u003c'EOF'\n## 1. Purpose\nThis agreement governs information exchange between Acme and Globex.\n\n## 2. Term\nThe term is two (2) years from the Effective Date.\n\n## 3. Notices\nAll notices shall be delivered to the addresses on the cover page.\nEOF\n\n# They sent back this:\ncat \u003e ready-to-sign.md \u003c\u003c'EOF'\n## 1. Purpose\nThis agreement governs information exchange between Acme and Globex.\n\n## 2. Term\nThe term is three (3) years from the Effective Date.\n\n## 3. Notices\nAll notices shall be delivered to the addresses on the cover page.\nEOF\n\n# Gate on it:\ncompare negotiated.md ready-to-sign.md\n# → substantive drift, exit 2\necho \"exit: $?\"\n\n# Or feed the base from nda-review-cli's negotiation.json:\ncompare --from-negotiation negotiation.json ready-to-sign.pdf\n\n# Strict mode: treat typographic drift ($1,000 vs $1000) as substantive too\ncompare negotiated.md ready-to-sign.md --strict\n```\n\nIn a CI pipeline:\n\n```sh\ncompare negotiated.docx received/$(date +%F).pdf || {\n  status=$?\n  case $status in\n    0) echo \"✓ safe to sign\" ;;\n    2) echo \"✗ substantive drift — do not sign\" ;;\n    3) echo \"⚠ cosmetic drift only — informational\" ;;\n    4) echo \"⚠ clauses moved but content identical\" ;;\n    *) echo \"✗ I/O or arg error\" ;;\n  esac\n  exit $status\n}\n```\n\n## Command reference\n\n```\nUSAGE\n  compare BASE CANDIDATE [options]\n  compare --from-negotiation NEG.json CANDIDATE [options]\n  compare --demo [--json]\n\nARGS\n  BASE        what was agreed (.docx | .pdf | .md | .txt | - for stdin)\n  CANDIDATE   what is being put forward (same formats, or -)\n\nOPTIONS\n  --from-negotiation PATH   read base text from nda-review-cli's negotiation.json\n  --require-signoffs        with --from-negotiation, require both parties to have signed off\n  --only-clauses PATTERNS   comma-separated; only include matching clause titles in the report + exit code\n  --ignore-clauses PATTERNS comma-separated; exclude matching clause titles from the report + exit code\n  --strict                  treat typographic drift as substantive (exit 2)\n  --strict-cosmetic         treat cosmetic drift as substantive (exit 2)\n  --json                    emit structured JSON to stdout\n  --sarif                   emit SARIF v2.1.0 to stdout (for code-scanning / CI annotations)\n  --no-intra-diff           disable inline word-level diff inside substantive clauses\n  --why                     print structured explanation to stderr\n  --silent, -q              suppress stderr\n  --check                   suppress all output; communicate via exit code only (implies --silent)\n  --output, -o PATH         write report to PATH instead of stdout (ignored with --check)\n  --completion bash|zsh     emit shell completion script\n  --demo                    run a zero-file 30-second demo\n  --version, -V             print version\n  --help, -h                show this help\n```\n\n### Exit codes\n\n| Code | Meaning                                                         |\n|------|-----------------------------------------------------------------|\n| `0`  | No drift detected, safe to sign                                 |\n| `1`  | I/O error — input not found, unreadable, malformed `.docx`/`.pdf` |\n| `2`  | Substantive drift (or `--strict`/`--strict-cosmetic` was set and tripped) |\n| `3`  | Cosmetic-only or typographic-only drift (informational)         |\n| `4`  | Clause(s) moved but content identical                           |\n\nStable across minor versions. Documented in\n[AGENTS.md](./AGENTS.md) and [COMPARE_SCHEMA.md](./COMPARE_SCHEMA.md).\n\n### What counts as which class?\n\n- **cosmetic** — whitespace runs, line wraps, curly vs straight quotes,\n  em-dashes vs hyphens, NBSP vs space, ellipsis vs `...`\n- **typographic** — number formatting (`$1,000` vs `$1000`,\n  `5.0%` vs `5%`), Oxford comma flips, case-only differences\n  (`Acme` vs `ACME`)\n- **substantive** — any word change, addition, deletion, or clause\n  reorganization (`will not` vs `will`, `two years` vs `three years`,\n  clauses added or removed)\n- **moved** — clauses whose text is byte-identical but whose position in\n  the ordered clause sequence changed\n\nThe exact rules — including what is *deliberately* not normalized away\n(singular/plural, tense, negation, list punctuation) — are locked in\n[COMPARE_SCHEMA.md](./COMPARE_SCHEMA.md) §5–§6.\n\n### `--json` output shape\n\nStable across minor versions. Top-level keys: `ok`, `exit_class`,\n`exit_code`, `base`, `candidate`, `summary`, `differences`, `warnings`.\nSee [COMPARE_SCHEMA.md §10](./COMPARE_SCHEMA.md) for the full shape.\n\n### `--why` output\n\nStructured `key=value` lines on stderr describing detection tiers,\nalignment method, class counts, exit decision, and strict-mode state.\nSame posture as draft-cli's `--why`.\n\n### `--from-negotiation`\n\nReads `nda-review-cli`'s `negotiation.json` and extracts the latest\nagreed text as BASE. Three-tier resolution (preferred → fallback):\ntop-level `status: converged|signed_off|finalized`, per-round\n`agreed: true` (minimum schema), per-round `clause_status` all\n`\"agreed\"` (historical fallback). See\n[COMPARE_SCHEMA.md §9](./COMPARE_SCHEMA.md).\n\nPair with **`--require-signoffs`** when running unattended: it errors\n(exit 2) unless both `signoffs.a` and `signoffs.b` are non-empty in the\nstate file. nda-review-cli populates these when the `negotiate sign-off`\ncheckpoint is satisfied — a human-review gate before any agreement is\nacted on.\n\n### Clause filters\n\n`--only-clauses Term,Payment,Indemnification` keeps only matching\nclauses in the report and exit-code calculation; `--ignore-clauses\nAcknowledgments,Notices` drops matching ones. Patterns are\ncase-insensitive substrings, matched against numbering-stripped clause\ntitles. Both flags can combine (`--ignore-clauses` runs after\n`--only-clauses`). The number of suppressed differences is surfaced in\nthe human report and as `summary.suppressed_by_filter` in `--json` /\nSARIF output, so the suppression is auditable.\n\n### `--sarif` (CI / code-scanning)\n\n`--sarif` emits a SARIF v2.1.0 document. Each substantive difference is\na result with `level: error`; cosmetic/typographic are `warning`;\nadded/removed/moved are `note`. Designed for GitHub Actions code-\nscanning upload — substantive drift appears as inline annotations on\nthe candidate file in the PR review UI.\n\n```sh\ncompare base.docx contracts/2026/acme.docx --sarif \u003e compare.sarif\n# upload via: github/codeql-action/upload-sarif@v3 with sarif_file=compare.sarif\n```\n\n### `--check` (exit-code-only mode)\n\n`--check` suppresses both stdout and stderr; the exit code is the only\noutput. Use for CI gates and short shell pipelines:\n\n```sh\ncompare base.docx cand.docx --check \u0026\u0026 echo \"safe to sign\"\n```\n\nImplies `--silent`. `--output` is also skipped under `--check` (you said\nyou only care about the exit code).\n\nIf no agreed round exists, the CLI exits 2 with a clear error.\n\n### Working with PDFs\n\nText extraction from `.pdf` is layout-lossy. When either side is a PDF,\nthe report surfaces a warning:\n\n```\nwarning: candidate was extracted from PDF; layout-sensitive differences\n         may surface as false positives\n```\n\nIf extraction returns zero characters (a scanned PDF without an OCR\nlayer), compare-cli **exits 1** with a clear message rather than\nsilently reporting no drift.\n\n## Part of the contract-ops suite\n\n[cli.drbaher.com](https://cli.drbaher.com)\n\nPipeline (in order):\n\n- **[draft-cli](https://github.com/DrBaher/draft-cli)** — fills\n  placeholders in templates before negotiation begins.\n- **[nda-review-cli](https://github.com/DrBaher/nda-review-cli)** — owns\n  the `negotiation.json` hash-chained state file. `--from-negotiation`\n  reads its output.\n- **[docx2pdf-cli](https://github.com/DrBaher/docx2pdf-cli)** — the\n  upstream step that turns the agreed `.docx` into the `.pdf` you put\n  in the signing envelope.\n- **[sign-cli](https://github.com/DrBaher/sign-cli)** — runs the actual\n  signing flow; compare-cli is the gate that runs before it.\n\nAuxiliaries:\n\n- **[template-vault-cli](https://github.com/DrBaher/template-vault-cli)**\n  — clause-aware template storage; produces `info --json` payloads that\n  downstream tools consume. Implements the same clause-detection rule\n  ([docs/clause-detection.md](./docs/clause-detection.md)) compare-cli\n  does; divergences tracked in\n  [template-vault-cli/docs/clause-detection-divergence.md](https://github.com/DrBaher/template-vault-cli/blob/main/docs/clause-detection-divergence.md).\n\n## Documentation\n\n- **[COMPARE_SCHEMA.md](./COMPARE_SCHEMA.md)** — v1 contract. The single\n  source of truth for what the CLI does. Implementation and tests are\n  written against this file.\n- **[AGENTS.md](./AGENTS.md)** — for LLM consumers and agent pipelines.\n  Stable output shapes, exit codes, failure diagnosis.\n- **[ARCHITECTURE.md](./ARCHITECTURE.md)** — how the CLI is shaped and why.\n- **[GETTING_STARTED.md](./GETTING_STARTED.md)** — 10-minute walkthrough.\n- **[FAQ.md](./FAQ.md)** — common questions.\n- **[SECURITY.md](./SECURITY.md)** — disclosure policy.\n- **[CONTRIBUTING.md](./CONTRIBUTING.md)** — for contributors.\n- **[CHANGELOG.md](./CHANGELOG.md)** — release history.\n\n## License\n\n[MIT](./LICENSE) © DrBaher\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDrBaher%2Fcompare-cli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FDrBaher%2Fcompare-cli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDrBaher%2Fcompare-cli/lists"}