zzop について
zzop は、コーディングエージェントや開発者向けの決定論的なリポジトリ分析エンジンです。コード構造を整理し、フロントエンドの呼び出しとバックエンドのルートを結び付け、ネットワークリクエストなしで再現可能な JSON の結果を返します。
主な機能
- 01TypeScript、JavaScript、Python、Java、C#、Go、Rust の解析
- 02フロントエンド呼び出しとバックエンドルートの連結
- 03リスク、デッドコード、リファクタリング候補の特定
- 04再現可能な JSON 結果の出力
- 05MCP サーバーまたは CLI で実行
- 06設定作成用の契約リソースを提供
活用シーン
- 01コーディングエージェントにリポジトリ概要を渡す
- 02バックエンドルートに届かないフロントエンド呼び出しの特定
- 03CI で重大度しきい値付きの検査を実行
MCP 対応
`zzop-mcp` バイナリは stdio 経由で分析ツールと `zzop://contract/*` リソースを MCP クライアントに公開します。CLI と同じエンジンおよびハンドラーを使用します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
翻訳後に原文が更新されています。最新の内容は原文をご確認ください。
zzop(ゼロ・ゾーン・オブ・ペイン)
AI コーディングエージェントはコードベース全体を読めません。zzop が読み取り、毎回同じように回答します。
zzop にリポジトリを1つ、またはフロントエンドとバックエンドをまとめて指定すると、実際に何があるかを説明する単一の JSON ドキュメントを返します。どのフロントエンドの呼び出しがどのバックエンドのルートに到達するか、何にも到達しないものはどれか、リスクがありそうなものは何か、使われていないものは何か、最初にどこをリファクタリングすべきか、そして今回の実行で確認できなかったことを示します。エージェントは、開く余裕があったわずかなファイルから推測するのではなく、その結果を出発点にできます。
zzop はコードを書きません。コードジェネレーターが作業の基盤とする「理解」を正確かつ再現可能にします。同じコミットを入力すれば、バイト単位で同一の分析結果が得られるため、エージェントが書くものは不完全な読み取りから推測した内容ではなく、コードの実際の動作に基づきます。改善する対象は能力ではなく、理解です。
問題が起きる様子を見る
**ルートを壊してみる**では、1回の変更による結合軸の変化を確認できます。これはこのツールが報告する4つの項目のうちの1つで、ほかの方法では特に見つけにくいものです。コードも型も共有していないフロントエンドとバックエンドのペアで、バックエンドのルート名を1つ変更します。フロントエンドは引き続きコンパイルでき、テストも引き続き通ります。それでも zzop は、問題が起きた両端をファイル名と行番号とともに示します(ここでは短縮版を示しています。デモページでは実行時の形式を確認できます)。
=== unprovided consumes ===
"PUT /api/user" @ fe-vite src/pages/Settings.jsx:19 ← the call now hits nothing
=== unconsumed provides ===
"PUT /api/users/me" @ be-express src/app/routes/auth/auth.controller.ts:61 ← the route nobody calls
**数秒で実行できます。**このリポジトリに同梱されているペアを使うため、取得するものはありません。デモ用ペアはこのリポジトリにコミット済みなので、このリポジトリをクローンすれば入手できます。
git clone https://github.com/eezz4/zzop && cd zzop
bash docs/demo/break-a-route-shipped.sh # needs a zzop binary and node, nothing else
スクリプトは target/release/ 内のバイナリ、または PATH 上の zzop を探し、どちらも見つからない場合は入手方法を案内します。一時コピーを分析し、docs/demo/pair/ は編集しません。
各ステップの結合状態を出力するのではなくアサーションで検証するため、正しくなくなった主張を説明してしまうのではなく、失敗します。CI では main へのプッシュ時とプルリクエスト時に実行されます。開発ブランチでは、これを確認するのが scripts/ci-local.sh の役割です。
ページ自体は、同じ変更を2つの独立して作成されたリポジトリで確認する説明付きのウォークスルーです。すべてのコマンドとその出力が記載されているため、何も実行せずに最初から最後まで読めます。その裏側にあるスクリプト docs/demo/break-a-route.sh は、初回実行用のコマンドではなくメンテナー向けのツールです。cargo のサンプルをビルドするため、リリース済みバイナリではなくソースをチェックアウトしたものが必要です。また、corpus/oss/fe-vite と corpus/oss/be-express にある、自分で用意した2つのリポジトリを分析します。corpus/oss/ は gitignore の対象で、このリポジトリにはそれらのツリーは含まれていません。再配布できないサードパーティーのチェックアウトだからです。コーパスの持ち込み方についてはCONTRIBUTING.mdを参照してください。(作成した合成コーパスは cases/ にコミット済みです。ただし、そのうち1つのフィクスチャだけは例外です。実際のベンダートークンのリテラルを含める必要があるため、そもそもコミットできません。README では、それによってベンチマークスコアにどのような影響があるかを説明しています。)
2つのバイナリのうち、どちらが必要ですか?
zzop は Node.js 不要の2つのバイナリとして提供されています。インストールする前に、必要なものを選んでください。
| 必要なもの | 使用するもの | 操作方法 |
|---|---|---|
| リポジトリについて質問に答える AI エージェント(Claude Code、Claude Desktop、任意の MCP クライアント) | zzop-mcp — stdio 経由の MCP サーバー | プラグインまたは .mcpb バンドルをインストールすると、エージェントがツールを呼び出します。コマンドの実行は不要です。→ Claude Code で使用する |
| ターミナル、CI ジョブ、スクリプトで自分で分析を実行すること | zzop — 通常の CLI | ツリーごとに一度 zzop init を実行し、その後 zzop analyze . または zzop cross --config … を実行します。JSON は stdout に出力されます。→ ターミナルまたは CI で使用する |
どちらのバイナリも、同じエンジン上で同じ共有ハンドラーを呼び出すため、同じパスを対象にした場合、ツール呼び出しと CLI の実行結果は一致します。どちらもネットワークリクエストを一切行いません — HTTP への依存関係もありません(プライバシー)。
- ドキュメントサイト:https://eezz4.github.io/zzop/(
site-src/で作成し、scripts/gen-site.mjsで生成します。site/はコミット済みの出力で、手作業による編集はガードによって拒否されます) - ドキュメント(リポジトリ内):
docs/README.md - 詳しい仕組み:
docs/ARCHITECTURE.md - 外部パーサープロトコル:
docs/NORMALIZED_AST.md
クイックスタート
どちらのバイナリにも Node.js、npm、コンパイラーは必要ありません。次の4つの方法のいずれかで入手できます:
- バイナリをダウンロードする。 GitHub Releasesから、お使いのプラットフォーム向けの
zzop-cli-<platform>[.exe](CLI)および/またはzzop-mcp-<platform>[.exe](MCP サーバー)のアセットを取得し、そのまま実行するか、PATHに配置してください。各リリースには、これらすべてのアセットを対象とするSHA256SUMSアセットも含まれています。⚠ 古いピンでは、ダウンロードできるリリースが存在しない場合があります — どのタグにアセットが含まれるかを唯一定めているVERSIONING.mdの*「Breaking in the current0.x」*を参照し、アセットがないものはソースからビルドしてください。(以前のこの文には、アセットが「v0.30.0以降」に存在すると書かれ、古いピンでは確認するよう案内されていました。その両方とも、2026-09-23の履歴書き換え前に書かれたもので、現在は当てはまりません。v0.30.0からv0.34.0までのタグについては、リリース自体がなくなっているため、確認するものはありません。)sha256sum -c SHA256SUMS --ignore-missingで検証してください。sha256sumのないmacOSでは、shasum -a 256 -c SHA256SUMS --ignore-missingを使います。この検証の範囲は限定的であることを明記しておく価値があります。ダウンロードの破損を検出し、別の経路でダイジェストを入手した人が利用できるようにするものです。リリースの配布元が侵害された場合には対応できません。アセットを差し替えられる攻撃者は、その隣にあるSHA256SUMSも差し替えられるためです。また、TLSはすでにMITMを拒否します。 各プラットフォームで実際にどこまで検証されているかは異なります。どれを選ぶか決める前に知っておく価値があります。 テストスイートはLinux x64でのみ実行されます。各リリースビルドでは、Windows x64、macOS arm64、Linux x64でversionを実行し、マニフェストと照合するスモークテストが行われます。クロスコンパイルされた2つのターゲット(macOS x64、Linux arm64)は、ビルドしたランナー上では実行できないため、スモークテストは一切行われません。つまり、macOSとWindowsで確認されているのはバイナリの読み込みとリンクであり、解析の動作はLinuxで確認したうえで、同様に動作すると想定しています。エンジンにはプラットフォーム固有のコードパスが1つしかないため、この想定には妥当性がありますが、保証ではありません。その例外は、この想定が最も当てはまりにくいケースなので、ここで明記しておく価値があります。crates/summary/src/siblings.rsでは、Windows上でディレクトリ名の大文字と小文字を区別せずに処理します。そうしないと、大文字と小文字を区別しないファイルシステムで、解析したルートが解析していない兄弟として報告されるためです。この処理のWindows側は、どこでも一度も実行されていません。スイートはLinux上で動作し、この処理は実行されません。また、開発者のMacでももう一方の処理をテストできません。APFSはデフォルトで大文字と小文字を区別しないため、その理由でテストが自身をスキップするからです。スキップ時の理由はソースに記載されています。再確認するには、次を実行してください:git grep -nE 'cfg!?\(\s*(not\()?\s*(windows|unix|target_os|target_family)' -- 'crates/**/*.rs' 'parser/**/*.rs' 'rules/**/*.rs' 'packages/**/*.rs' - Claude Codeプラグイン。
/plugin marketplace add eezz4/zzopを実行し、続けて/plugin install zzop@zzopを実行してください — 詳しくは下記のClaude Codeでの使用を参照してください。(Windowsでは、インストールフックにPOSIXシェルが必要です。サポートされている方法はGit for Windowsを使うことです。詳しくはpackages/README.mdを参照してください。) - Claude Desktop。 ワンクリックの
.mcpbバンドル(ドラッグ&ドロップでインストール)です — インストール前にインストーラーが知っておくべきこと(更新は手動、macOSでは署名のないバイナリがGatekeeperにブロックされる想定であること、プライバシーに関する説明)はpackages/mcpb/BUNDLE-README.mdにあります — v0.32.0より後のリリースのバンドルには、このファイルが独自のREADMEとして含まれます。v0.32.0まで(v0.32.0を含む)のバンドルには含まれていません。だからこそ、ここでインストール前に案内することが重要です。 パッケージ化の内部情報については、packages/mcpb/README.mdを参照してください。 - npm。
npm i -g @zzop/cliを実行すると、上記とまったく同じzzopバイナリがお使いのプラットフォーム向けにnpm依存パッケージとして取得され、インストールされます。zzop helpに表示されるすべてのサブコマンドが、バイト単位で同じ出力を返します。必要なのは小さなランチャースクリプトだけなので、Nodeランタイムは不要で、ネイティブバイナリとの間で差異が生じる可能性のある別個のJS実装もありません。プロジェクトですでにnpmを使ってツールチェーンを管理している場合に便利です。packages/cli/README.mdを参照してください。
Claude Code で使用する(MCP プラグイン)
エージェント向けの利用方法です。zzop-mcp は MCP サーバーを内蔵した単体バイナリです。一度インストールすれば、自然な言葉で質問するだけで、エージェントがツールを選択します。
/plugin marketplace add eezz4/zzopを実行し、続けて/plugin install zzop@zzopを実行します(別々の手順です)。- 新しいセッションを開始します。初回実行時に、プラグインがプラットフォーム用のバイナリをダウンロードします。
PATHには追加されません。最初のセッションでは、まだ zzop ツールは一覧に表示されません。ダウンロードが完了する前にツール一覧が確定するためです。Claude Code を一度再起動すると表示されます(フックも標準出力でそのように通知します)。インストール後、新しいリリースがある場合は通知されますが、気づかないうちにインストールされることはありません。
サーバーは、ツール analyze_repo、cross_repo、check_file、check_endpoint、check_coverage、module_map、analyze_envelope、validate_envelope、validate_rule_pack を公開します。また、作成時の契約を含む zzop://contract/* リソースも公開します。これらには、エンベロープスキーマ、DSL リファレンス、ルールカタログ、設定項目、注釈付きのスターター設定などが含まれ、バイナリだけでアダプターやルールパックを作成できます。zzop-mcp 自体には分析用のサブコマンドはありません。引数なし、または mcp を指定すると stdio でサービスを提供し、それ以外に使える形式は version と help のみです。
インストール、ツール、リソースの詳細についてはpackages/README.mdを、引数の正確な形式についてはdocs/modules/mcp.mdを参照してください。
ターミナルまたは CI で使用する(zzop CLI)
人間向けの利用方法です。zzop.config.jsonc を作成し、ESLint と同じ要領で実行します。設定は必須です。設定ファイルがないツリーでは、どちらのバイナリでも、すべての分析処理が拒否されます。設定がないと、zzop がプロジェクトについて推測することになる名前(認証ガードの呼び名や、生成ファイルを示すバナーなど)は設定ファイルに記述するものであり、宣言されていないキーについて zzop は判断を下さないためです。
zzop init # write the starter config — do this first, once per tree
zzop analyze . # analyze one repo/tree -> JSON findings summary
zzop analyze --config ci/zzop.config.jsonc # same, for a config that does not sit at the tree root
zzop analyze . --severity critical --limit 10 # narrow the findings LIST (counts always cover everything)
zzop cross --config zzop.config.jsonc # cross-layer join, driven by that config
zzop analyze . --fail-on critical # THE CI GATE: exit 3 when anything at/above that severity exists
zzop <subcommand> --help # that one subcommand's own line (exit 0); `zzop help` prints them all
サブコマンド一覧の正式な情報源は zzop --help です。この README には重複して記載していません。
指定がなければ、終了コードは 0 です。 --fail-on を指定しない場合、実行結果は「zzop が実行されたか」だけを示すため、重大な問題が多数あるツリーでも終了コードは 0 です。指定した場合は、名前で指定した重要度以上の検出結果があると終了コード 3 になります(3 番目のコードなので、CI ログ上で設定の不備を示す 1 と実際の検出結果を区別できます)。ただし、結果全体は引き続き標準出力に出力されます。この段落ではなく、ビルドの動作を確認してください。zzop analyze . --fail-on critical; echo $? を実行します。--rule の ID が一致しないことを証明できる場合の 2 を含む、終了コードの一覧はdocs/getting-started.mdに記載されています。
実行すると、分析対象のツリーに書き込みます。 初回の分析時に、設定と同じ場所に .zzop/cache/(既定の cacheDir)が作成され、ファイルごとの分析キャッシュが保存されます。これは派生データのみで、安全に削除でき、次回の実行時に再生成されます。小さいままではなく、ツリーの規模に応じて増加します(du -sh .zzop で容量を確認できます。このリポジトリの値は、実行ごとに変わるため、ここに記載するほどのものではありません)。zzop init を実行すると、そのディレクトリの .gitignore に **/.zzop/ の行が追加されます。何も書き込まないようにするには、"cacheDir": null を設定します。
契約の経時的な差異を追跡するには、ある時点の状態だけでなく、構造マニフェストをコミットし、後の実行結果と差分を比較します。形式はリントのベースラインファイルと同じで、zzop ではなく利用者が管理します。
zzop manifest ./api ./web > contracts.json # identity only: provides/edges/bucket membership
zzop diff contracts.json contracts.new.json # read `transitions` first — a key that left `edges`
# for `unprovidedConsumes` is a broken contract
zzop facts ./api ./web > facts.json # post-assembly facts (per-tree CommonIr + the whole join,
# uncapped) for your own rule program
zzop graph ./api ./web > join.mmd # the cross-layer join as mermaid, for any renderer —
# scoped with --scope/--top, every cap disclosed in the file
zzop graph . --domain dep > imports.mmd # the FILE import graph instead — cycles drawn as hexagons
# with thick arrows, from the engine's own circular findings
zzop graph . --domain risk > risk.mmd # blast-radius hubs + extraction seams. The health SCORES
# are NOT drawn — a table of numbers is not a graph
zzop graph . --domain posture # the mutating attack surface and its guard status —
# a box means GUARDED-OR-EXEMPT, never proven guarded
zzop graph . --domain cochange > churn.mmd # which files keep changing TOGETHER, from git history —
# not imports, so it finds the coupling no dep graph can see
zzop graph . --domain dep --fold 2 # the SAME import graph with each path's first 2 segments
# drawn as one box — the module map you were trying to see
# IS the picture, and every edge says how many file edges
# it collapsed. --fold 1 for the top-level view
zzop map . --fold 2 # the same folding as DATA, not a picture: one row per
# module with its files, lines and the imports between
# modules. `--fold` is the only knob (NOT --depth, which
# is git's), and `moduleEdges` counts edges BETWEEN
# modules while `fileImports` counts every file-level one
大規模なリポジトリでは数分かかり、上記の各コマンドは完了するまで何も書き出しません。
進捗は表示されません。応答は1つのドキュメントとして組み立てられてから書き出されるため、途中で中断すると部分的な回答ではなく0バイトになります。処理中はハングしたようにしか見えません。このプロジェクト独自のコーパスで計測したところ、3,800ファイルのツリーは数秒、24,000ファイルのモノレポでの zzop facts は約50秒で10.8 MB、ASP.NET規模のツリー(17,000ファイル、解決済みインポートエッジ1.26M件)での analyze は約8分です。⚠ これらは浅いクローンでの数値であり、あなたのツリーはおそらくそうではありません。 元となったコーパスのツリーにはそれぞれコミットが1つだけ含まれていました(git -C corpus/frameworks/aspnetcore rev-list --count HEAD → 1)。そのため、これらでは git の処理にコストはかかりませんでした。履歴のあるリポジトリでは、それがほかのすべてを上回ることがあります。docs/modules/mcp.md には、16,485コミットのツリーにおいて、すべての分析に13秒かかったのに対し、git log --numstat に548秒かかった記録があります。つまり、この数値には含まれていなかった要因によって、処理量は42倍です。ファイルにリダイレクトして、完了するまで待ってください。上限が必要な場合は、呼び出しを独自の timeout で囲み、強制終了された場合は正常な結果ではなく、回答なしとして扱ってください。
マニフェストには意図的に上限を設けておらず、ファイルや行の情報も含まれません。そのため、純粋なリファクタリングでは差分が空になり、サマリーの上限を超えていても、結合から外れたルートが隠れることはありません。diff は --allow-tool-drift を渡さない限り、異なる zzop ビルドのマニフェストを拒否します(渡した場合は、そのドリフトを明示します)。また、カバレッジを失ったソースに起因する削除には、削除と断定する代わりに blindnessSuspect のタグを付けます。
この拒否の仕組みによって、マニフェストの有効期間は1リリースになります。 tool にはリリース番号、8つすべてのパーサーフィンガープリント、エンジンのフィンガープリントが含まれるため、使っている機能に変更がないリリースでも、リリースごとに変わります。そのため、次のアップグレードでコミット済みのベースラインは期限切れとなり、zzop manifest を再実行して再コミットする作業もアップグレードの一部になります。--allow-tool-drift は、自分で解釈すると決めた単発の比較に使ってください。常用は避けてください。両ファイルのマニフェスト形式が同じかどうかを確認する唯一の手段でもあります。ほかには、行の形状を比較するものがないためです。
カスタムルールの拡張ポイントにおけるもう一方、つまりコンシューマー側で使う上限のない経路が facts です。DSLでルールを表現できない場合、zzopは組み立てとレイヤー間結合の後に把握しているすべての情報を出力します。各ツリーの CommonIr 全体と、結合バケットすべてがそのまま出力され、何を問題とみなすかは独自のプログラムで判断します。zzopはそのプログラムを実行せず、その検出結果を読み込むこともありません。出力形式については、docs/modules/facade.md を参照してください。manifest、diff、facts、graph、explain、init はCLI専用の経路であり、対応するMCPツールはありません。
そのほかの機能:analyze-envelope、validate-envelope、validate-rule-pack、endpoint、file(zzopが1つのファイルについて把握しているすべての情報。ツリー、シンボル、I/Oファクト、双方向の依存関係エッジ、そのファイルに紐づくすべての検出結果を含みます。判定結果には、そのファイルが解析されたかどうかが示されるため、構造解析の対象になっていないファイルの検出結果リストが空でも「問題なし」と誤解されることはありません)、init(注釈付きのスターター zzop.config.jsonc を書き出します。同じドキュメントが、MCPでは config-template リソースとして提供されます)、contract、explain、version、help。CLIと設定の全リファレンスについては、packages/README.md を参照してください。
どちらのバイナリも実行せずにエンジンを組み込むには、zzop-facade/zzop-summary クレートのJSON入出力コントラクトを直接呼び出してください。これらはワークスペース内でのみ使用され、crates.ioには公開されていないため、インプロセスのRust依存として使うには、このワークスペースをベンダリングする必要があります。cargo add では追加できません。CLIのJSONサブコマンドをシェルから呼び出す場合、リンクは一切不要です。
let report: serde_json::Value =
serde_json::from_str(&zzop_facade::analyze_json(r#"{"root":"."}"#)?)?;
結果(抜粋)
上記の2つのバイナリが実際に出力する内容は次のとおりです。findings は配列ではなくセンサスオブジェクトです。応答が生のダンプではなく、構造化された要約だからです。以下の数値は、このリポジトリ自身の cases/trees/api-be フィクスチャに対して、このチェックアウトからビルドした zzop で測定した実行結果です。実行コマンドは zzop analyze --config cases/trees/api-be/zzop.config.jsonc です。
どのバイナリで再現したかも、主張の一部です。 zzop version はリリース番号だけを出力し、main はリリース間でその番号を維持します。そのため、インストール済みの @zzop/cli とこのチェックアウトのビルドは、どちらも 0.35.0 と表示しながら、同じバージョン文字列の異なるビルドなので、正当に異なる検出結果を報告することがあります。見分けるには zzop version --verbose を実行してください。各パーサーのフィンガープリントとエンジンハッシュが表示されます。数値が以下のブロックと異なる場合、どちらかが間違っていると決めつける前に、この行を比較してください。
(次の編集者へ:これらの数値は cases/trees/api-be が変更されるたびに、また、測定対象がリリースによって変わるたびにも変わります。2つ目には、目立つ変更だけでなく、すべてのルール変更が含まれます。コマンドを再実行して再測定してください。数値を1つだけ修正してはいけません。このブロックは、マシンで固定できるまでに4回古くなりました(2026-08-11、08-15、08-21、09-02)。4回目は v0.34.0 で、すべてのガードがグリーンの状態でリリースされました。現在は固定されています。scripts/measure/readme-result-block.sh は、このチェックアウトから zzop をビルドして実行し、ブロック内のすべての数値を比較するため、不完全な編集はリリース前に CI で失敗します。手作業で修正して表示を信じるのではなく、必ず再実行してください。
同じ日に、外部の読者がこのブロックについて 87/73 という結果を報告しましたが、古い README を読んでいたわけではありません。公開済みの @zzop/cli 0.33.0 で測定しており、同じバージョン文字列の別のビルドだったため、正当に異なる結果になりました。そのための説明が、上の段落です。以下の disclosure 行は意図的に数値から外しています。独自のコメントを参照してください。)
pain は単独では意味をなしません。painMeasuredWeight / painTotalWeight は、このツリーで重みテーブルのうち実際に測定できた範囲を示し、pain: null は、いずれのメトリックにも母集団がなかったことを意味します。データがないのであって、問題がないという意味ではありません。
また、pain は欠陥スコアではありません。 ルールに関する検出結果は一切含みません。以下の実行結果では検出数が101件、そのうち重大度が critical のものが7件ありますが、defect の pain は 0 です。painByAxis は、この点が暗示ではなく明示されるよう数値を分けています。defect(循環インポート。唯一の項目)、opinion(バレルの規律、FSD レイヤリング、SDP/Main Sequence、Newman モジュラリティ、LOC の上限。意図的に逆の方針を取るプロジェクトが間違っているわけではなく、スコアが低くなります)、history(名前変更の頻度、バスファクター)です。この3つはそれぞれ pain と同じ尺度を持ち、合計すると pain の値になります。欠陥を調べるには findings を、コードの構成に対して zzop がどの程度異なる見解を持つかを調べるには pain を参照してください。
{
"fileCount": 98,
"findings": {
"total": 101,
"bySeverity": { "critical": 7, "warning": 59, "info": 35 },
"byRule": { "security/weak-crypto": 6, "db/unawaited-write": 1 },
"shown": [ /* 50 here — the listed slice, capped by --limit; each entry has ruleId, severity, file, line, message */ ]
},
"architecture": { "pain": 7.5, "painMeasuredWeight": 13.8, "painTotalWeight": 18.6,
"painByAxis": [ { "axis": "defect", "pain": 0.0, "totalWeight": 3.0 },
{ "axis": "opinion", "pain": 7.4, "totalWeight": 15.0 },
{ "axis": "history", "pain": 0.0, "totalWeight": 0.6 } ],
"topRecommendation": null, "criticalTop": [],
/* + painMeaning / topRecommendationMeaning / criticalTopMeaning: the sentences
that say what each of the three above is, and is NOT, on the wire */ },
"coverage": { /* how much of the tree zzop actually saw, per extension */ },
"coverageGaps": { /* which principal extensions reached no resolved import edge, always present —
each row's `kind` ("source", "data-config", "unclassified") says whether the zero
means a missing parser or a filetype you have to open to judge */ },
"disclosure": { /* the census of zzop's OWN known silent-failure classes, keyed
classes / asserted / partial / notYetDetected, plus the `note`,
`command` and `resource` that lead to the full text. No counts are
copied here: the reply carries its own, and the two that were copied
here went stale while the two beside them stayed right — which is
indistinguishable from correct until someone re-runs it. Read them
with `zzop contract disclosure-classes`, the command the field itself
names. */ },
"warnings": [ /* anything this run could not provide */ ]
}
すべての検出結果には、ルール ID、重大度、file:line 形式の位置、メッセージが含まれます。レコード自体は shown に格納されています。メッセージは通常、ルールの説明ではなく参照先です。ルール自身が文面を定義している検出結果では、代わりに messageBy フィールドが含まれます。その場合、該当する検出結果の ruleId を使って全文を確認してください(zzop explain <ruleId> または MCP リソース zzop://rule/{id})。設定でその検出結果を抑制するキーも、ここに記載されています。文面ではなく messageBy フィールドを確認してください。応答自体にも findings.messageByIdMeaning と記載されています。bySeverity / byRule は常に実行全体の件数を集計するため、--limit でリストを短縮しても変わりません。この分割が、findings がオブジェクトである理由です。
メトリックごとの scores ブロック、health オブジェクト、recommendations は、このワイヤー形式には含まれません。構造化された要約では、これらを上記のコンパクトな architecture オブジェクトにまとめています。完全な形式で利用できるのは zzop-facade の埋め込み経路(zzop_facade::analyze_json、すぐ上のスニペット)だけです。この経路独自の形式については、docs/modules/facade.md を参照してください。
analyzeTrees(複数ツリー)ではさらに、フロントエンドの fetch とバックエンドのルートを結合した crossLayerFindings も返します。これは単一ツリーに相当する機能はありません。
仕組み
各リポジトリは言語に依存しない 1 つの IR に解析されるため、Python のルートも TypeScript の fetch も、同じ種類の事実として扱われます。中心となるのは、リポジトリをまたいだ結合です。フロントエンドの呼び出しをリポジトリの境界を越えてバックエンドのルートと完全一致で照合し、残ったものも見落とさず、理由を示します。大文字小文字やベースパスの違い、バージョンのずれ、メソッドの不一致は、それぞれ異なる要素を明記したニアミスの検出結果として返されるため、手作業で差分を確認する必要はありません。ニアミスの判定は、表記ではなく、こうした軸に基づきます。複数形や誤字(/api/users に対する /api/userss)は、意図していると思われるルートとは対応付けず、一致しない呼び出しとして報告されます。ルールごとの対象範囲はカタログに記載されています。結合と並行して、同じエンジンが階層型ルールシステム(グラフ全体を対象としたネイティブ解析と宣言型 JSON ルールパック)を各リポジトリに個別に適用し、構造上の検出結果、依存関係/デッドコード分析、健全性スコアを同じ JSON ドキュメントに追加します。
実行結果は常に決定論的です。同じコードを入力すれば、常に同じ検出結果が得られます。2 回の実行結果を互いに比較できるほど、バイト単位で安定しています。そのため、zzop は CI ゲート(JSON の重大度別件数を読み取り、コントラクトのずれがあれば PR を失敗させる)としても、エージェントが変化する回答に振り回されることなく再実行できる基盤としても利用できます。同じくらい重要なのが、実行結果に自身の盲点が示されることです。warnings とツリーごとの coverage 集計から、実行されなかった処理がわかるため、検出結果が少ない理由がエンジンの未対応によるものかどうかを見分けられます。
設計の全容は、docs/ARCHITECTURE.mdを参照してください。出力の読み方、重大度の意味、抑制については、docs/getting-started.mdを参照してください。スタックがデフォルトと一致しない場合(独自拡張、独自のガード名、ゲートウェイのプレフィックス、未実装のルールなど)は、docs/extending.mdに、利用時にたどる順にすべてのプラグイン拡張ポイントが記載されています。
サポート対象の言語
| 言語 | サポート |
|---|---|
TypeScript / JavaScript (.ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts) | ネイティブ対応、完全な AST(swc):シンボル、インポート、呼び出し、HTTP ルート/外部送信、TypeORM @Entity/@Column の db-table 提供(スキーマ側。クライアント側の消費と結合)、ORM アクセサーおよび生の SQL 文文字列からの db-table 消費 |
Python (.py, .pyi) | ネイティブ対応、完全な AST(ruff、Python 3 — Python 2 専用構文は字句解析にフォールバック):シンボル、インポート、FastAPI ルート提供、Django URLconf ルート提供(urlpatterns の url()/re_path()/path() エントリーと、ファイルをまたぐ include('<dotted.module>') のマウント。メソッドはビュークラス内にあるため、出力される動詞は不明)、requests/httpx の消費(モジュールレベルの呼び出しに加え、Session/Client/AsyncClient インスタンス)、SQLModel/SQLAlchemy および Django ORM の db-table 提供とクエリ箇所での消費、呼び出し箇所、認証ガードの証拠(FastAPI Depends + DRF permission_classes)— v1 の対象範囲 |
Rust (.rs) | ネイティブ対応、完全な AST(syn 2):シンボル、インポート/mod ツリー(同一ワークスペース内のクレート解決を含む)、axum ルート提供、reqwest の消費、生の SQL による db-table 消費(sqlx/tokio-postgres/rusqlite など)、リポジトリ全体の呼び出しグラフのための呼び出し箇所、エクストラクターに基づく認証ガードの証拠 — v1 の対象範囲 |
Go (.go) | ネイティブ対応、完全な CST(tree-sitter-go 0.25):シンボル、インポート/依存関係グラフ(go.mod によるモジュール解決、パッケージディレクトリ全体にわたるエッジ)、gin + net/http のルート提供(ファイルをまたぐマウント合成 — 別ファイルの呼び出し箇所からマウントされる関数パラメーターのルーター — Go 1.22 の "METHOD /path" マルチプレクサー構文を含む)、net/http のリテラルな外部送信の消費(パッケージのフリー関数とバインドされた http.Client 値)、GORM の db-table ファクト、呼び出し箇所 — v1 の対象範囲 |
Java (.java) | ネイティブ対応、完全な CST(tree-sitter-java 0.23.5、Java 21 文法):シンボル(ネストされた型、ドット修飾されたメソッド名、実際の可視性を含む)、インポート/依存関係グラフ((package, type) でインデックス化された解決、パッケージディレクトリ全体にわたるグロブエッジ)、Spring MVC ルート提供(ファイルをまたぐ extends チェーン + 定数プレフィックスの解決)、RestTemplate/WebClient のリテラルな外部送信の消費(Feign と java.net.http は認識されません。RestTemplate.put/.delete は、Map.put に誤ってキー付けされる汎用名であるため、意図的に認識されません — この制限は明示されています)、JPA @Entity/@Table の db-table 提供、呼び出し箇所、Spring Security の認証ガードの証拠(@PreAuthorize/@PostAuthorize/@Secured/@RolesAllowed)— v1 の対象範囲 |
C# (.cs) | ネイティブ対応、完全な CST(tree-sitter-c-sharp 0.23.5):シンボル(ネストされた型、ドット修飾されたメソッド名、public の可視性を含む)、インポート/依存関係グラフ(名前空間→ファイルのインデックス、パッケージディレクトリ全体にわたる using エッジ)、ASP.NET Core ルート提供([Route("api/[controller]")] + [HttpGet]/… を組み合わせた属性コントローラーに加え、同一ファイル内の Minimal-API app.MapGet/MapGroup)、HttpClient のリテラルな外部送信の消費、EF Core DbSet<T>/[Table] の db-table 提供、呼び出し箇所 — v1 の対象範囲 |
Prisma スキーマ (.prisma) | ネイティブ対応、字句解析によるスキーマ:モデル/フィールド(構造と使用状況を考慮したスキーマルール)+クライアント側の消費と結合する db-table 提供 |
SQL (.sql) | ネイティブ対応、字句解析:CREATE TABLE → db-table 提供(マイグレーションファイルにより、MyBatis/JDBC スタイルのスタックで db-table チャネルが有効になります)。このクレートはチャネルの消費側の文リーダーも担当し、他のパーサーが保持する SQL 文字列に対してこれを呼び出します |
| その他すべて(Ruby、JSP、...) | ツリー内での字句解析フォールバック:ファイルは走査・カウントされ、到達できるのは line-scan ルールのみです。これは上限であり、対応範囲を保証するものではありません — バンドル済みルールがその言語に到達するのは、それ自身の file_pattern が拡張子を指定している場合だけです。上記の行にないほとんどの言語では、該当するルールがないため、この行では意図的に数値で示していません(言語ごとに異なり、変化します)。代わりに、実際のツリーで測定してください:zzop analyze <tree> を実行し、packsLoaded[].filesInScope を確認します — パックの値が 0 なら、そのパックのルールのパス条件に該当するバイト列が一つもないことを意味します。そのため、そのパックで検出結果がゼロでも、問題がないことの証明ではなく、対象範囲外ということです — あわせて coverageGaps を確認します。そこでは拡張子に対応する行に kind: "source" が記載されています。この方法で 5 ファイルの Ruby ツリーを測定したところ、バンドル済みパックのどれも .rb ファイルを一つも対象にしませんでした。第一級のサポートは、Normalized AST プロトコルに準拠する外部パーサーアダプターによって提供されます。 |
完全精度ティアの内訳 — 各ネイティブパーサーが抽出する内容、Python の v1 スコープに関する注記、各パーサーのフィンガープリントについては、docs/ARCHITECTURE.md をご覧ください。(これらのフィンガープリントは zzop version のデフォルト出力には含まれません。スクリプトが1つのトークンを解析できるよう、リリース番号のみを出力するためです。zzop version --verbose と、同一の文字列を出力する zzop-mcp version --verbose では確認できます。また、zzop manifest の tool フィールドにも、アーティファクト内に同じ文字列が含まれます。) |
Rust には、ほかのどの言語にもないレポート規則があります。#[cfg(test)]/#[test] が適用された項目の内部に行がある検出結果は除外されます。Rust の単体テストはリリース対象ファイル内に置かれるため、ほかのすべての言語が利用するパス名ベースのテスト除外(foo.test.ts、tests/test_foo.py)では検出できないからです。保存時の認証情報に関するルールは例外で、コンパイラーがその領域を残すかどうかにかかわらず、コミットされたキーは漏えいしているとみなして判定を続けます。その旨は各ルールのカタログ行に記載されています。両方については、docs/rules/catalog.md をご覧ください。
ネイティブパーサーのない拡張子を持つ通常サイズのファイルは、出力の warnings にも自己申告されます。拡張子、ファイル数、パスのサンプルが示されるため、黙って見落とされることはありません。その言語が分析に必要な場合は、アダプター(zzop.config.jsonc の overlays: [...])を指定してください。
バージョン管理と安定性
zzop は 1.0 より前(0.x)であり、不安定です。どのリリースでも動作、出力、ルール、デフォルト設定が変わる可能性があるため、正確なバージョンを固定し(^/~ の範囲指定ではなく)、アップグレード前に再テストしてください。セマンティック バージョニングは 1.0.0 から始まります。それまでに保証される範囲はより限定的で、変更の頻度ではなく記録に関する保証です。VERSIONING.md に記載された対象のいずれかに破壊的変更があった場合、変更前後の表記を両方とも CHANGELOG.md に記録します。VERSIONING.md では、対象の内部で変更が続いている特性 — ルール ID、SourceSymbol.id の一意性、ネイティブ ID の名前空間 — についても明示しており、実行結果から推測する必要はありません。
構成と開発
コントリビュートを検討している方、またはクレートの構成を知りたい方へ。CONTRIBUTING.md には、クレートごとの責務一覧と、ビルド/テスト/計測用のコマンドの両方が記載されています。このページは zzop の採用を決めるために読むものであり、依存関係グラフはインストール前に誰も尋ねない内容への答えだからです。これらの情報は、そのためこのページではなく CONTRIBUTING.md にあります。
ライセンス
MIT — LICENSE をご覧ください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。