mcpField
D
data-structure-protocol

data-structure-protocol

github.com/k-kolomeitsevエージェントワークフロー6853 回インストール12 週間前に更新
リポジトリ

data-structure-protocol について

プロジェクトのコードエンティティと依存関係を `.dsp/` にグラフとして記録するスキルおよび CLI プロトコルです。コーディングエージェントによる索引作成、探索、影響分析と、コード変更に合わせたグラフの更新を支援します。

主な機能

  1. 01エンティティと依存関係をグラフ化
  2. 02目的、インポート、エクスポートを記録
  3. 03プロジェクト内のエンティティを検索・探索
  4. 04依存元と依存経路を分析
  5. 05コード変更に応じてグラフ記録を更新
  6. 06循環依存と孤立エンティティを診断

活用シーン

  1. 01コードベースの導入時にグラフを構築
  2. 02コード変更前に依存関係を確認
  3. 03モジュールや関数の変更影響を評価
  4. 04コード編集とグラフのメタデータを同期

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/k-kolomeitsev/data-structure-protocol --skill data-structure-protocol

インストール後、Claude Code で/data-structure-protocolを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

dsp-tool-config.json
LICENSE
references/
bootstrap.md
operations.md
storage-format.md
scripts/
dsp-cli.py

詳細

Data Structure Protocol(DSP)

DSP は、プロジェクトのエンティティの依存関係グラフを .dsp/ ディレクトリに構築します。各エンティティ(モジュール、関数、外部依存関係)には、UID、説明、インポート一覧、エクスポートインデックスが割り当てられます。このグラフは、何が存在するのか、なぜ存在するのか、何が何に依存しているのか、誰が何を使用しているのかに答えます。

DSP は、人間向けのドキュメントでも AST のダンプでもありません。 意味(目的)、境界(インポート/エクスポート)、そして つながりの理由(なぜ)を記録します。

エージェント向けプロンプト

DSP で管理されているプロジェクトで作業する際は、このコンテキストを埋め込んでください。

このプロジェクトでは DSP(Data Structure Protocol)を使用しています。 .dsp/ ディレクトリは、このプロジェクトのエンティティグラフです。モジュール、関数、依存関係、公開 API が含まれています。これは、コード構造に関する長期記憶です。

基本ルール:

  1. コードを変更する前に — dsp-cli search、find-by-source、または read-toc で影響を受けるエンティティを見つけます。コンテキストを理解するために、それらの description と imports を読みます。
  2. ファイル/モジュールを作成するとき — dsp-cli create-object を呼び出します。エクスポートする関数ごとに、--owner を指定して create-function を呼び出します。create-shared でエクスポートを登録します。
  3. インポートを追加するとき — 簡潔な理由を why に指定して dsp-cli add-import を呼び出します。外部依存関係の場合は、エンティティがまだ存在しなければ、先に create-object --kind external を実行します。
  4. インポート/エクスポート/ファイルを削除するとき — それぞれ remove-import、remove-shared、remove-entity を呼び出します。関連項目のクリーンアップは自動で行われます。
  5. ファイルの名前を変更/移動するとき — move-entity を呼び出します。UID は変わりません。
  6. 目的や依存関係に影響しない内部実装のみの変更であれば、DSP に手を加えないでください。
  7. TOC への所属 — 新しいエンティティは、そのパスをカバーするルートスコープを持つすべての TOC に追加されます(または、繰り返し指定可能な --toc を明示的に渡します)。add-to-toc/move-to-toc で所属を変更します。
  8. 初期設定 — .dsp/ が空の場合:ルートを検出し(--new-root --scope)、ファイルをボリュームが均等になるよう TOC ごとのバッチに分割してから、バッチ全体に対して並列で 3 段階の処理を行います。すべてのファイルをインデックス化し、次にすべてのエクスポートを登録し、最後にすべてのインポートを登録します。各ファイルを読み込むのは 1 回だけ(Wave 1)で、後続の段階ではその読み込み結果を再利用します。

