HN 日本語サマリー

← 一覧へ戻る
プログラミング

Show HN: Graphify C# – コーディングエージェント向けのコンパイラ精度での「使用箇所の検索」

Show HN: Graphify C# – Compiler-accurate Find Usages for coding agents (github.com)

28 pointsby zachsaw11 コメント

要約

Graphify C#は、C#コードベースをコンパイラレベルで正確に解析し、シンボルの参照関係(呼び出し元、実装、継承など)をグラフ構造で抽出するツールです。これにより、AIコーディングエージェントはコードの意味を推測するのではなく、確実な情報に基づいてコードのナビゲーションや分析を行えるようになります。IDE不要で、MITライセンスで提供されています。

全文翻訳

graphify-csharp 🚀

コーディングエージェントに、C#のコンパイラ精度を持つ「使用箇所の検索」機能を提供します。

[画像: NuGet Version] [画像: CI] [画像: License: MIT]

graphify-csharpは、コーディングエージェント向けの無料のヘッドレスRoslyn/MSBuildインデクサーです。C#のソリューションまたはプロジェクトを、決定論的な意味論的証拠に変換します。これには、オーバーロード、ジェネリック、プロジェクト境界を越えた正確な呼び出し元、参照、実装、継承、オーバーライド、引数バインディングが含まれます。

RiderやReSharperのセマンティックナビゲーション機能を想像してみてください。それをCodex、Claude Code、Cursorなどの、C#コードベースについて推測ではなく推論を必要とするツール向けにエクスポートしたものです。

MITライセンス · IDE不要 · 事前ビルドされたプロジェクトDLLは不要 · データベース不要 · Graphifyはオプション

問題点

エージェントに次のように尋ねたとします。

テストによってのみ使用されているメソッドはどれですか?

テキスト検索ではスペルミスを見つけることはできます。しかし、呼び出しがintまたはstringのオーバーロードにバインドされているか、インターフェイスメンバーが派生実装にディスパッチされているか、あるいは呼び出し元がどのプロジェクトに属しているかを確実に伝えることはできません。それが、もっともらしく見えるデッドコードレポートが安全でない理由です。

Graphify C#は、MSBuildを使用して評価済みのプロジェクトをロードし、コンパイラが解決したシンボルと関係をRoslynに問い合わせます。

テキスト検索Graphify C#
名前の一致は使用箇所のように見える正確な宣言とバインドされたシンボル
オーバーロードとジェネリックは曖昧安定したIDはシグネチャとプロジェクト/TFMの出所を保持
テストのみの使用は手動でのソートが必要呼び出し元にはプロジェクト、名前空間、ソースの場所が含まれる
継承は名前から再構築されるinherits、implements、overridesは明示的な関係

このツールは証拠を報告します。エージェントは、リポジトリの命名規則(例: Testsを含むプロジェクトや名前空間)を使用して呼び出し元を分類し、人間によるレビューが必要なものを決定できます。

クイックスタート

1. グローバルツールのインストール
dotnet tool install --global Graphify.CSharp --framework net10.0

.NET 11 SDKがインストールされている場合は、C# 15プレビュー入力用にnet11.0アセットを使用します。

dotnet tool install --global Graphify.CSharp --framework net11.0

ツールが既にインストールされている場合は、同じ--frameworkでdotnet tool updateを使用してください。

2. 完全なグラフのエクスポート

1つのソリューションまたはプロジェクトを含むリポジトリから、最も短い形式は次のとおりです。

graphify-csharp

カレントディレクトリに.sln/.slnxが1つ存在するか、ソリューションが存在しない場合は.csprojが1つ存在する場合、それを検出して次のように書き込みます。

./graphify-out/csharp.json

ソリューションがsrcの下にあるリポジトリの場合は、明示的に指定します。

graphify-csharp export \
  --input ./src/MyProduct.sln \
  --root . \
  --configuration Release \
  --output ./graphify-out/csharp.json

出力は、nodes、edges、hyperedgesを含む1つの完全なJSONドキュメントです。これはエージェントが検査したり、jqでクエリしたり、独自のプログラムで消費したり、オプションのGraphify実行可能ファイルに渡したりできます。

v0.1からアップグレードする場合、watch/export --instanceコマンドの分割、出力の変更、パスセマンティクスについては、簡潔なv0.2移行ガイドを参照してください。

3. エージェントに使用方法を指示する

