abcop について
abcop は、AI が生成したコードや開発チーム向けの単体コード複雑度チェッカーです。多言語の関数・モジュールの ABC 複雑度を判定し、具体的な診断とエージェント向け MCP 検査ツールを提供します。
主な機能
- 01関数とモジュールの ABC 複雑度を判定
- 02単一バイナリで多言語を解析
- 03テキスト、JSON、JSONL の診断を出力
- 04変更されたコードを中心に検査
- 05単回使用・未使用のローカル変数を検出
- 06MCP 検査ツールを提供
活用シーン
- 01CI に複雑度チェックを追加
- 02コード変更による複雑度を確認
- 03エージェントに具体的なリファクタリング情報を提示
- 04エージェントの編集中にコード指標を検査
MCP 対応
`abcop --mcp` を実行すると、stdio 経由で MCP サーバーを起動します。`abcop_inspection` ツールが AI クライアントに検査結果を返します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
abcop
AI が記述したコードに欠かせないゲートです。 エージェントの出荷速度は、人間がコードを読み返す速度を上回ります。abcop は関数とモジュールの ABC 複雑度をゲートすることで、すべての単位が人間の理解力と LLM のコンテキストウィンドウに収まるようにし、コードを理解しやすい状態に保ちます。診断結果は、メソッドの抽出やモジュールの分割といった自動リファクタリングのきっかけにもなります。CI は望ましくない肥大化を拒否するだけでなく、保守性を高める具体的な修正方法をエージェントに示します。
Ruby、Rust、Python、Go、PHP、Java、C#、Dart、JavaScript、TypeScript、C、C++、Objective-C、Swift、Solidity、Zig、Haskell に対応した、自己完結型の単一バイナリです。 ランタイム、プラグイン、言語ごとのインストールは不要です。速度を重視して Rust で記述されており、ファイルごとの解析は 1 回、メトリクスごとの走査も 1 回だけで、文法は組み込み済みです。ツリー全体をミリ秒単位で処理できます。
インストール
brew install adrianov/abcop/abcop
cargo install abcop
macOS(GitHub Releases の .tar.gz。バイナリと man を同梱):
# Apple Silicon — use the *-x86_64-apple-darwin.tar.gz asset on Intel Macs
curl -LO https://github.com/adrianov/abcop/releases/download/v0.23.0/abcop-0.23.0-aarch64-apple-darwin.tar.gz
tar -xzf abcop-0.23.0-aarch64-apple-darwin.tar.gz
sudo cp abcop-0.23.0-aarch64-apple-darwin/abcop /usr/local/bin/
sudo mkdir -p /usr/local/share/man/man1
sudo cp abcop-0.23.0-aarch64-apple-darwin/abcop.1 /usr/local/share/man/man1/
Ubuntu / Debian(GitHub Releases の .deb。amd64、Ubuntu 22.04+ / Debian bookworm+):
# example for v0.23.0 — use the asset name from the release page
curl -LO https://github.com/adrianov/abcop/releases/download/v0.23.0/abcop_0.23.0-1_amd64.deb
sudo dpkg -i abcop_0.23.0-1_amd64.deb
man abcop
実行例
lib/sinatra/base.rb:1254:0: C: Metrics/AbcSize: Assignment Branch Condition size for `error_block!` is too high. [<7, 14, 9> 18.06/17]
src/main.rs: W: Metrics/ModuleAbcSize: Assignment Branch Condition size for module is too high. [<80, 200, 60> 228.04/120] -- extract a coherent subunit
132 files analysed in 0.09s, 7 abc offenses, 0 used-once offenses, 0 never-used warnings, 14 module-abc warnings
行数ではなく ABC を使う理由
行数は実態を反映しません。ABC メトリクス(Jerry Fitzpatrick、C++ Report、1997 年 6 月)は、実際に処理を行う要素、つまり代入(A)、分岐(B)、条件(C)を sqrt(A² + B² + C²) として数えます。Fitzpatrick はメソッドとモジュールの両方を対象範囲として定義しており、abcop はその両方をゲートします。
| ルール | 重要度 | 意味 |
|---|---|---|
Metrics/AbcSize | C | 関数の ABC が --max-abc(デフォルト 17)を超えています。通常のスキャンでは HEAD と比べて増加した箇所を報告します。--full と --everything では上限を超えるすべての関数を報告します |
Metrics/ModuleAbcSize | W | モジュールの ABC が --max-module-abc(デフォルト 120)を超えています。通常のスキャンでは HEAD と比べて増加した箇所を報告します。--full と --everything では上限を超えるすべての本番モジュールを報告します |
UsedOnce | W | 編集によって変更された関数内で、1 回だけ書き込まれ、1 回だけ読み取られるローカル変数です。--full と --everything では、該当するすべてのローカル変数を報告します |
NeverUsed | W | 編集によって変更された関数内で、書き込まれているものの一度も読み取られないローカル変数です。UsedOnce と同じツリー全体スキャンの切り替えオプションを使います |
簡潔なラッパーと、機能が過密な巨大オブジェクトでは、行数が同じになることがあります。ABC なら両者を区別できます。ゲートの基準は複雑度であり、行数の上限ではありません。UsedOnce / NeverUsed は補助的なルールです。
AI ワークフロー向けに構築
- 設計上、理解しやすいコード。 AbcSize 17 と ModuleAbcSize 120 により、新しい各ユニットを人の頭と LLM のコンテキストウィンドウに収まる大きさに保てます。変更によってスコアが上がらない場合、既存のユニットがこの上限を超えたままでも問題ありません。モデルは小さなユニットを確実に編集できます。何かが壊れても、影響範囲はごく小さくなります。
- リファクタリングのフック。 終了コード
1と安定した JSON/JSONL 診断情報(rule、score、vector、message)をエージェントやスクリプトに渡せます。サイズ超過のモジュールを分割したり、ホットメソッドを抽出したりできます。各指摘は、スタイル上の些細な問題ではなく、保守性を高めるための実行可能なステップです。 - あらゆるプッシュに十分な速さ。 エージェントが明日読み直すことのないコードも含め、ツリー全体を 1 秒未満でスキャンします。
- シグナルだけを出力。 フォーマットやスタイルを取り締まる機能はありません。ベンダーコード、生成コード、テストツリーはデフォルトでスキップされます。調整用オプション:
--max-abcと--max-module-abc。--fullと--everythingは現在の編集箇所だけでなく、すべての該当箇所を報告します。 - LLM では MCP を推奨。
abcop --mcpは、エージェントから abcop を使う最適な方法です。モデルはコードを書いた直後に違反を受け取るため、同じターン内で複雑さや未使用のローカル変数を修正し、後続の CLI/CI チェックを待たずに、すぐに効果的なコードを出荷できます。公式 RustrmcpSDK を使用し、ツールはabcop_inspectionです。 MCP Registry にio.github.adrianov/abcop(crates.io パッケージと各 GitHubv*タグ)として登録されています。
RuboCop(Ruby AbcSize との互換性、および # rubocop:disable ディレクティブ)と
lizard(1 つのツールで多くの言語に対応)に着想を得ています。Ruby のメソッドカウントは、RuboCop 1.89 とバイト単位で一致します(scripts/compare_parity.py)。メソッド外のブロック(match do、before do、クラスレベルの each)は独立したユニットです。each/map/select は引き続き、それらを含むブロックに加算されます。
利点
- コアあたり約 850k~940k LOC/秒(Apple M1 Pro)。RuboCop の lib ツリー(943 ファイル、110k LOC):0.13 秒 —
rubocop --only Metrics/AbcSizeより約 39 倍高速(キャッシュ無効時)、rubocop 全体の実行より約 140 倍高速です。 - バイナリ 1 つ、依存関係ゼロ — 文法と組み込みの結果キャッシュ(
cache.redb)をコンパイル済みです。言語ツールチェーンのないクリーンな CI イメージでも動作します。 - 決定論的 — 実行ごとに同じ指摘が得られます。テキスト/JSON/JSONL はファイルの処理完了に合わせてストリーム出力されます。
--sort-by-scoreはスコアの高い順に出力するため、結果をバッファリングします。
使い方
abcop [OPTIONS] PATH...
| オプション | デフォルト | 説明 |
|---|---|---|
[PATH]... | 自動 | 対象。省略時は スコープ選択 |
--max-abc N | 17 | 関数の ABC 上限 |
--max-module-abc N | 120 | モジュールの ABC 上限 |
--only abc|used-once|never-used | すべて | 単一チェック |
--full | オフ | 本番ツリー全体と、上限を超えるすべての関数およびすべてのローカル変数を対象にします(デフォルトのスキップ設定は有効のままです) |
--everything | オフ | gitignore/隠しファイル/ベンダーコードの除外を無効にします(ユーザー設定の ignore は適用されます)。--full と同じ全件レポートを出力します |
--format text|json|jsonl | text | CI に適した出力 |
--sort-by-score | オフ | ABC の高い順 |
--mr | オフ | MR スコープ(未コミットの変更+ブランチとベースの差分) |
--uncommitted | オフ | HEAD に対する作業ツリー+インデックス+未追跡ファイルのみ |
--no-cache | オフ | ディスク上のキャッシュをスキップ |
--mcp | オフ | 標準入出力で MCP サーバーを起動(AI クライアント向け) |
--dump-tree FILE | — | 構文ツリーのデバッグ出力 |
終了コード:0 は問題なし、1 は指摘あり、2 は使用方法のエラーです。
abcop app lib # two trees; rises and edited functions only
abcop --format jsonl lib > abcop.jsonl # streaming CI / agent input
abcop --only used-once src # inline candidates in edited functions
abcop --max-abc 12 --only abc lib # stricter function budget
abcop --full lib # every function over the ceiling, every local
abcop --everything lib # same report, with no default pruning
abcop --max-module-abc 80 lib # stricter module budget
abcop --sort-by-score --only abc lib # worst first
abcop --uncommitted # pre-commit; rises and edited functions only
abcop --mr --only abc # branch files; still only ABC rises vs HEAD
abcop --mcp # MCP server on stdio (for AI clients)
JSON 診断情報には file、line、column、severity、rule、message が含まれます。また、ABC ルールには score/vector も含まれます。
{"rule":"Metrics/AbcSize","score":10.0,"vector":"<6, 8, 0>"}
{"rule":"Metrics/ModuleAbcSize","score":120.5,"vector":"<40, 100, 40>"}
スコープの選択
パスを指定 — 指定した対象のみです。検出結果には、以下の編集フィルターが引き続き適用されます。
省略時 — 有用な範囲のうち最も狭いものを選び、stderr に通知します。
- 作業ツリーがダーティーな場合、未コミットの変更と
HEADの差分 - それ以外の場合、現在の MR(
--mrを指定するとこちらを強制します) - それ以外の場合、作業ツリー全体(リポジトリ外の場合)
デフォルトの走査では、テスト/フィクスチャのツリー、ベンダー/ビルド出力
(vendor/、node_modules/、target/ など)、db/migrate/、ルートテーブル
(config/routes.rb、config/routes/*.rb)、生成された名前
(*.min.js、*_pb.go など)を除外します。明示的にパスを指定すれば、そのパスも走査されます。
Rails のスキーマダンプ(db/schema.rb、db/*_schema.rb、db/schema_*.rb)
は、指定した場合でも走査されません。
サードパーティー、ルートテーブル、フィクスチャのパスは、スコープ対象のレビュー範囲にはなりません。vendor/ や tests/fixtures/ を通る差分があっても、その内容は管理対象コードにはなりません。
ダーティーなツリーでは、オプションを指定しない場合、未コミットの変更のみが対象です。--mr を指定すると、ブランチ間の差分全体が対象になります。ブランチのベースを適用できない場合、main に直接コミットした変更には過去 36 時間の期間が適用されます。--uncommitted は、リポジトリ外では対象を黙って拡大する代わりにエラーになります。
通常のスキャンで報告される内容
--full と --everything 以外のすべてのスキャンでは、作業ツリーを
HEAD と比較します。
- AbcSize は、メソッドのスコアが
--max-abcを超え、かつHEADにある同じメソッド(同名、ソース順)が持つスコアより厳密に高い場合にのみ報告します。スコアが同じか下がった場合は、以前から上限を超えていたレガシーメソッドも含め、報告しません。作業ツリーにのみ存在するメソッドは、スコアが上昇したものとして扱います。HEADでのスコアがすでに上限を超えていた場合、メッセージでは以前のスコアに戻すよう求めます(rose from 20 to 21 -- back to 20 or below)。HEADでのスコアが上限未満だった場合、目標は上限になります(rose from 16.28 to 21.28 -- back to 17 or below)。 - UsedOnce / NeverUsed は、テキストが
HEADから変更された関数内でのみ報告します。編集されていない関数内のローカル変数は報告されません。関数の外にあるローカル変数は引き続き報告されます。 - ModuleAbcSize は、モジュールのファイル全体のスコアが
--max-module-abcを超え、かつHEADにあるそのファイルのスコアより厳密に高い場合にのみ報告します。スコアが同じか下がった場合は、以前から上限を超えていたレガシーモジュールも含め、報告しません。HEADに存在しないファイルには上限が適用されます。HEADでのスコアがすでに上限を超えていた場合、メッセージでは以前のスコアに戻すよう求めます(rose from 200 to 210 -- back to 200 or below)。HEADでのスコアが上限未満だった場合、目標は上限になります。 HEADの blob がない場合(Git のチェックアウトでない、または未追跡ファイルの場合)、上限を超えるすべてのメソッド、すべてのローカル変数、上限を超えるすべてのモジュールを報告します。
--uncommitted と --mr では、差分で変更されていない行にある関数およびローカル変数の検出結果も除外されます。
ツリー全体のレポート
--full と --everything では、--max-abc を超えるすべてのメソッド、すべてのローカル変数、--max-module-abc を超えるすべての本番モジュールを報告します。これらの実行でも、ModuleAbcSize はテストツリーを除外します。--full ではデフォルトの除外が適用されます。--everything では、gitignore、隠しディレクトリ、ベンダー/生成物/テストの除外を解除します。ユーザー設定の ignore は、どちらにも適用されます。
ユーザー設定
ユーザーオプションは 1 つのファイルに保存されます。環境変数が設定されている場合は $XDG_CONFIG_HOME/abcop、それ以外の場合は ~/.config/abcop です。$ABCOP_CONFIG でパスを置き換えられます。プロジェクトには何も書き込まれません。
ignore は gitignore パターンで、1 行に 1 つずつ記述します。各プロジェクトのルートを基準に、すべてのプロジェクトで適用されます。ディレクトリパターンは、その中のすべての内容を対象にします。パスを指定しても、--full や --everything を指定しても、一致するパスは対象に戻りません。一致したパスに対する MCP の検査結果は空になります。
ignore = app/services/legacy/
ignore = lib/old.rb
ディレクティブ
Rust 以外では、RuboCop スタイルの # / // 抑制が使用できます
(行末およびブロック形式。Metrics 単独も使用可能です)。rubocop:disable-next は RuboCop と同様に無視されます。
def legacy_path # rubocop:disable Metrics/AbcSize
...
end
MCP(Model Context Protocol)
LLM/エージェントのワークフローに推奨します。 abcop を MCP サーバーとして接続すると、モデルは編集中に abcop_inspection を呼び出せます。フィードバックは同じターン内に届くため、エージェントはすぐに修正でき、CI で ABC/UsedOnce/NeverUsed を初めて検出するのではなく、最初の段階から保守しやすいコードを書けます。
abcop --mcp は stdio 上で長時間稼働する MCP サーバーを起動します。RuboCop の MCPやrrubocopと同じ考え方で、Ruby の mcp gem は不要です。ツール:
| ツール | 目的 |
|---|---|
abcop_inspection | path/paths(文字列または配列)やインラインの source_code を使って解析し、簡潔な違反 JSON(code、line、column、message。ABC ルールでは score/vector も含む)を返します。通常のスキャンと同じ編集フィルターを使用します。AbcSize と ModuleAbcSize はスコアが HEAD に対して上昇した場合のみ、UsedOnce と NeverUsed は編集によって変更された関数内のみが対象です。新しいモジュールにはモジュールの上限を適用します。明示的なプロジェクトパスを必ず渡してください。対象を省略するとエラーになります(MCP の cwd が誤って設定された場合に $HOME をスキャンするのを防ぎます)。 |
- MCP Registry 名:
mcp-name: io.github.adrianov/abcop
メタデータは server.json にあり、crates.io の Cargo パッケージに含まれています。GitHub の各 v* リリースタグで、crates.io へのアップロード後に、このリストが MCP Registry に公開されます。
クライアント設定例(Cursor/VS Code/Windsurf):
{
"mcpServers": {
"abcop": {
"type": "stdio",
"command": "abcop",
"args": ["--mcp"],
"cwd": "/path/to/your/project"
}
}
}
Claude Code:
claude mcp add abcop -- abcop --mcp
対話的な使用ではなく、MCP クライアントでの使用を想定しています。
キャッシュ
コンテンツアドレス方式のキャッシュは $XDG_CACHE_HOME/abcop(または ~/.cache/abcop)に保存されます(ABCOP_CACHE_DIR で変更可能)。キャッシュが温まった後の再実行は約 5 倍高速です。キーには内容、バージョン、ルールのリビジョン、しきい値、チェック項目、パスが含まれ、プロジェクト間で衝突しません。20,000 件に自動整理されます。--no-cache で無効にできます。プロジェクト内には何も書き込みません。
対応言語
17 言語に加えて、HTML/テンプレート内の埋め込み JS に対応しています。各言語に 4 つのルールがあり、CI ゲートは 1 つです。
| 言語 | ファイル | 備考 |
|---|---|---|
| Ruby | .rb .rake .ru .gemspec、Gemfile、Rakefile、… | メソッドの AbcSize は RuboCop と同等です。メソッド外のブロックは計測単位です |
| Rust | .rs | |
| Python | .py .pyi .pyw | |
| Go | .go | |
| PHP | .php | |
| Java | .java | |
| C# | .cs | |
| Solidity | .sol | |
| Dart | .dart | |
| Zig | .zig | |
| Haskell | .hs .lhs | |
| JavaScript | .js .mjs .cjs .jsx | HTML/テンプレート内の <script> にも対応 |
| TypeScript | .ts .tsx .mts .cts | lang="ts"/typescript のスクリプトタイプ |
| 埋め込み JS | .html .htm .xhtml .erb .slim .haml .pug .vue .svelte .ejs .njk .jinja .j2 .twig .liquid .hbs …、*.js.erb | スクリプトを抽出し、<% %>、{{ }}、{% %} の穴は空白として扱います |
| C/C++ | .c .h .cc .cpp .cxx .hpp .hxx .hh | .h は C++ 文法で解析 |
| Objective-C | .m .mm | |
| Swift | .swift |
名前付き宣言は計測単位です。無名の関数形式は包含する単位に集計され、ネストされた単位が二重に計上されることはありません。C 系言語では、ファイルスコープのグローバル変数は単一ファイルでは到達できません。ループヘッダー内のローカル変数はプロトコルです。フィールドへの書き込みではオブジェクトも読み取るものとして扱います。エクスポートマクロを使ったクラス形式(class UTIL_EXPORT Foo)は変数ルールの対象外です。
ベンチマーク
Apple M1 Pro、キャッシュが温まった状態:
| コーパス | 規模 | abcop | rubocop --only AbcSize¹ | Full rubocop |
|---|---|---|---|---|
| rubocop/lib | 943 ファイル、110k LOC | 0.13 s | 5.1 s(約 39 倍) | 18.3 s |
| cargo registry サンプル | 6,603 ファイル、2.6M LOC | 約 2.8 s | — | — |
¹ --cache false — これを指定しないと、rubocop 自身のキャッシュにより、繰り返し実行が無料のように見えます。
開発
cargo test
cargo build --all-targets # zero warnings
abcop src # dogfood
共有エンジン:src/scope_model/(backend、walk、eval)。各言語のコレクターは各バックエンド(clike/、sollang/、…)の隣に配置されています。abcop --dump-tree FILE で文法ノードを調べられます。互換性の検証:
scripts/compare_parity.py。
ライセンス
GNU GPL v3 以降(SPDX:GPL-3.0-or-later)。LICENSE を参照してください。
Copyright © 2026 Peter Adrianov. All rights reserved.
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。