主なコマンド:

dsp-cli init
dsp-cli create-object <source> <purpose> [--kind external] [--uid UID] [--toc TOC ...] [--new-root [--scope DIR]]
dsp-cli create-function <source> <purpose> [--owner UID] [--uid UID] [--toc TOC ...]
dsp-cli create-shared <exporter_uid> <shared_uid> [<shared_uid> ...]
dsp-cli add-import <importer_uid> <imported_uid> <why> [--exporter UID]
dsp-cli add-to-toc <uid> [<uid> ...] --toc TOC [--toc TOC ...]
dsp-cli move-to-toc <uid> [<uid> ...] --from TOC --to TOC
dsp-cli remove-import <importer_uid> <imported_uid> [--exporter UID]
dsp-cli remove-shared <exporter_uid> <shared_uid>
dsp-cli remove-entity <uid>
dsp-cli move-entity <uid> <new_source>
dsp-cli update-description <uid> [--source S] [--purpose P] [--kind K] [--scope DIR]
dsp-cli get-entity <uid>
dsp-cli get-children <uid> [--depth N]
dsp-cli get-parents <uid> [--depth N]
dsp-cli search <query>
dsp-cli find-by-source <path>
dsp-cli read-toc [--toc ROOT_UID]
dsp-cli get-stats

TOC はルート UID、またはリテラルの default(標準の .dsp/TOC ファイル)です。

CLI の使用

スクリプトは、このスキルディレクトリからの相対パス scripts/dsp-cli.py にあります。

python <skill-path>/scripts/dsp-cli.py [--root <project-root>] <command> [args]

--root の既定値は現在の作業ディレクトリです。引数に指定するすべてのパスは、リポジトリからの相対パスです。

コアコンセプト

  • コード=グラフです。 ノードはオブジェクトと関数です。エッジはimportsとshared/exportsです。
  • 識別にはファイルパスではなくUIDを使います。 パスは属性であり、名前の変更や移動ではUIDは変わりません。
  • 「共有」するとエンティティが作成されます。 公開(エクスポート)されるものは、それぞれ独自のUIDを持ちます。
  • インポートでは「どこから」と「何を」の両方を追跡します。 1つのコードインポートによって、モジュールへのリンクと、特定の共有エンティティへのリンクという、2つのDSPリンクが作成されることがあります。
  • すべてのインポートを網羅します。 インポートされるすべてのファイルやアセットは、.dsp内のオブジェクトでなければなりません。コード、画像、スタイル、設定など、すべてが対象です。
  • whyは、インポートされたエンティティの隣にあるexports/ディレクトリ(逆引きインデックス)に配置します。
  • ルートから始めます。 各ルートのエントリーポイントには、それぞれ独自のTOCファイルがあります。ルートではscope(ディレクトリのサブツリー)を宣言できます。新しいエンティティは、そのパスをルートのスコープに含むすべてのTOCに自動で割り当てられます。
  • 外部依存関係は記録のみです。 kind: externalとし、node_modules/site-packagesなどの詳細には立ち入りません。ただし、exports indexは機能し、どのエンティティがインポートしているかを表示します。
  • 永続的な逆引きインデックスキャッシュです。 .dsp/.cache/には、逆向き隣接関係(imported → importers)が、インポートされたエンティティごとに1つのファイルとして保存されます。これにより、大規模なグラフでも、逆引きやトラバーサルのコマンド(get-recipients、get-parents、get-path、およびget-entityの「exported to」)が再スキャンなしで高速に実行できます。ローカルおよび順方向のコマンド(get-children、get-shared、read-toc、find-by-source、search)はライブファイルを読み込み、キャッシュには触れません。変更コマンドは影響を受けるエントリーのみを差分更新するため、グラフの構築中もキャッシュは正しい状態に保たれます。
    • 自動構築です。 キャッシュがない場合、次の逆引き/トラバーサルコマンド、または逆引きに影響する次の変更時に、自動で構築されます。通常の使用では手動の操作は不要です。
    • グラフと一緒にコミットされます(gitの無視対象ではありません)。通常のgit checkout/pullでは、キャッシュも.dsp/と一緒に更新されます。ただし、.dsp/に影響するmerge/rebaseでは、.cache/のファイルが誤ってマージされたり、競合が残ったりする場合があります。キャッシュは自己検証を行わず、センチネルのみを追跡して内容は追跡しないため、安全のためにその後rebuild-cacheを実行してください。
    • rebuild-cacheです。 このCLIの外部で.dsp/が変更された場合(手動編集、または.dsp/に影響するmerge/rebase)、python <skill-path>/scripts/dsp-cli.py rebuild-cacheを実行してください。プロトコルに従うエージェントは、dsp-cliのみを使って.dsp/を変更するため、通常の作業ではほとんど必要ありません。

