data-structure-protocol について
プロジェクトのコードエンティティと依存関係を `.dsp/` にグラフとして記録するスキルおよび CLI プロトコルです。コーディングエージェントによる索引作成、探索、影響分析と、コード変更に合わせたグラフの更新を支援します。
主な機能
- 01エンティティと依存関係をグラフ化
- 02目的、インポート、エクスポートを記録
- 03プロジェクト内のエンティティを検索・探索
- 04依存元と依存経路を分析
- 05コード変更に応じてグラフ記録を更新
- 06循環依存と孤立エンティティを診断
活用シーン
- 01コードベースの導入時にグラフを構築
- 02コード変更前に依存関係を確認
- 03モジュールや関数の変更影響を評価
- 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.jsonLICENSEreferences/bootstrap.mdoperations.mdstorage-format.mdscripts/dsp-cli.py詳細
Data Structure Protocol(DSP)
DSP は、プロジェクトのエンティティの依存関係グラフを .dsp/ ディレクトリに構築します。各エンティティ(モジュール、関数、外部依存関係)には、UID、説明、インポート一覧、エクスポートインデックスが割り当てられます。このグラフは、何が存在するのか、なぜ存在するのか、何が何に依存しているのか、誰が何を使用しているのかに答えます。
DSP は、人間向けのドキュメントでも AST のダンプでもありません。 意味(目的)、境界(インポート/エクスポート)、そして つながりの理由(なぜ)を記録します。
エージェント向けプロンプト
DSP で管理されているプロジェクトで作業する際は、このコンテキストを埋め込んでください。
このプロジェクトでは DSP(Data Structure Protocol)を使用しています。
.dsp/ディレクトリは、このプロジェクトのエンティティグラフです。モジュール、関数、依存関係、公開 API が含まれています。これは、コード構造に関する長期記憶です。基本ルール:
- コードを変更する前に —
dsp-cli search、find-by-source、またはread-tocで影響を受けるエンティティを見つけます。コンテキストを理解するために、それらのdescriptionとimportsを読みます。- ファイル/モジュールを作成するとき —
dsp-cli create-objectを呼び出します。エクスポートする関数ごとに、--ownerを指定してcreate-functionを呼び出します。create-sharedでエクスポートを登録します。- インポートを追加するとき — 簡潔な理由を
whyに指定してdsp-cli add-importを呼び出します。外部依存関係の場合は、エンティティがまだ存在しなければ、先にcreate-object --kind externalを実行します。- インポート/エクスポート/ファイルを削除するとき — それぞれ
remove-import、remove-shared、remove-entityを呼び出します。関連項目のクリーンアップは自動で行われます。- ファイルの名前を変更/移動するとき —
move-entityを呼び出します。UID は変わりません。- 目的や依存関係に影響しない内部実装のみの変更であれば、DSP に手を加えないでください。
- TOC への所属 — 新しいエンティティは、そのパスをカバーするルートスコープを持つすべての TOC に追加されます(または、繰り返し指定可能な
--tocを明示的に渡します)。add-to-toc/move-to-tocで所属を変更します。- 初期設定 —
.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 の前のバリアです。
dsp-cli initを実行して.dsp/ディレクトリを作成します。- フェーズ 0 — ルート:エントリーポイントとそのディレクトリ範囲を特定し、それぞれについて
create-object <path> <purpose> --new-root --scope <dir>を使って作成します(.= リポジトリ全体)。スコープにより、以降のすべての項目の TOC 割り当てが自動化されます。 - インベントリとバッチ分け:サイズを含むプロジェクト内の全ファイルを列挙します(例:
git ls-files | xargs wc -c。ベンダーコード、ビルド出力、ロックファイルは除外します)。TOC ごとにグループ化し、各グループをおおむね同じ量になるようバッチに分割します。サブエージェントごとに 1 バッチを割り当て、並列で実行します。 - Wave 1 — 全ファイル:各サブエージェントは担当バッチの各ファイルを1 回だけ読み取り(目的、エンティティ、エクスポート、使用箇所を含むインポートを記録)、登録します:
create-objectと、重要な内部エンティティ用のcreate-function --owner、およびソース内の@dspマーカー。 - Wave 2 — 全エクスポート:同じサブエージェントが再読み取りせずに、ファイルごとに
create-sharedを実行します(バッチ内で完結し、他のバッチを待つ必要はありません)。 - バリア:すべてのバッチで Wave 1〜2 が完了したら、サブエージェントが外部依存を報告します。オーケストレーターは重複を取り除き、それぞれを 1 回だけ登録します(
create-object --kind externalと、それを使用する他のルートに対するadd-to-toc)。 - Wave 3 — 全インポート:同じサブエージェントが、引き続き再読み取りせずに、使用状況に基づく
whyを指定してadd-importを実行します(未使用のインポートは Wave 1 の読み取り時にすでに除外されています)。ターゲットはfind-by-sourceで解決します。 - 検証します:
get-stats、get-orphans、detect-cyclesを実行し、すべてのインベントリファイルがfind-by-sourceで解決できることを確認します。詳細:bootstrap.md。
コードにすでに @dsp マーカーがあるプロジェクトを再インデックスする場合は、各作成手順で古い UID を --uid に渡します。グラフは安定した識別子を保ったまま再構築されます。
エンティティの作成(新しいコードを書く場合)
- モジュールを作成します:
dsp-cli create-object <path> <purpose>— パスを含むルートスコープのすべての TOC に登録されます(--toc <TOC>で上書き可能。複数指定できます) - 関数を作成します:
dsp-cli create-function <path>#<symbol> <purpose> --owner <module-uid> - エクスポートを登録します:
dsp-cli create-shared <module-uid> <func-uid> [<func-uid> ...]— shared エントリは既存エンティティの UID であり、エクスポート名ではありません - インポートを登録します:
dsp-cli add-import <this-uid> <imported-uid> <why> [--exporter <module-uid>]— すべての UID がすでに存在している必要があります - 外部依存関係:
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 の更新は不要です |
参考資料
- ストレージ形式 —
.dsp/ディレクトリ構造、ファイル形式、TOC - ブートストラップ手順 — プロジェクトの初期マーキング(3 波アルゴリズム)
- 操作リファレンス — インポートの例を含む、すべての操作の詳細な仕様