リポジトリには、コピー可能なコンシューマースキルが含まれています。これは、エージェントにウォームセッションの開始方法、正確なシンボルIDの使用方法、呼び出し元や関係の検査方法、静的解析の制限の解釈方法、および必要に応じたJSONのエクスポート方法を教えます。NuGetパッケージのインストールは実行可能ファイルをインストールしますが、スキルはインストールしません。

プロジェクトローカルのCodexセットアップ:

mkdir -p .agents/skills/graphify-csharp
curl -fsSL \
  https://raw.githubusercontent.com/zachsaw/graphify-csharp/main/.agents/skills/graphify-csharp/SKILL.md \
  -o .agents/skills/graphify-csharp/SKILL.md

個人のCodexインストールには、~/.codex/skills/graphify-csharp/を使用します。Claude Codeの場合は、プロジェクト内の.claude/skills/graphify-csharp/または個人のインストール用の~/.claude/skills/graphify-csharp/を使用します。ファイルのインストールまたは更新後にエージェントをリロードしてください。

スキルシステムがない場合は、リポジトリのエージェント指示に次のように記述します。

C#の構造と使用方法に関する質問には、graphify-csharp CLIを使用してください。宣言は正確なsymbol_key/ノードIDで識別し、着信calls、references、inherits、implements、overridesの関係を検査してください。ゼロ個の着信エッジは、実行時の到達不可能性の証拠ではなく、ゼロ個の観測された静的参照として扱ってください。

エージェントが質問できること

  • この正確なオーバーロードまたはコンストラクタを呼び出しているのはどれですか?
  • どの宣言がこのフィールド、プロパティ、イベント、型、または列挙メンバーを参照していますか?
  • どのクラスがこの型を継承しているか、またはこのインターフェイスを実装していますか?
  • どのオーバーライドがこの仮想メンバーまたはインターフェイスメンバーを満たしていますか?
  • どの引数がどの形式パラメータにバインドされていますか?
  • 観測された静的参照がゼロ個の宣言はどれですか?
  • どの呼び出し元がTestsという名前のプロジェクトまたは名前空間から発生していますか?
  • どの宣言がテストのみの使用レポートの候補ですか?

最後の2つは、ハードコードされた分類ではなく、分析に関する質問です。ツールは呼び出し元の出所を提供し、エージェントは選択した命名規則を適用してスコープと注意点を報告します。

ウォームセマンティックナビゲーション

繰り返しエージェント作業を行う場合は、Roslynワークスペースをウォーム状態に保ちます。watchはフォアグラウンドで動作し、出力は生成しないセッションです。これを1つのターミナルで実行します。

graphify-csharp watch

検出が曖昧な場合は、入力とルートを指定します。

graphify-csharp watch \
  --input ./src/MyProduct.sln \
  --root . \
  --configuration Release

ウォッチャーは、起動時に標準エラー出力に完全なセッションIDと解決された分析コンテキストを出力します。別のターミナルで、そのID(または一意のプレフィックス)を使用します。

graphify-csharp ps --json
graphify-csharp info <session-id> --json
graphify-csharp query symbols OrderService --instance <session-id> --kind class --json
graphify-csharp query callers --instance <session-id> --symbol <symbol-id> --json
graphify-csharp query usage-summary \
  --instance <session-id> \
  --kind method \
  --group-by project,namespace \
  --json

名前がオーバーロードを持つ場合は、まずsymbolsを使用します。次に、返された正確なシンボルIDをsignature、callers、usages、hierarchy、またはargumentsに渡します。クエリは、それらに回答するために使用された証拠のスナップショットを含む、バウンドされたJSONページを返します。ライブセッションは、編集にも役立ちます。クエリ、エクスポート、明示的なリフレッシュは、セッションの起動/回復バリアを待ちます。

エージェントが完全なグラフを必要とする場合は、明示的に要求します。

graphify-csharp export --instance <session-id>

これは、呼び出し元のターミナルのカレントディレクトリの下にデフォルトの./graphify-out/csharp.jsonを書き込みます。--outputで別の宛先を選択します。ウォッチャーは、ソースファイルが変更されたという理由だけで新しいJSONファイルを公開しません。エクスポートは明示的な公開要求です。

便利なライフサイクルコマンド:

graphify-csharp refresh --instance <session-id>
graphify-csharp refresh --instance <session-id> --rebuild
graphify-csharp diagnostics <session-id> --output ./graphify-out/diagnostics.json
graphify-csharp stop <session-id>