UID形式

  • オブジェクト:obj-<8 hex>(例:obj-a1b2c3d4)
  • 関数:func-<8 hex>(例:func-7f3a9c12)

ソースコード内のUIDマーカー — 宣言の前にコメント@dsp <uid>を記述します。

// @dsp func-7f3a9c12
export function calculateTotal(items) { ... }
# @dsp obj-e5f6g7h8
class UserService:

ワークフロー

DSP のセットアップ(3 つのウェーブでブートストラップ)

コアとなる経済ルール:各ファイルは、1 つのサブエージェントによって、ちょうど 1 回だけ読み取られます。3 つのウェーブはすべて、この 1 回の読み取りを前提に実行されます。バッチは並列で実行され、唯一の同期ポイントは Wave 3 の前のバリアです。

  1. dsp-cli init を実行して .dsp/ ディレクトリを作成します。
  2. フェーズ 0 — ルート:エントリーポイントとそのディレクトリ範囲を特定し、それぞれについて create-object <path> <purpose> --new-root --scope <dir> を使って作成します(. = リポジトリ全体)。スコープにより、以降のすべての項目の TOC 割り当てが自動化されます。
  3. インベントリとバッチ分け:サイズを含むプロジェクト内の全ファイルを列挙します(例:git ls-files | xargs wc -c。ベンダーコード、ビルド出力、ロックファイルは除外します)。TOC ごとにグループ化し、各グループをおおむね同じ量になるようバッチに分割します。サブエージェントごとに 1 バッチを割り当て、並列で実行します。
  4. Wave 1 — 全ファイル:各サブエージェントは担当バッチの各ファイルを1 回だけ読み取り(目的、エンティティ、エクスポート、使用箇所を含むインポートを記録)、登録します:create-object と、重要な内部エンティティ用の create-function --owner、およびソース内の @dsp マーカー。
  5. Wave 2 — 全エクスポート:同じサブエージェントが再読み取りせずに、ファイルごとに create-shared を実行します(バッチ内で完結し、他のバッチを待つ必要はありません)。
  6. バリア:すべてのバッチで Wave 1〜2 が完了したら、サブエージェントが外部依存を報告します。オーケストレーターは重複を取り除き、それぞれを 1 回だけ登録します(create-object --kind external と、それを使用する他のルートに対する add-to-toc)。
  7. Wave 3 — 全インポート:同じサブエージェントが、引き続き再読み取りせずに、使用状況に基づく why を指定して add-import を実行します(未使用のインポートは Wave 1 の読み取り時にすでに除外されています)。ターゲットは find-by-source で解決します。
  8. 検証します:get-stats、get-orphans、detect-cycles を実行し、すべてのインベントリファイルが find-by-source で解決できることを確認します。詳細:bootstrap.md。

コードにすでに @dsp マーカーがあるプロジェクトを再インデックスする場合は、各作成手順で古い UID を --uid に渡します。グラフは安定した識別子を保ったまま再構築されます。

