mcpField
C
confdiff-mcp

confdiff-mcp

ローカル
github.com/esperanza-volkov開発ツール415 週間前に更新

confdiff-mcp について

confdiff は JSON、YAML、TOML、INI、.env、XML、CSV など、設定ファイルやデータファイルを形式に応じて比較する差分ツールです。テキストではなくデータ構造を比較するため、並び順や整形の変更は差分になりません。秘密情報を伏せて出力することもできます。

主な機能

  1. 01八種類の設定・データ形式に対応
  2. 02キーの順序や整形を無視した意味単位の比較
  3. 03--redact による秘密値のフィンガープリント化
  4. 04形式を跨ぐ比較とディレクトリ単位の比較
  5. 05CI 向けの終了コードと JSON 出力
  6. 06AI エージェント向けの組み込み MCP サーバー

活用シーン

  1. 01環境間の設定差分の確認
  2. 02PR や CI ログへの安全な設定変更の共有
  3. 03形式移行の前後における設定ファイルの比較

MCP 対応

confdiff は MCP サーバーを内蔵しており、AI コーディングエージェントが意味単位で設定を比較できます。redact により平文の秘密情報がエージェントのコンテキストに入りません。

設定

ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。

mcp.json · 共通設定
{
"mcpServers": {
"esperanza-volkov-confdiff": {
"command": "npx",
"args": [
"-y",
"confdiff-mcp"
]
}
}
}
起動コマンドnpx -y confdiff-mcp

ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。

パッケージ
npmconfdiff-mcp0.17.1

ツール

2

掲載時のツール一覧 · 2 週間前に更新

パラメーター型必須説明
astringはい1 つ目の設定を文字列で指定します。
bstringはい2 つ目の設定を文字列で指定します。
onlyarrayいいえ設定すると、これらの glob に一致するパスのみを比較します。
loosebooleanいいえ緩やかなスカラー比較:文字列、数値、ブール値を相互に変換するため、"3" == 3 となります。
ignorearrayいいえ無視するパスの glob。ドット記法を使用します(例:'metadata.creationTimestamp'、'spec.**')。
redactbooleanいいえ機密値(キー名から検出されるパスワード、トークン、キー)を安定した不可逆のフィンガープリントに置き換えます。平文の機密情報がコンテキストに入るのを防ぎながら、構成の差異を確認できます。
formatAenumいいえ1 つ目の入力形式を強制的に指定します(指定しない場合はファイル名/内容から推定します)。json | jsonc | yaml | toml | ini | env | xml | csv
formatBenumいいえ2 つ目の入力形式を強制的に指定します。json | jsonc | yaml | toml | ini | env | xml | csv
arrayKeyarrayいいえオブジェクトの配列を位置ではなくフィールド値で照合します。これにより、リストの並べ替え(例:k8s の env:/containers: ブロック)が変更として報告されません。フィールド名のみ('name')、またはスコープ付きの 'pathGlob=field' を指定します。
arraySetbooleanいいえ配列をインデックス順ではなく、順序のない多重集合として比較します。
redactEntropybooleanいいえredact と併用すると、キーに関係なく、機密情報のように見える値(長く、エントロピーが高い値)もマスクします。

詳細

confdiff

設定ファイルと構造化データファイル向けの、意味と形式を考慮した差分表示です。 実際に変わったもの、つまりテキストではなく意味を確認できます。

npm version npm downloads CI license: MIT

▶ ブラウザーで試す — インストール不要(2 つの設定ファイルを貼り付けるだけで、すべてクライアント側で実行され、アップロードは一切ありません)。

🌐 日本語版の README はこちら → README.ja.md

アニメーション表示のターミナル:confdiff が --redact を使って 2 つの .env ファイルを比較しています。キーの並べ替えとコメントの追加はノイズなしとして報告され、実際の 3 つの変更だけが表示されます。シークレット値は安定したフィンガープリントでマスクされます

$ confdiff old.yaml new.yaml
~ env.LOG_LEVEL  "info" => "debug"
+ env.NEW_FLAG   = true
~ image          "nginx:1.25" => "nginx:1.26"
~ ports[1]       443 => 8443
~ replicas       3 => 5

5 changes: 1 added, 4 changed

……そして、シークレットが PR に漏れることもありません。--redact はシークレット値を安定したフィンガープリントでマスクするため、値が差分、PR コメント、CI ログに一切表示されることなく、パスワードやトークンに変更があったことを確認できます。

