DEV Community

bigkijimon
bigkijimon

Posted on

graphifyがApple Siliconで全滅した — x86_64 tree-sitterの罠と、コード ドキュメントを丸ごと知識グラフ化するまでの実録

🇯🇵 This post is written in Japanese. Originally published on Zenn(この記事はZennからの転載です)。

Claude Codeが毎回ファイルを読み直す問題

Claude Codeで大きめのプロジェクトを触っていると、毎セッション同じことが起きる。「あのファイルどこだっけ」でgrep、全文Read、また別のファイルをRead……。コードベースはgrepには大きすぎ、コンテキストに丸ごと積むには高すぎる。

これを解くのが graphify(PyPIパッケージ名はgraphifyyで yを2つ重ねる/CLIコマンドはgraphify)。フォルダを丸ごと知識グラフにして、Claudeがファイルを読み直す代わりにグラフを引く。公称「クエリあたり最大71.5xのトークン削減」。

知識グラフとは何かを一言で。コードとドキュメントを解析して「関数・クラス・概念=ノード」「呼ぶ・依存する・参照する=有向エッジ」の有向グラフとして抽出したもの。質問すると、全文を読み直す代わりに関連ノードだけを部分グラフで返す。だから軽い。graphifyはコードをtree-sitterでローカルAST解析(LLM不使用)し、ドキュメントだけをモデルで意味抽出する。

M1 Max(Apple Silicon)で、自分のプロジェクト——シェルのオーケストレーション群、Swiftのメニューバーアプリ、設計ドキュメント——を丸ごとグラフ化しようとした。そしていきなり全滅した。この記事はその実録。

トラブルシューティング

全滅:incompatible architecture

uv tool install graphifyy で入れて、AST抽出を走らせた瞬間これが出た。

ImportError: dlopen(.../tree_sitter/_binding.cpython-313-darwin.so, 0x0002):
  tried: '.../tree_sitter/_binding.cpython-313-darwin.so'
  (mach-o file, but is an incompatible architecture
   (have 'x86_64', need 'arm64e' or 'arm64'))
Enter fullscreen mode Exit fullscreen mode

tree_sitter のネイティブバインディング(.so)が x86_64 で、arm64のPythonがロードできない。graphifyはコードをtree-sitterでAST解析するので、ここが死ぬとコード抽出が全滅する。

Apple Siliconあるあるだが、厄介なのは「graphify自体が抱えていたx86_64依存」だったこと。自分のコードでもモデルでもなく、ツールのネイティブ依存がx86_64前提でインストールされていた。原因はシンプルで、arm64のPythonがx86_64の.soをdlopenできずに落ちている。uv toolの解決時にx86_64ホイールを掴んでいた。

修正①:tree-sitterをarm64で入れ直す

uv tool環境にはpipが無いので、uv pipでその環境を指定して強制再インストールする。

PY=/Users/you/.local/share/uv/tools/graphifyy/bin/python
uv pip install --python "$PY" --reinstall-package tree-sitter --no-cache 'tree-sitter>=0.23.0'
Enter fullscreen mode Exit fullscreen mode

tree-sitter 0.26.0(arm64)が入り、dlopenの悲鳴は止まった。……が、まだAST結果は0ノードだった。

修正②:言語grammarが「そもそも」入っていなかった

再試行で今度はこう出た。

warning: 32 .swift file(s) contributed nothing to the graph
  because a dependency is missing: tree_sitter_swift not installed.
Enter fullscreen mode Exit fullscreen mode

tree-sitterのコアは直ったが、各言語のgrammartree_sitter_swift等)が別パッケージで、未導入だった。ここで一気に入れる。特に tree-sitter-bash を入れると、シェルスクリプトのオーケストレーション群もAST解析できるようになる——これが自分の環境では本命だった。

uv pip install --python "$PY" --no-cache \
  tree-sitter-bash tree-sitter-swift tree-sitter-python \
  tree-sitter-typescript tree-sitter-javascript tree-sitter-json tree-sitter-go
Enter fullscreen mode Exit fullscreen mode

7言語すべてimportOK。このtree-sitter-bash導入が効いて、それまで0ノードだったシェル13本+Swift32本が解析対象になった。 再々試行:

Swift AST: 323 nodes, 759 edges
Enter fullscreen mode Exit fullscreen mode

動いた。 archを直し、grammarを入れる——この2段で復活する。片方だけだと0ノードで沈黙するので、両方必須。全体の流れはこう。

全滅から復活へ — Apple Siliconのgraphify、2段の修正(archエラー→arm64再インストール→まだ0ノード→言語grammar導入→0から332ノードへ)

段階 状態
初期 dlopen incompatible architecture で全滅
修正①後(arm64 tree-sitter) archエラーは消えるが 0ノード
修正②後(言語grammar導入) 332ノード / 653エッジ

コードグラフ構築:bash+Swiftを1グラフに

コード → 332ノード

まずコード資産をASTで(LLM不使用・完全無料)。シェルのオーケストレーション13本(GPU調停・ディスパッチャ・監視系など)+Swiftアプリ32本=45本を1グラフに。

Graph: 332 nodes, 653 edges, 23 communities
God node: 中核ViewModel   ← アプリの中枢を正しく検出
Enter fullscreen mode Exit fullscreen mode

ここでベストプラクティスをひとつ。testは除外、infra/docsは含める。 testはノードを3-4倍に膨らませてクラスタリングを濁す(graphifyの公式ガイドでも指摘される経験則)。逆にインフラ設定やドキュメントは「システムがどう配線されているか(何が何に依存するか)」を教えてくれる。

+ドキュメント → 629ノード

次に、CLAUDE.mdや設計ドキュメント60本をsemantic抽出(並列サブエージェント)でグラフに足した。結果:

ENRICHED Graph: 629 nodes, 986 edges, 76 communities
Enter fullscreen mode Exit fullscreen mode

コード構造と設計知識が1つのグラフに同居した。構築の流れを図にするとこう。

コード+ドキュメント → 1つの知識グラフ → 副産物(コード45本はローカルAST・無料、設計doc60本はsemantic抽出。629ノード/986エッジのグラフから graph.html・Obsidian・Wiki・MCPサーバ・graphify query が全部出る)

実際に引いてみる

「GPU調停まわりは何と繋がってる?」を聞くと、BFSでこう返る(識別子は汎用名にしてある。形式は実出力のまま)。

$ graphify query "gpu arbitration freeze thaw"
Traversal: BFS depth=2 | Start: [GpuMonitor] | 13 nodes found

NODE GpuMonitor       [src=app/services/gpu_monitor.swift  L9   community=8]
NODE MemSwitchScript  [src=scripts/mem_switch.sh           L1   community=29]
NODE thaw_ollama()    [src=scripts/mem_switch.sh           L38  community=29]
NODE LocalLLMRuntime  [src=docs/env_snapshot.md            —    community=6]

EDGE GpuMonitor      --shares_data_with--> CoreViewModel   [INFERRED  0.85]
EDGE MemSwitchScript --references-->       LocalLLMRuntime [EXTRACTED 1.0]
EDGE thaw_ollama()   --calls-->            LocalLLMRuntime [EXTRACTED 1.0]
Enter fullscreen mode Exit fullscreen mode

Swiftの型(コード)、シェルのスクリプトと関数(コード)、設計メモの「ローカルLLM基盤」(ドキュメント)が1つの答えに混ざって出てくるshares_data_with(INFERRED 0.85)やreferences(EXTRACTED 1.0)のように、関係の種類と確信度まで付く。「実装」と「なぜ・どこに繋がるか」を一度に返す——これがコードとドキュメントを同居させた効果だ。graphify explain "<ノード>"ならType / Community / Degreeと接続先一覧を平易に出してくれる。

性能計測:約215xのトークン削減

graphify benchmarkの実測がこれ。

Corpus:          31,450 words → ~41,933 tokens (naive)
Graph:           629 nodes, 986 edges
Avg query cost:  ~195 tokens
Enter fullscreen mode Exit fullscreen mode

表にするとこう。

方式 1回のコスト 倍率
コーパス丸ごと積む(naive) ~41,933 tokens 1x
graphify query ~195 tokens 約215x削減

(コーパス 31,450 words / グラフ 629ノード・986エッジ/graphify benchmark実測)

数字は2つある。公称「最大71.5x」はgraphify公式のベンチ値この自分のコーパスでの自測値は約215xgraphify benchmarkの出力)。コーパスの内容と質問で変わる——構造・依存を尋ねる質問ほど効き、編集そのものやグラフ外のファイルには効かない。ただ「毎回コードベースを積み直す税」が桁で消えるのは共通だ。

副産物も全部おいしい

graphifyは1回のビルドで大量の成果物を吐く。全部使うと効く。

  • HTMLgraph.html):ブラウザで開く対話グラフ。サーバ不要。
  • Obsidian vault:1ノード1mdの双方向リンク。「第二の脳」化。
  • Wiki:コミュニティ別の記事。エージェントがwiki/index.mdから辿る。
  • MCPサーバpython -m graphify.serve graph.jsonget_node/get_neighbors/shortest_pathをツール露出。エージェントがグラフをライブ照会できる(要mcpパッケージ)。
  • 常時ON統合graphify claude installでCLAUDE.mdにルールとPreToolUseフックが入り、以後は明示/graphifyなしでコードベースの質問前に自動でグラフを参照する。

生成されるObsidianノートは1ノード=1メモで、frontmatterと[[…]]のbacklinkが付く(識別子は汎用名)。まずGpuMonitorのノート:

---
source_file: "app/services/gpu_monitor.swift"
type: "code"
community: "Community 8"
---
# GpuMonitor
## Connections
- [[CoreViewModel]] - `shares_data_with`
- [[MemSwitchScript]] - `conceptually_related_to`
Enter fullscreen mode Exit fullscreen mode

繋がった先のCoreViewModelノートを開くと、逆向きのリンクが自動で張られている(双方向):

---
source_file: "app/models/core_view_model.swift"
type: "code"
community: "Community 1"
---
# CoreViewModel
## Connections
- [[GpuMonitor]] - `shares_data_with`
- [[MetricsProbe]] - `calls`
- [[SessionProbe]] - `calls`
Enter fullscreen mode Exit fullscreen mode

Obsidianのグラフビューで開けば、この双方向リンクがそのままノード網になり、コードを1行も読まずに「どのモジュールが何と繋がるか」を辿れる。

教訓(Apple Siliconでgraphifyを動かす人へ)

  1. archエラーは2段で直すtree-sitter本体をarm64で再インストール → 言語grammar(tree-sitter-bash/swift/…)を導入。片方だけだと0ノードで沈黙する。
  2. bash grammarを入れる:シェル中心のオーケストレーションこそグラフ化の価値が高い。
  3. testは切り、infra/docsは入れる:グラフの主役はクラスタの純度と「配線」。
  4. docのsemanticはモデルAPIを使う:コードはローカルAST(無料)、doc/画像はモデル呼び出しでトークンを食う。コスト意識するならスコープを絞る(画像はvisionで特に高い=依存グラフには不要なので除外が正解)。

archの罠を抜ければ、graphifyはApple Siliconで完全に動く。そして一度グラフにすると、AIが「プロジェクト全体の文脈を持った状態」で動き始める——速度だけの話ではない、というのが一番の収穫だった。

Top comments (0)