AIスロップ・クリーナー:コードベースの衛生状態を自動化する

Dev.to / 2026/4/30

💬 オピニオンDeveloper Stack & InfrastructureTools & Practical Usage

要点

  • この記事では、ツリーサイター(tree-sitter)のAST解析を用いて、未使用のインポート、死んだ関数/クラス、過度に複雑な関数を検出し、コードベースの衛生状態を自動化するCLIツール「slop-cleaner」を紹介する。
  • 高い自信(特に未使用インポート)の問題のみを自動修正し、死んだコードや高いサイクロマティック複雑度といった中程度の自信の検出結果は人間によるレビュー対象としてフラグを立てる。
  • このツールは5段階のパイプライン(Audit(監査)、Analyze(分析)、Clean(クリーニング)、Verify(検証))を採用し、PythonおよびTypeScript/TSXファイルをパースし、プロジェクト横断のコールグラフを構築したうえで、変更を原子的なパッチとして適用する。
  • slop-cleanerには安全機構が組み込まれている。書き込み前にファイルをバックアップし、テストスイートが失敗した場合は変更を自動的にロールバックして、サイレントな回帰を防ぐのに役立つ。
  • 複雑度の閾値(デフォルトではサイクロマティック複雑度 > 10)を使い、危険な自動削除を行わずにリファクタリング候補を優先順位付けする。

すべてのコードベースは、時間の経過とともに見た目のごみ(クラッター)が積み重なっていきます。リファクタリングのあとに残された import。もう誰も呼ばない helper 関数。理解しきれないほど複雑になってしまったメソッド。どれもすぐに何かを壊すわけではありませんが、それを読みにいくすべての開発者の速度を確実に落とし、将来のあらゆる変更コストを静かに押し上げます。

通常の対処は、人手による見直しです。誰かが1時間ほど使って未使用 import を探し、死んだ関数を見つけ、複雑さのホットスポットに印を付けます。これは面倒で一貫性に欠け、あるべき頻度よりもずっと稀にしか行われません。

slop-cleaner は、この作業を自動化する CLI ツールです。tree-sitter AST 解析(正規表現ではありません)によって、未使用の import、死んだ関数やクラス、そして過度に複雑なコードを検出します。そのため、ドキュストリングや文字列アノテーション内に現れる import を決して削除しません。すべてのパッチは原子的(atomic)に適用されます。書き込みの前にバックアップを取り、テストスイートが失敗した場合は自動的にロールバックします。

slop-cleaner が検出・修正するもの

slop-cleaner は、すべてのコードベースに積み重なるクラッターを、次の3つのカテゴリに絞って対象にします。

未使用 import: リファクタリングのあとに残された import です。これは HIGH 信頼度で検出され、自動的に削除されます。このツールは、1行 import の処理、from X import A, B ブロックから使われていない名前が1つだけの場合の選択的削除、from X import (...) のような複数行ブロックから各行を必要十分に切り出して削除する処理を行います。

死んだ関数とクラス: コードベース内のどこからも呼ばれていないものです。これは MEDIUM 信頼度で検出され、人によるレビューのためにレポートへフラグ付けされます。この判定を行う前に、ツールはあらゆるシンボルをまたいだ完全な呼び出しグラフを構築します。

過度に複雑な関数: 複雑度が閾値(デフォルト10)を超える関数です。これは MEDIUM 信頼度で検出され、人によるリファクタリングのためにフラグ付けされます。ツールは関数を自動削除することはありません。複雑度は「何かに注意が必要」というシグナルであり、安全な自動修正ではないためです。

HIGH 信頼度の問題は自動修正されます。MEDIUM 信頼度の問題は常に人間の判断に委ねられます。

5フェーズ・パイプライン

slop-cleaner が行うすべての処理は、5フェーズのパイプラインとして実行されます。各フェーズは次のフェーズへ引き継がれ、すべてのパッチは原子的に適用されます。書き込みの前にバックアップを取り、テストが失敗した場合は自動的にロールバックします。