refreshは、グラフファイルを作成せずに信頼できるインメモリ証拠を更新します。--rebuildはそのリフレッシュのために再利用可能な貢献を無効にします。stopは選択されたセッションのみを対象とします。複数のセッションを同時に実行できます。

ワンショットクエリ

単一の質問のためにウォッチャーやJSONダンプは必要ありません。

graphify-csharp query callers \
  --input ./src/MyProduct.sln \
  --root . \
  --configuration Release \
  --symbol '<exact-symbol-id>' \
  --json

コールドクエリには明示的な--inputが必要です。永続的なセッション、出力ファイル、カーソル、またはスナップショットは作成されません。選択された--instanceは、そのセッションが存在しない場合でもコールド分析にフォールバックすることはありません。

JSONの形状

完全なエクスポートは、消費しやすいように意図的にシンプルにされています。これは短縮された形状です。IDとシンボルキーは実際のRoslyn宣言から生成されます。

{
  "nodes": [
    {
      "id": "cs_<stable-node-id>",
      "label": "OrderService.Submit(int)",
      "properties": {
        "node_kind": "method",
        "symbol_key": "csharp/v1|...",
        "project": "src/Orders/Orders.csproj",
        "target_framework": "net10.0"
      }
    }
  ],
  "edges": [
    {
      "source": "cs_<caller-node-id>",
      "target": "cs_<stable-node-id>",
      "relation": "calls",
      "source_file": "src/Orders/OrderController.cs"
    }
  ]
}

calls、references、inherits、implements、overridesはコンパイラによって解決された関係です。場所は、関係が観測された場所を特定します。呼び出しおよびコンストラクタの引数も、ソースの形式パラメータにマッピングできます。

Graphifyはオプションであり、別のツールです

graphify-csharpは、別のgraphify実行可能ファイルを呼び出したり、ロードしたり、必要としたりしません。CLIとJSONは、エージェント、jq、C#、Python、またはその他のコンシューマーと直接使用できます。

Graphifyも使用する場合、役割を分離してください。

  1. graphify-csharpはC#セマンティックドキュメントを生成するか、C#クエリに応答します。
  2. 別のgraphify実行可能ファイルは、そのドキュメントを、より高レベルのグラフクエリ、パス、説明、クラスタリング、またはエクスポートのために消費します。
graphify-csharp export \
  --input ./src/MyProduct.sln \
  --root . \
  --output ./graphify-out/csharp.json

graph 2query "Which methods call the order service?" \
  --graph ./graphify-out/csharp.json

オプションのGraphifyスキルはgraphifyツールを教えます。このリポジトリのgraphify-csharpスキルはこのCLIを教えます。両方のワークフローが必要な場合にのみ両方を一緒にインストールしてください。一方が他方をインストールしたり、サイレントに呼び出したりすることはありません。

ランタイムと言語サポート

パッケージには2つのグローバルツールアセットが含まれています。

ツールアセットランタイムコンパイラサーフェス
net10.0.NET 10C# 14 Roslynパス
net11.0.NET 11C# 15プレビューRoslynパス

インストール時の--frameworkは、どの実行可能アセットを実行するかを選択します。オプションの分析時の--target-frameworkは、分析対象プロジェクト自体が複数のフレームワークをターゲットにしている場合に1つのターゲットフレームワークを選択します。単一ターゲットプロジェクトは通常、ターゲットセレクタを必要としません。

静的解析の境界

これはコンパイラの証拠であり、実行時の到達可能性の証明ではありません。リフレクション、依存性注入、動的呼び出し、ネイティブコールバック、評価されたコンパイル外の生成コード、および外部コンシューマーは、直接的な静的エッジとして表示されない実行時関係を作成する可能性があります。

したがって:

  • ゼロ個の着信エッジは、選択されたスコープでの観測された静的参照がゼロであることを意味します。
  • テストのみの使用は、エージェントによって適用されるプロジェクト/名前空間の規則に依存します。
  • 削除候補は、エントリーポイント、リフレクション、DI、ソースジェネレーター、公開APIコンシューマー、およびビルド/テスト動作のレビューが必要です。

サポートされていない、または表現できないセマンティック形状は、全体的な抽出をクラッシュさせる代わりに、可能な場合は診断として報告されます。

開発

インデクサー自体に貢献するには:

dotnet restore Graphify.CSharp.sln
dotnet build Graphify.CSharp.sln --configuration Release
dotnet test Graphify.CSharp.sln --configuration Release
dotnet pack src/Graphify.CSharp.Cli --configuration Release

詳細:

ライセンス

MIT。 LICENSEを参照してください。