$ confdiff prod.env staging.env --redact
~ DB_PASSWORD  «redacted:28c19f» => «redacted:7ae46c»
~ API_TOKEN    «redacted:4badbf» => «redacted:057852»
~ LOG_LEVEL    "info" => "debug"

これを実現する設定ファイル差分ツールは、ほかにありません。シークレットを安全に扱う差分表示へ →

git diff は文字を表示します。confdiff はキーと値を表示します。各ファイル(JSON、YAML、TOML、INI、.env、.properties、CSV、XML)をデータモデルに解析してから、そのモデルを比較します。そのため、キーの並べ替え、配列の折り返し、引用符の変更、コメントの追加、インデントの調整は変更として報告されません。データに実際の差異がある場合のみ報告されます。

このプロジェクトは、自律型 AI エージェント(Esperanza Volkov)によって開発・保守されています。Issue と PR はエージェントが読み、対応します。問題があれば、Issue を作成してください。そのフィードバックが、まさに改善につながります。confdiff によってノイズの多い差分を避けられた方は、ほかの人が見つけやすくなるよう ⭐ を付けていただけると助かります。


なぜ単に diff/git diff を使わないのですか?

設定ファイルのテキスト差分はノイズが多く、誤解を招きます。

  • YAML/TOML/JSON オブジェクトのキーを並べ替えると、何も変わっていなくても大きな差分として表示されます。
  • 書式の変更(2 スペースから 4 スペースへの変更、インラインの [80, 443] からブロック形式のリストへの変更、シングルクォートとダブルクォートの変更)も、変更として表示されます。
  • コメントの追加も、変更として表示されます。
  • port: 80(数値)が port: "80"(文字列)に変わったことを判別できません。これは実際のバグですが、テキスト差分では同じように表示されます。
  • ある形式から別の形式に移行したファイルを比較できません。

confdiff は見た目だけのノイズを無視し、意味上の変更のみを、明確なパス、変更前の値、変更後の値とともに 1 行ずつ報告します。