Audit(監査): tree-sitter により、すべての .py および .ts/.tsx ファイルを解析します。未使用 import は HIGH 信頼度で収集され、高複雑度の関数は MEDIUM 信頼度で収集されます。

Analyze(分析): プロジェクト内のすべてのシンボルを横断して呼び出しグラフを構築します。死んだコードや、定義されているのに一度も呼ばれていないものを特定します。

Clean(クリーンアップ): HIGH 信頼度のパッチを原子的に適用します。from X import (...) の単一行および複数行ブロックを扱います。書き込みの前に各ファイルをバックアップします。

Verify(検証): pytest でテストスイートを実行します。失敗が発生した場合は、パッチを当てたすべてのファイルを自動的にバックアップへロールバックします。CI が検知できるように終了コード 1 を返します。

Document(ドキュメント化): Markdown レポートを3種類生成します。ARCHITECTURE.mdFUNCTION_MAP.md、そして SLOP_REPORT.md です。詳細は以下に示します。

自動修正されるもの/フラグ付けされるもの

この区別は重要です。HIGH 信頼度のパッチは、「削除しても安全」だとツールが確信しているケースです。MEDIUM 信頼度のケースでは、死んだコードや複雑さが、動的ディスパッチ、リフレクション、その他のパターンによって自動削除のリスクになり得ます。ツールはそれらをフラグ付けし、判断はあなたに委ねます。

対応しているエッジケース

未使用 import を検出する上で最も難しいのは、「使われていないように見える名前が、実は必要とされているのかどうか」を知ることです。slop-cleaner はこれらを正しく扱います:

これらはまさに、正規表現ベースのツールが間違えやすいケースです。slop-cleaner は実際の AST を解析するため、文字列の中に名前が現れているのか、識別子として使われているのかの違いを理解できます。

インストール

git clone https://github.com/your-org/slop-cleaner
cd slop-cleaner

# 仮想環境を作成して有効化
python3 -m venv .venv
source .venv/bin/activate      # macOS / Linux
# .venv\Scripts\activate       # Windows

# ツールと依存関係をインストール
pip install -e .

このコマンドは2つ登録されます:slop-auditslop-clean
依存関係は pyproject.toml 経由で自動的にインストールされます:

モダンな Linux(Ubuntu 23.04+、Debian 12+)向けの注意:システムの Python ではグローバルな pip install がブロックされます。上記のように必ず仮想環境を使うか、pipx install . を使って venv なしで CLI ツールをグローバルにインストールしてください。

テストスイートを実行するには:

pip install -e ".[test]"   # pytest + pytest-cov を追加
pytest                     # tests/test_parsers.py(22テスト)を実行

クイックスタート

# プロジェクトを監査 — 問題があればレポートを出して exit 1(CI向け)
slop-audit path/to/project/

# 単一ファイルを監査
slop-audit src/services/user_service.py

# フルクリーン — 監査、修正、テスト検証、ドキュメント生成
slop-clean path/to/project/

# ドライラン — ファイルに触れずに変更内容を表示
slop-clean path/to/project/ --dry-run

# ツール連携のために監査JSONを書き出す
slop-audit path/to/project/ --output report.json

コマンド

slop-audit
slop-audit はファイルまたはディレクトリをスキャンし、何も触らずに検出したすべての問題の一覧を表形式で出力します。問題が見つかった場合は終了コード 1 で終了するため、CI のゲートとしてクリーンに扱えます。

slop-audit <target> [--output JSON] [--threshold N] [--verbose]

終了コード:0 = クリーン、1 = 問題が見つかりました。

slop-clean
slop-clean は、完全な5フェーズのパイプラインを実行します。馴染みのないプロジェクトでは必ず最初に --dry-run を実行してください。どのパッチが適用されるかを、ファイルに触れることなく正確に表示します。

slop-clean <target> [--output DIR] [--threshold N] [--dry-run] [--verbose]

終了コード:0 = 成功、1 = ロールバックがトリガーされました。

生成された出力

slop-clean を実行した後、--output ディレクトリには3つのレポートが含まれます:

After slop-clean runs, the --output directory contains three reports:

slop-output/
├── ARCHITECTURE.md   — ファイルツリー + Mermaid の依存関係グラフ
├── FUNCTION_MAP.md   — 開始行と複雑性スコア付きで、すべてのシンボル
└── SLOP_REPORT.md    — 問題の要約、適用されたパッチ、デッドコード候補

ARCHITECTURE.md は、Mermaid のコールグラフを視覚的に添えたコードベースの構造的な概要で、一目でプロジェクトがどう組み合わさっているかを理解するのに役立ちます。

FUNCTION_MAP.md は、すべての関数とクラスについて、開始行と複雑性スコアを含む完全なインデックスです。大規模なコードベースでは、複雑性がどこに集中しているかを最速で把握できます。

SLOP_REPORT.md は実行可能な出力です。自動的に修正された内容、手動レビューが必要としてフラグが立てられた内容、そして人間による判断が必要なデッドコード候補の一覧です。

例のプロジェクトで試してみる

examples/ には2つのサンプルプロジェクトが用意されているので、インストール後すぐにツールを試せます:

# 監査のみ — テストの検証は不要
slop-audit examples/todo_app/ --verbose
slop-audit examples/event_pipeline/ --verbose

# 完全クリーン — まずドライラン、次に適用
slop-clean examples/todo_app/ --dry-run
slop-clean examples/todo_app/

例のテストスイートを直接実行するには、最初にプロジェクトディレクトリへ移動して import が正しく解決されるようにします:

cd examples/todo_app && pytest tests/ -v
cd examples/event_pipeline && pytest tests/ -v

todo_app は、意図的にスロップが入ったサンプルのPythonアプリで、ツールが何を検出するかを正確に確認するのに最適な最初の実行です。event_pipeline は、別名のエイリアス、複数行の import、文字列注釈のような扱いにくいパターンをカバーしており、AST解析が境界ケースを正しく処理できることを示すために設計されています。

CI 連携

slop-audit は、品質ゲートとしてそのまま CI に投入できます。不具合が見つかった場合は 1 を返して、ワークフローのステップを自動的に失敗させます:

# .github/workflows/quality.yml
jobs:
  slop-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pip install -e .
      - run: slop-audit src/ --threshold 12

これは、main ブランチにマージされる前のすべてのプルリクエストで、未使用 import や複雑性の回帰を検知します。

プロジェクト構成

slop-cleaner/
├── cli/
│   └── main.py               — エントリポイント + 豊富なフォーマット出力
├── engines/
│   ├── auditor.py            — 第1フェーズ:ASTベースの課題検出
│   ├── analyzer.py           — 第2フェーズ:コールグラフ + デッドコード検出
│   ├── cleaner.py            — 第3フェーズ:原子的なパッチ適用
│   ├── verifier.py           — 第4フェーズ:pytest ランナー + ロールバック
│   └── documenter.py         — 第5フェーズ:Markdownレポート生成
├── parsers/
│   ├── python_parser.py      — tree-sitter の Python ラッパー
│   └── typescript_parser.py  — tree-sitter の TypeScript/TSX ラッパー
├── examples/
│   ├── todo_app/             — 意図的にスロップが入ったサンプルPythonアプリ
│   └── event_pipeline/       — 扱いにくい import パターンを持つサンプルプロジェクト
├── assets/
│   ├── pipeline.svg          — 5フェーズのフロー図
│   ├── features.svg          — 機能概要のインフォグラフィック
│   └── before-after.svg      — コード変換の可視化
└── tests/
    └── test_parsers.py       — パーサーをカバーする22のテスト

この構成は、5つのフェーズにきれいに対応しています。フェーズごとに1つのエンジン、Python と TypeScript/TSX 用に2つのパーサー、そしてそれらを結びつける単一の CLI エントリポイントです。

NEO を使ってこれを作った方法

このツールは、完全に NEO のみを使って設計され、作られ、デバッグされ、改良されました。手取り足取りなしに、実在のコードを書き、実行し、反復する完全自律型のAIエンジニアリングエージェントです。