エンティティの作成(新しいコードを書く場合)
  1. モジュールを作成します:dsp-cli create-object <path> <purpose> — パスを含むルートスコープのすべての TOC に登録されます(--toc <TOC> で上書き可能。複数指定できます)
  2. 関数を作成します:dsp-cli create-function <path>#<symbol> <purpose> --owner <module-uid>
  3. エクスポートを登録します:dsp-cli create-shared <module-uid> <func-uid> [<func-uid> ...] — shared エントリは既存エンティティの UID であり、エクスポート名ではありません
  4. インポートを登録します:dsp-cli add-import <this-uid> <imported-uid> <why> [--exporter <module-uid>] — すべての UID がすでに存在している必要があります
  5. 外部依存関係:dsp-cli create-object <package-name> <purpose> --kind external
グラフのナビゲーション(コードを読んで理解する場合)
  • ファイルからエンティティを検索:dsp-cli find-by-source <path>
  • キーワードで検索:dsp-cli search <query>
  • TOC を読み取る:dsp-cli read-toc → すべての UID を取得し、その後 get-entity で詳細を確認します
  • 依存関係ツリーを下方向にたどる:dsp-cli get-children <uid> --depth N
  • 依存関係ツリーを上方向にたどる:dsp-cli get-parents <uid> --depth N
  • 影響分析:dsp-cli get-recipients <uid> — このエンティティに依存しているもの
  • エンティティ間のパス:dsp-cli get-path <from> <to>
更新(コードを変更する場合)
  • 目的の変更:dsp-cli update-description <uid> --purpose <new>
  • ファイルの移動:dsp-cli move-entity <uid> <new-path>
  • インポート理由の変更:dsp-cli update-import-why <importer> <imported> <new-why>
  • ルートの範囲の変更:dsp-cli update-description <root-uid> --scope <dir>
TOC メンバーシップの管理
  • 既存エンティティを他の TOC に追加:dsp-cli add-to-toc <uid> [<uid> ...] --toc <TOC>(冪等。例:2 つ目のルートが使用する外部依存)
  • TOC 間でエンティティを移動(単一またはバッチ):dsp-cli move-to-toc <uid> [<uid> ...] --from <TOC> --to <TOC> — すべて成功するか、すべて失敗します。ルートは自身の TOC から移動できません
  • <TOC> はルート UID または default です
削除(コードを削除する場合)
  • インポートを削除:dsp-cli remove-import <importer> <imported> [--exporter UID]
  • エクスポートを削除:dsp-cli remove-shared <exporter> <shared>
  • ファイル/モジュールを削除:dsp-cli remove-entity <uid>(連鎖的にクリーンアップ)
診断
  • dsp-cli detect-cycles [--toc ROOT_UID] — 循環依存(--toc を指定すると、1 つの TOC ルートのエンティティに範囲を限定します)
  • dsp-cli get-orphans [--toc ROOT_UID] — 未使用のエンティティ(--toc を指定すると、1 つの TOC ルートのエンティティに範囲を限定します)
  • dsp-cli get-stats [--toc ROOT_UID] — プロジェクトグラフの概要(--toc を指定すると、1 つの TOC ルートのエンティティに範囲を限定します)

DSP を更新するタイミング

コードの変更DSP の操作
新しいファイル/モジュールcreate-object + create-function + create-shared + add-import
新しいインポートを追加add-import(新しい外部依存関係の場合は create-object --kind external も実行)
インポートを削除remove-import
エクスポートを追加create-shared(新しい関数の場合は create-function も実行)
エクスポートを削除remove-shared
ファイル名を変更/移動move-entity
ファイルを削除remove-entity
目的を変更update-description
モジュールを別のサブプロジェクト/ルートに移動move-to-toc(パスも変更された場合は move-entity も実行)
エンティティが別のルートから使用されるようになったadd-to-toc
内部のみの変更DSP の更新は不要です

参考資料

コメント