特長

  • 8 つの形式を 1 つのツールで: JSON(コメント付き JSON を含む — tsconfig.json、 VS Code の settings.json、.jsonc、// および /* */ コメント、末尾のカンマ)、 YAML、TOML、INI/.cfg/.conf、.env、Java .properties(=、:、 空白区切りに対応)、CSV/TSV、XML(.xml/.svg/.plist/…)に対応します。拡張子から 形式を自動検出し、拡張子で判別できない場合は内容を調べます。
  • 形式をまたいだ比較: config.json と、移行後の config.yaml を比較し、同等であることを確認できます。
  • ディレクトリ全体の差分: 2 つのディレクトリ (confdiff old-manifests/ new-manifests/)を指定すると、設定 ファイルを相対パスで再帰的に対応付け、追加、削除、意味上の変更があった ファイルを表示します。2 つの Helm レンダリング結果、2 つの 環境の設定ツリー、または kubectl get -o yaml の実行前後のダンプの比較に最適です。ディレクトリ差分を参照してください。
  • 複数ドキュメントの YAML: --- 区切りを含むファイル(Kubernetes マニフェスト、 kubectl get -o yaml、Helm のレンダリング結果)はドキュメントのリストとして解析され、 ドキュメントごとに比較されます。「複数ドキュメント」の解析エラーはもう発生しません。末尾や空の 区切りは見た目だけのものとして扱われ、架空の差分は生じません。
  • テキストではなく行単位で比較する CSV/TSV: 区切り文字(, \t ; |)を 自動検出し、RFC-4180 の引用符を処理します。位置で比較するか、 --csv-key <column> を渡してキー列で行を照合できます。行の並べ替えや挿入に埋もれることなく、 実際に変更されたセルを特定できます。
  • シークレットを安全に扱う差分(--redact): パスワード、トークン、 API キーなどのシークレット値を、生の値ではなく安定したフィンガープリント («redacted:1a2b3c»)にマスクします。シークレットに差異があることは確認できます(2 つのフィンガープリントが異なります)が、 値が PR のコメント、Slack のスレッド、CI ログに記録されることはありません。この機能を備えた 他の設定差分ツールはありません。シークレットを安全に扱う差分を参照してください。
  • 型の変更を検出: ~ port 80 => "80" (type) のように、テキスト差分では見逃される種類の バグを検出します。
  • 大きな整数を損失なく処理: 64 ビットカウンターや、Discord/Twitter の「スノーフレーク」 ID(2^53 を超える値)を正確に比較するため、異なる 2 つの ID が誤って「差分なし」と 判定されることはありません(すべてを浮動小数点数として解析するツールで起きる問題です)。 YAML のアンカーマージキー(<<: *anchor)は、差分の比較前に実効内容へ解決されます。
  • --ignore と --only で使えるパスの glob:変動するフィールドを無視し (--ignore "metadata.*" --ignore "**.timestamp")、またはサブツリーに絞って比較できます。キー自体にドットが 含まれる場合(k8s のアノテーション app.kubernetes.io/version など)でも、変更箇所として 表示されるパスを glob にそのまま渡せます。
  • 緩やかなモード(-l):"3" と 3、"true" と true を同じ値として扱います。すべてが文字列となる .env/INI に最適です。
  • 順序が重要でないリストに使える順不同配列(--array-set)。
  • キー付き配列(--array-key):オブジェクトのリストを位置ではなくフィールド値で照合します。 Kubernetes の env: や containers: ブロックを並べ替えても、不要な差分は 発生せず、各エントリが対応する要素と比較されます: containers[name=web].env[name=LOG_LEVEL].value。キー付き配列を参照してください。
  • CI に適した設計: 差分がある場合は終了コード 1、差分がない場合は 0、エラーの場合は 2 を返します。 機械可読な --json 出力に対応します。標準入力(-)から読み込めます。
  • MCP サーバーを内蔵: AI コーディングエージェントは confdiff を呼び出して、設定を意味に基づいて比較できます。 シークレットの値をマスキングするため、平文がコンテキストに入ることはありません。MCP サーバーを参照してください。
  • 設定不要で高速、依存関係も最小限です。ライブラリとしても使えます。

比較

優れた差分ツールは数多くあります。confdiffは、プロジェクト内で混在する形式をまたいで、設定やデータを意味に基づいて比較するという特定の用途を想定しています。

confdiffdiffxdifftasticdyffjd / json-diff
JSON✅✅✅✅✅
YAML✅✅✅✅—
TOML✅✅✅——
INI / .env✅INI のみ———
CSV / TSV✅(キー付き行)✅———
XML✅✅———
形式をまたいだ比較(JSON ↔ YAML)✅————
スカラー値の緩い比較モード(.env/INI)✅————
セマンティック比較(キー順序/配列の折り返しを無視)✅✅一部¹✅✅
型変更の検出(80 と "80")✅✅———
パスの glob による無視/限定✅正規表現²—一部—
git diff-driver との連携✅————
CI 終了コード + --json✅✅✅✅✅
インストール/エコシステムnpmcargocargoバイナリnpm

¹ difftasticは構文ベースの構造差分ツールです。ソースコードに優れており、キーの並べ替えも移動として検出します。confdiffはセマンティックです。ファイルをデータとして扱うため、キーの順序変更や配列の折り返しは変更と見なしません。用途が異なります。コードにはdifftastic、設定にはconfdiffをお使いください。

² diffxは最も近いツールで、高速で成熟したRust製のセマンティック差分ツールです。Rustエコシステムを使っているなら、優れた選択肢です。confdiffは現在、同じ形式セット(XMLを含む)に対応していますが、Node/npmの世界を対象としており、設定移行のワークフローに重点を置いています。形式をまたいだ比較(config.jsonと、それを変換したconfig.yamlを比較)、.env/INI内のPORT=80とPORT="80"を型の変更として扱わないスカラー値の緩い比較モード、追跡対象の設定に対するgit diffでセマンティックな出力を表示する、差し替え可能な**git diff driver**を備えています。スタックに合うほうをお選びください。どちらもテキスト差分より優れています。

インストール

一度だけ実行し、インストールしない方法(Node.js ≥ 18 が必要です):

npx confdiff old.yaml new.yaml

confdiffコマンドをグローバルにインストールする方法:

npm install -g confdiff
confdiff old.yaml new.yaml

confdiffはnpmレジストリで公開されています。最新版を使いたい場合は、npm install -g github:esperanza-volkov/confdiffでソースから直接インストールすることもできます。

Homebrew(macOS / Linux):

brew install esperanza-volkov/confdiff/confdiff

タップは最新リリースを追跡し、Node.jsも自動でインストールします。

Nodeがない場合:コンテナを実行

依存関係のない小さなイメージをGitHub Container Registryで公開しています。ファイルのあるディレクトリをマウントし、そのディレクトリからの相対パスを指定してください。

docker run --rm -v "$PWD:/work" ghcr.io/esperanza-volkov/confdiff old.yaml new.yaml

エントリーポイントはCLIなので、すべてのフラグを同じように使えます(--redact、--only、--jsonなど)。:latestを使うか、バージョンタグ(ghcr.io/esperanza-volkov/confdiff:v0.10.0)を指定してください。

使い方

confdiff <a> <b> [options]

  confdiff old.yaml new.yaml
  confdiff config.json config.yaml         # cross-format
  confdiff old.csv new.csv --csv-key id    # match CSV rows by a key column
  cat a.env | confdiff - b.env --format env

Options:
  -f, --format <fmt>     Force format for BOTH inputs (json, yaml, toml, ini, env, csv, xml)
      --format-a <fmt>   Force format for the first input
      --format-b <fmt>   Force format for the second input
  -i, --ignore <glob>    Ignore paths matching glob (repeatable / comma-separated)
  -o, --only <glob>      Only compare paths matching glob (repeatable)
  -l, --loose            Loose scalars: "3"==3, "true"==true
      --array-set        Compare arrays as unordered sets (ignore element order)
      --array-key <spec> Match arrays of objects by a key field, not by position
                         (e.g. k8s env/containers): --array-key name, or scope
                         with <pathGlob>=<field>. Repeatable / comma-separated.
      --csv-key <col>    For CSV/TSV: match rows by this column, not by position
      --redact           Mask secret values (passwords/tokens/keys) as fingerprints
      --redact-key <glob> Also redact values at these key/path globs (repeatable)
      --redact-entropy   Also redact high-entropy secret-looking values (any key)
      --array-set        Compare arrays as unordered sets
      --json             Machine-readable JSON output
  -q, --quiet            No output; communicate via exit code only
      --no-color         Disable ANSI color
      --exit-zero        Always exit 0 even when there are differences
  -h, --help             Show help
  -v, --version          Show version

Exit codes: 0 = no differences, 1 = differences, 2 = usage/parse error
パスの glob

パスにはドット記法と配列インデックスを使います(例:server.ports[0]、env.LOG_LEVEL)。globでは、*は1つのセグメントに、**は任意の深さに一致します。セグメント内では*(任意の文字列)と?(1文字)も使えるため、*_SECRET、db_*、item?はいずれも使用できます。配列インデックスには、ツールが出力する角括弧形式(items[0]、items[*])とドット形式(items.0、items.*)のどちらも使えます。そのため、変更箇所として表示されたパスは、そのまま--ignore/--onlyに指定して再利用できます。

# ignore anything under metadata, and any "timestamp" key at any depth
confdiff a.json b.json -i "metadata.*" -i "**.timestamp"

# only care about the database section
confdiff a.toml b.toml --only "database.**"

# mute every key that ends in _SECRET or _TOKEN, at the top level
confdiff .env.a .env.b -l -i "*_SECRET" -i "*_TOKEN"
CSV / TSV

CSVとTSVは、ヘッダーをキーとして行に解析されます。デフォルトでは行は位置で比較されます。これは追記のみのエクスポートに適しています。ただし、並べ替えたり再エクスポートしたりしたCSVを位置で比較すると、すべてが変更されたように見えます。そのため、安定したキーで行を照合するには--csv-key <column>を指定してください。

# users.csv reordered, with one role change and one new row
$ confdiff old.csv new.csv --csv-key id
~ 2.role  "user" => "editor"
+ 3       = {"id":"3","name":"carol","role":"user"}

2 changes: 1 added, 1 changed

同じファイルを位置で比較すると、誤検出の変更が十数件報告されます。CSVのセルは常に文字列なので、--looseは形式をまたいだ比較と相性がよく(CSVの"80"はJSONの80と等しくなります)。区切り文字(, \t ; |)は自動検出され、RFC-4180形式の引用符(引用符で囲まれたカンマや改行、""によるエスケープ)も処理されます。

XML

XML は入れ子構造のデータモデルに解析されるため、テキストではなく構造で差分を比較します。そのため、インデントの変更、属性の並べ替え、兄弟要素の順序変更は変更として報告されません。属性には @_ 接頭辞が付き、要素自身のテキストは #text となり、繰り返される子要素は配列になります。

$ confdiff old.xml new.xml
~ config.server.@_port  8080 => 9090
~ config.server.#text   "on" => "off"

スカラーのテキストと属性値は型変換されるため、<port>80</port> は JSON の "port": 80 と等しいものとして比較されます。XML でも形式をまたいで比較できるため、移行前の config.xml と移行後の config.yaml を差分比較できます。型変換を避けたい場合は --loose を使用してください。不正な XML は正常に処理され、終了コード 2 が返されます。

キー付き配列(リストマップ)

多くの設定形式では、実際には1つのフィールドをキーとするマップであるオブジェクトのリストが使われます。典型的な例は、Kubernetes の env:、containers:、ports:、volumeMounts: ブロックです。位置で比較すると、2つの要素を入れ替えただけでも、意味的には何も変わっていないのに大きな変更のように見えてしまいます。--array-key <field>(またはカンマ区切り/繰り返し指定のリスト)を指定すると、confdiff はそのフィールドの値で要素を照合します。

$ confdiff old-deploy.yaml new-deploy.yaml --array-key name
~ spec.replicas                                     3 => 4
~ spec.template.spec.containers[name=web].image     "nginx:1.25" => "nginx:1.26"
~ spec.template.spec.containers[name=web].env[name=LOG_LEVEL].value  "info" => "debug"

フィールドが使用されるのは、両側のすべての要素が、そのフィールドを持つオブジェクトであり、値がスカラーである場合に限られます。そのため、--array-key name は env/containers のキー付けに使われる一方、ports: リストには name がないため、インデックスで差分比較されます。そちらにもキーを付けるには、別のフィールドを指定してください(--array-key name --array-key containerPort)。片側でキー値が一意でない場合、その配列は安全のため位置による差分比較にフォールバックします。<pathGlob>=<field> を指定すると、1つの配列にキーを限定できます(例:--array-key spec.template.spec.containers=name)。出力される [name=web] セレクターは、そのまま --ignore/--only に渡して再利用できます。

ディレクトリの差分比較

confdiff に2つのディレクトリを指定すると、両方のツリーをたどり、相対パスで設定ファイルを対応付け、ファイルごとに意味的な差分を表示します。どのファイルが追加、削除、または実際に変更されたかを確認できます(キーの並べ替え、再フォーマット、コメントの変更は、単一ファイルの場合と同様に無視されます)。

$ confdiff env/staging/ env/prod/
~ deploy.yaml
    ~ replicas       2 => 5
    ~ image          "app:1.4.0" => "app:1.4.1"
+ feature-flags.json (new file)
- legacy.ini (deleted)

3 file(s): 1 changed, 1 added, 1 removed

認識される設定ファイルの拡張子(JSON、YAML、TOML、INI、.env、.properties、CSV、XML)を持つファイルのみが対象です。それ以外のファイル(README.md、バイナリ、ロックファイルなど)はスキップされ、.git/ と node_modules/ は走査対象から除外されます。すべてのオプションはツリー全体に適用されます。--ignore/--only の glob はすべてのファイルに適用され、--redact は各ファイル内のシークレットをマスクし、--loose と --array-set も引き継がれます。また、--json は CI 向けに、構造化された { changed, files: [...] } レポートを出力します。何かに差異があれば終了コードは 1、ツリーが意味的に同一なら 0 です。

これは、レンダリング済みの2つの Helm 出力、2つの環境、または kubectl get -o yaml の実行前後で「実質的な変更があったか」を、ファイルごとにテキスト差分のノイズをかき分けることなく確認するための、すばやい方法です。

シークレットを安全に保つ差分(--redact)

設定ファイルには、DB_PASSWORD、API_TOKEN、秘密鍵などのシークレットが含まれています。設定ファイルの差分を PR レビュー、Slack のスレッド、CI ログに貼り付けた瞬間、変更されたシークレットがそのまま漏洩してしまいます。--redact を使うと、シークレットらしい値が安定した復元不可能なフィンガープリントに置き換えられるため、値を明かさずに変更を確認できます。

$ confdiff prod.env staging.env --redact
~ DB_PASSWORD  «redacted:28c19f» => «redacted:7ae46c»
~ API_TOKEN    «redacted:4badbf» => «redacted:057852»
~ LOG_LEVEL    "info" => "debug"

3 changes: 3 changed

2 つのフィンガープリントが異なるため、どのシークレットが変更されたかはわかりますが、出力から値を復元することはできません。シークレットではないキー(LOG_LEVEL)は通常どおり出力されます。フィンガープリントは値から生成されるため、変更されていないシークレットは報告されません。

  • シークレットとして扱うキーは、キー名に対する組み込みのヒューリスティックによって決まります(password、passwd、secret、token、api_key、access_key、private_key、credential、client_secret、passphrase、dsn など)。大文字と小文字、区切り文字を区別せずに照合されます(DB_PASSWORD、db-password、dbPassword はすべて一致します)が、keyboard や monkey のような、似ているだけで問題のない語は意図的に除外されます。
  • --redact-key <glob>(繰り返し指定可能、カンマ区切り)で独自のキーを追加できます。組み込みルールに追加され、--ignore/--only と同じ glob を受け付けるため、--redact-key "auth.*" のような指定も、キー名だけの指定も使用できます。
  • --redact-entropy を指定すると、シークレットに見える値(長く、ランダムで、エントロピーの高いトークン、API キー、JWT、Base64 のデータなど)も、キー名を問わずマスクします。これにより、キー名のヒューリスティックでは検出できない、x、data、value のような無難なキーに格納された認証情報も検出できます。この機能はキー名のチェックを置き換えるのではなく、補完します。Letmein のような弱いパスワードはエントロピーが低く、キー名ルールでのみ検出されます。一方、目立たないキー名の下にある 40 文字のトークンはエントロピーによってのみ検出されます。そのため、最も幅広く検出するには両方を有効にしてください。(コンテンツに基づく検出を提案してくれた Hacker News の皆さん、ありがとうございます。)
  • 名前と値のペアにも対応しています。 Kubernetes の env: エントリ(および多くの CI 変数ブロック)では、シークレットのキー名がそのままキー名になるわけではありません。{ name: DB_PASSWORD, value: <secret> } オブジェクトのリストとして格納されるため、認証情報を保持するキーは文字どおり value です。このようなリストを --array-key name で比較すると、confdiff は兄弟の name フィールドを読み取り、対応する value をマスクします。そのため、env[name=DB_PASSWORD].value はマスクされますが、env[name=LOG_LEVEL].value は通常どおり出力されます。
  • --json 出力でも値をマスクし、その変更に "redacted": true を追加します。

これは GitHub Action で必要な機能です(redact: true を設定してください)。PR コメントはリポジトリの読み取り権限を持つ全員に表示されるため、そこに変更されたシークレットの値が含まれると、実際のインシデントにつながります。

差分での意図しない漏洩を防ぐための安全策であり、シークレットマネージャーの代わりでも、すでに平文でコミットされた認証情報をローテーションする代わりでもありません。

使用例

confdiff が得意とする実際の作業(すべて設定不要で、実際の変更があると終了コード 1 を返すため、そのまま CI に組み込めます):

2 つの Kubernetes マニフェスト間の設定のずれを検出する(変更されやすいサーバー管理フィールドの metadata を無視します):

confdiff rendered-prod.yaml rendered-staging.yaml \
  --ignore "metadata.annotations.*" \
  --ignore "metadata.creationTimestamp" \
  --ignore "metadata.resourceVersion" \
  --ignore "status.*"

シークレットや順序の違いを無視して、環境間の .env を比較する(.env の値はすべて文字列なので、緩いモードを使用します):

confdiff .env.development .env.production -l --ignore "*_SECRET" --ignore "*_KEY"

形式を移行しても内容が変わっていないことを確認する(JSON → YAML)。confdiff はバイト列ではなく、データモデルを比較します。

confdiff config.json config.yaml && echo "migration is faithful"

依存関係の更新で、想定した箇所だけが変更されたことを確認する — package.json のセマンティック差分では、並べ替えや再フォーマットを無視し、バージョンの変更だけを表示します。

git show HEAD~1:package.json | confdiff - package.json

制限された設定に実際の変更があった場合、PR を失敗させる(再フォーマットだけでは失敗しません):

confdiff baseline/app.toml app.toml --json > changes.json  # exit 1 => CI fails

CSV/TSV のデータエクスポートを行の位置ではなく ID で追跡することで、行の並べ替えや挿入に埋もれることなく、変更されたセルを特定できます。

confdiff yesterday.csv today.csv --csv-key id

git diff ドライバーとして使用する

git diff、git log -p、git show で設定ファイルのセマンティックな差分を表示します。キーの並べ替えや再フォーマットがノイズとして表示されなくなります。

1 つのコマンドで設定できます(冪等で、何度実行しても安全です)。

confdiff install-git-driver            # this repo
confdiff install-git-driver --global   # all your repos

これにより diff.confdiff.command が設定され、.gitattributes に一般的な設定ファイルのパターン(*.json、*.yaml、*.toml、*.ini、*.env、*.csv、*.xml など)が追加されます。デフォルトを上書きするには、独自のパターンを指定します。

confdiff install-git-driver "*.conf" "config/**/*.json"

キーの順序だけが変わった場合、セマンティックな変更は表示されず、値が実際に変わった場合は、変更箇所だけが表示されます。

$ git diff config/app.yaml
confdiff config/app.yaml
~ server.port  8080 => 9090

手動で設定する場合は、次の 2 行です。

git config diff.confdiff.command 'confdiff --git-diff-driver'
echo '*.yaml diff=confdiff' >> .gitattributes

--git-diff-driver は git の 7 つの差分引数を受け取り、それらを 2 つのファイルバージョンに割り当てます。これは git diff ドライバーでの正しい呼び出し方法です。

GitHub Action — PR 上で設定ファイルのセマンティックな差分を表示

再フォーマットされたテキストが大量に並ぶ代わりに、設定ファイルの実際の変更を PR 上で直接確認できます。この Action は、変更された JSON/YAML/TOML/INI/.env/CSV/XML ファイルをすべて調べ、キーと値の変更のみを示す単一の固定コメントを投稿します。キーの並べ替え、再フォーマット、コメント、引用符の変更は無視されます。

# .github/workflows/confdiff.yml
name: confdiff
on: pull_request
permissions:
  contents: read
  pull-requests: write   # needed to post the comment
jobs:
  config-diff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0   # confdiff needs the base commit to compare against
      - uses: esperanza-volkov/confdiff@v1

その場合、deploy/values.yaml の変更は次のようなコメントとして表示されます。

~ image      "nginx:1.25" => "nginx:1.26"
~ replicas   3 => 5
+ newFlag    = true

入力(すべて省略可能):paths(チェック対象のファイルを絞り込むパス指定)、args(追加の confdiff フラグ。例:--loose --ignore metadata.*)、redact(true/false、デフォルトは false。シークレット値をフィンガープリントとしてマスクし、変更された認証情報が PR コメントに投稿されないようにします。シークレットを含む設定ファイルがあるリポジトリでは推奨)、base(差分の比較対象となる ref)、comment(true/false、デフォルトは true)、fail-on-diff(セマンティックな変更があった場合にジョブを失敗させる)、github-token。出力:changed(true/false)。

      - uses: esperanza-volkov/confdiff@v1
        with:
          redact: true          # never leak a changed secret into the PR comment

コメントの代わりに、設定ファイルの変更をマージの条件にする場合:

      - uses: esperanza-volkov/confdiff@v1
        with:
          comment: false
          fail-on-diff: true
          paths: 'config/** k8s/**'

pre-commit フック — コミット前に差異を防ぐ

confdiff には pre-commit フックが付属しているため、ローカルで 2 つの設定ファイルの同期を保てます。ファイルの内容に差異があるとコミットは失敗し、セマンティックな差分が表示されます。よくある用途は、実際の .env に対する .env.example の保護や、いくつかの既知のキーを除いて staging と prod のオーバーレイを一致させることです。

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/esperanza-volkov/confdiff
    rev: v0.17.4
    hooks:
      - id: confdiff
        args: [config/staging.yaml, config/prod.yaml, --ignore, replicas]
        files: ^config/(staging|prod)\.yaml$

2 つのパスと confdiff フラグを args で指定します。このフックは一致したファイル名を追加しないため、比較対象を正確に制御できます。files: で対象を絞り、これらの設定ファイルに変更があった場合のみ実行するようにします。キーの並べ替え、再フォーマット、コメントは無視されるため、このフックは実際の値の変更があった場合のみ実行され、ファイルの再フォーマットによる誤検出はありません。

プログラムから利用する API

import { compare, diff, parseContent } from "confdiff";

// high-level: raw strings, formats auto-detected or forced
const changes = compare(rawA, rawB, {
  formatA: "json",
  formatB: "yaml",
  ignore: ["metadata.*"],
});

// low-level: diff two already-parsed values
const d = diff({ a: 1 }, { a: 2 }); // [{ path: ["a"], kind: "change", ... }]

各 Change は { path, kind: "add"|"remove"|"change", oldValue?, newValue?, typeChanged? } です。

MCP サーバー — AI エージェントで設定を差分比較

confdiff には MCP サーバーが付属しているため、AI コーディング アシスタント(Claude Desktop、Cursor、Cline、Windsurf、…)は、設定ファイル全体を貼り付けて差分のノイズを目視で確認する代わりに、 意味に基づいて設定を比較できます。次の 2 つのツールを公開しています。

  • diff_configs — モデルがすでにコンテキスト内に持っている 2 つの設定文字列を差分比較します。
  • diff_config_files — パスを指定してディスク上の 2 つのファイルを読み込み、差分比較します。

どちらも CLI と同じオプション(ignore、only、arrayKey、 arraySet、loose、formatA/formatB、redact、redactEntropy)を受け付け、 実際の変更だけを簡潔なリストと構造化 JSON で返します。キーの順序や 書式の違いによるノイズは除外されます。特に重要なのは、redact: true を指定すると、秘密の値が 安定したフィンガープリントとしてマスキングされることです。そのため、平文のパスワードやトークンが設定内にあっても、 モデルのコンテキストに入ることなく、ドリフトを確認できます。

任意の MCP クライアント設定に追加してください。

{
  "mcpServers": {
    "confdiff": {
      "command": "npx",
      "args": ["-y", "confdiff-mcp"]
    }
  }
}

サーバーは独立したパッケージ confdiff-mcp として提供され、 公式の MCP Registry に io.github.esperanza-volkov/confdiff-mcp として登録されています。または、 npm i -g confdiff-mcp でグローバルにインストールし、args を指定せず "command": "confdiff-mcp" を使用してください。 (メインの confdiff パッケージ内の confdiff-mcp バイナリも、引き続き ["-y", "-p", "confdiff", "confdiff-mcp"] から利用できます。)

ビルド手順や API キー、設定が必要な環境変数はありません。初回実行時に npx 経由で公開済みパッケージを取得します。MCP サーバーを 自動的にインストールするエージェント(Cline など)は、 llms-install.md に従うと、正確なワンステップの設定方法を確認できます。 その後、エージェントに「prod.yaml の編集で、レプリカ数以外に実質的な変更はあった?」 や「タイムスタンプを無視して、この 2 つの Helm のレンダリング結果を差分比較し、秘密の値は表示しないで」 といった質問をしてみてください。

2 つのファイルが等しいと判断する方法

  1. 両方をプレーンなデータモデル(オブジェクト、配列、スカラー値)に解析します。
  2. オブジェクトのキーの順序を無視し、キーごとに再帰的に比較します。
  3. add / remove / change を報告し、変更によって値の型も変わった場合はそれを示します。

コメント、空白、引用符のスタイル、キーの順序、および(任意で)配列の順序は、 すべて非セマンティックな要素とみなされ、報告されません。

質問・フィードバック

正しく差分比較できない設定ファイルや、追加してほしい形式、共有したい confdiff の活用方法があれば、 GitHub Discussions (Q&A / アイデア / 活用例)にスレッドを立ててください。誤動作の原因となる実際のファイルを共有いただくのが、最も役立ちます。バグは issues から報告してください。

貢献

Issue とプルリクエストを歓迎します。テストスイートは次のコマンドで実行できます。

npm install
npm test
npm run build

詳しいガイド(新しい形式の追加方法を含む)は CONTRIBUTING.md、CODE_OF_CONDUCT.md、 リリースノートは CHANGELOG.md を参照してください。

関連プロジェクト

confdiff を気に入った方におすすめする、同じメンテナーによる依存関係ゼロの小さな CLI ツールです。

  • cmdpeek — --help/man ページを解析して、あらゆるコマンドのフラグを対話的に参照・作成できます(ローカルでオフライン動作する explainshell + Ctrl-G シェルウィジェットです)。
  • comptab — --help/man を解析して、仕様を手作業で用意せずに、あらゆる CLI の bash / zsh / fish 向けシェル補完を生成します。

ライセンス

MIT © Esperanza Volkov

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。