すべてのエンジン、あらゆるエッジケースの修正、そしてすべてのSVGは、NEO によって1セッションで作られました。5フェーズのパイプライン、Python と TypeScript の tree-sitter AST パーサー、バックアップとロールバック付きの原子的なパッチ適用、コールグラフビルダー、失敗時に自動ロールバックする pytest ランナー、そして3つの Markdown レポート生成器――これらすべてが、高レベルの問題説明からエンドツーエンドで組み上げられました。

NEO でこのツールを使い、拡張する方法

すべてのプルリクエストで CI の品質ゲートとして使う:
slop-audit を CI パイプラインに投入してください。すべての PR で、main に触れる前に未使用 import と複雑性の回帰がチェックされます。問題があれば終了コード 1 によりビルドが自動的に失敗し、ワークフローの1ステップ以外の設定は不要です。すでに標準でこの用途向けに組み込まれています。

大規模なリファクタリングの前に使う:
大きなリファクタリングを始める前に、コードベースで slop-clean を実行します。溜まってしまった import の煩雑さを取り除き、もはや対処する必要のない死んだコードを検出し、複雑性マップを生成します。よりクリーンな出発点でリファクタリングに入り、複雑性がどこに潜んでいるかを明確に把握できます。

不慣れなコードベースへのオンボーディングに使う:
引き継いだばかりのプロジェクトに対して slop-audit を実行し、SLOP_REPORT.md を読みます。使われていない import、死んだ関数、複雑性のホットスポットを、構造化された一覧として得られます。コードを触りながら一つずつ見つけるのではなく、実行できる形の技術的負債のマップが手に入ります。

レガシープロジェクトのドキュメント基盤を作るために使う:
slop-clean を実行し、ARCHITECTURE.mdFUNCTION_MAP.md を読みます。ファイルツリー、視覚的なコールグラフ、そして、すべてのシンボルについてその複雑性スコアを含む完全なインデックスが得られます。既存のドキュメントがないプロジェクトにとって、それは意味のある出発点になります。

このツールは拡張することも前提に設計されており、NEO ならこれらのどれも、最初から作り直すことなくさらに追加できます:

JavaScript/JSX パーサー: 同じ tree-sitter のラッパーパターンに従って、すでに 2 つのパーサーが存在します(python_parser.pytypescript_parser.py)。JavaScript/JSX 用の 3 つ目も同じインターフェースに従うため、すぐに 5 つのエンジンすべてに組み込めます。

追加の複雑性メトリクス: auditor.py はすでに循環的複雑性を追跡しています。関数の長さのような追加メトリクスも同様の検出パターンに従い、追加され次第 FUNCTION_MAP.md と監査出力の両方に自動的に表れます。

死んだコードに対する自動修正: 現在、死んだコードは MEDIUM の確度でフラグが立てられ、人間の判断に委ねられています。コールグラフによって到達不能であることが明確に確認できた死んだ private 関数に対しては、自動削除が自然な次のステップになります。これは、既存の analyzer.pycleaner.py の仕組みに直接組み込んで実現できます。

プリコミットフック: slop-audit はすでに問題がある場合に 1 を返して終了します。既存の CLI エントリポイントにフックする小さなラッパーによって、slop の検出を CI に何かが届く前にローカル開発のループへ組み込めます。

Final Notes

コードの煩雑さは見た目の問題ではありません。未使用の import はすべてのコードレビューにノイズを加えます。死んだ関数は、頭の中で考慮し続けなければならない領域(表面積)を増やします。高複雑性の関数は変更に抵抗し、バグを隠します。slop-cleaner はこの 3 つすべてに自動で対処します。正規表現ベースのツールでは一致できない AST レベルの精度と、見つけたときよりも悪い状態のままコードベースを放置しないためのテスト検証ステップを備えているためです。
コードは https://github.com/your-org/slop-cleaner にあります。
また、IDE 内で NEO を VS Code 拡張 または Cursor を使ってビルドすることもできます。