cartograph について
cartograph は、プロダクト構造とコード構成の対応を調べる開発者向けのコードベース分析スキルです。画面、エンティティ、操作、フロー、技術スタックを抽出し、コード健全性の分析を含む構造マップを作成します。
主な機能
- 01画面・機能・エンティティの抽出
- 02エンティティ関係と操作の対応付け
- 03ユーザーフローの追跡
- 04機能別のコード区分
- 05コード健全性と不変条件の分析
- 06技術スタックとファイル比重の整理
活用シーン
- 01大規模コードベースの構造把握
- 02機能を実装するファイルの特定
- 03コード構成と不変条件の確認
- 04コードベース構造マップの作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ noodleflowlabs/ cartograph --skill cartographインストール後、Claude Code で/cartographを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
.DS_Storeapp/package-lock.jsonpackage.jsonserver.mjsapp/checks/check-no-cdn.mjscheck-syntax.mjsapp/ui/cartograph-logo.svgfavicon.svgindex.htmlREADME.mdapp/ui/src/app.jsconfig.jsmain.jsapp/ui/src/components/common.jssessions.jssidebar.jswelcome.jsapp/ui/src/lib/data.jshtml.jsprompts.jsapp/ui/src/views/details.jsengineering.jsoverview.jspanel.jsapp/ui/styles/base.csscontent.csslayout.cssnavigation.cssresponsive.cssviews.css詳細
Cartograph
コードベースの構造マップを抽出します。対象は、サーフェス、機能、エンティティ、関係性、操作、フロー、コンパートメント、技術スタックです。直交する4つの軸があります。サーフェスは移動先(ページ/エントリーポイント)、機能は実行できること(独立した機能)、エンティティはアプリが扱うもの(データ)、コンパートメントはコードの構成方法(プロダクトの概念と基盤となるコードベースをつなぐ論理的なファイル群)です。技術スタックでは、プロジェクトで使用されているすべての技術、フレームワーク、ライブラリを網羅的に一覧化します。
ワークフロー
意図の検出
デフォルトのモードはフルスキャンです。コードベースの完全な構造マップとコードの健全性を出力します。ユーザーのメッセージが、以下の不変条件に特化したモードのいずれかを明確に求めていない限り、このモードを実行してください。
デフォルトを上書きする、より限定的なモードが2つあります。
- 不変条件の追加 — メッセージに「add invariant」、「new invariant」、または「add this invariant: '...'」が含まれる場合 → 不変条件の追加フロー。
- 単独検証 — メッセージに「verify」、「check invariants」、「run invariants」などが含まれる場合 → 単独検証フロー。
フルスキャン
スキャンは4つのステップで構成されます。
- 検出 — コードベースを読み込み、すべての抽出タスクに必要なコンテキストを構築します。
- 抽出 — 構造マップを作成します。
- 分析 — 作成したマップのコードの健全性と不変条件を評価します。
- 組み立て — すべてを
.cartograph/mapping.jsonに統合します。
抽出と分析では、入力の準備ができたタスクをサブエージェントに並列で割り当ててください。オーケストレーターで順番に実行しないでください。実行時間が重要です。自然な並列バッチは次のとおりです。
{ Surfaces, Entities }
→ { Features, Operations }
→ { Flows, Compartments, File Tree Weights }
→ { Compartment Dependencies }
→ { Co-location, DRYness, Dead Code, Invariants }
以下の各タスクには、入力と返却内容が記載されています。すべての返却形式は references/json-schema.md に準拠します。
1. 検出
並列化する前に、これを自分で実行してください。すぐに終わり、すべての抽出タスクで必要になります。
package.jsonを読み込み、プロジェクト名と依存関係を確認します(フレームワークの検出)。- 主要な構造ファイルを glob で検索します。
- スキーマ:
**/*.prisma、**/schema.*、**/models/** - ルート/ページ:
app/**/page.{tsx,ts,jsx,js}、app/api/**/*.{ts,js}、pages/**/*.{tsx,ts} - サーバーアクション:「"use server"」を grep で検索します。
- コンポーネント:
components/**/*.{tsx,jsx} - ライブラリ/サービス:
lib/**/*.{ts,js}、services/**/*.{ts,js}
- スキーマ:
- ディレクトリツリーを読み込み、全体的な構成を把握します。
- 技術スタックを検出します。 使用されている技術ごとに、名前、バージョン、カテゴリ、参照元(見つかった場所)、確信度(高=明示的な依存関係と一致する設定がある、中=依存関係のみ、低=パターンから推定)を記録します。設定ファイル、ファイルパターン、インポートパターンなど、検出シグナルの全カタログは
references/tech-stack-detection.mdにあります。カテゴリ一覧はreferences/json-schema.mdにあります。 - 生成ファイル以外のファイルをすべて収集します。
返却するのは検出バンドルです。ファイルインベントリと技術スタックの配列を含みます。これをすべての抽出タスクと分析タスクに渡してください。
2. 抽出
サーフェス
必要なもの: 検出バンドル。
サーフェスはエントリーポイント、つまり独立したユーザー向け体験です。各アプリは、基本的に複数のサーフェスで構成されます。
- ルートツリー(
app/**/page.tsx)をたどり、ユーザー向けの独立した体験をそれぞれ特定します。 - 関連するルートをサーフェスにまとめます(例:
/create+/create/[id]/edit= 1つの「Creation Studio」サーフェス)。 - 管理者専用エリア、単独ツール、ダッシュボード、オンボーディングフローを探します。
- 各サーフェスについて、エントリーポイント(メインのページファイルとルート)、アクター(ユーザー/管理者/システム)、説明(独立した体験としてこのサーフェスが何をするか)を特定します。
返却内容: サーフェスの配列(entityIds、operationIds、flowIds、compartmentIds は含めません。これらは後続のタスクと組み立て時に補完されます)。
エンティティとリレーションシップ
必要なもの: discover。
エンティティ — スキーマ/型定義を読み取り、ドメインオブジェクトを抽出します。
- DB モデル(高信頼度)— Prisma モデル、TypeORM エンティティ、Mongoose スキーマ。
- TypeScript の型/インターフェース(中信頼度)— API ペイロード、フォームデータ、状態に使用される型。
- 列挙型(高信頼度)— ドメイン概念を表す列挙型定義。
- 派生型(中信頼度)—
PostWithAuthorのような変換済みの型。
各エンティティについて、id、name、kind、description、source location、主要なフィールド(特に重要なものを3~8個)、confidenceを記録します。
リレーションシップ — エンティティ間のつながりをマッピングします。
- スキーマ内の外部キーと参照 →
has-many、belongs-to、has-one。 - ネストされた include/join → リレーションシップを確認します。
- 型の構成 →
derives-from。 - より緩やかな参照 →
references。
返却値: entities と relationships の2つの配列。
機能
必要なもの: discover、surfaces、entities。
機能はサーフェスに組み込まれた独立した能力であり、アプリ内の「どこに行くか」ではなく、「何ができるか」を表します。いいねボタン、プロンプトウィザード、クレジット購入、年齢確認ゲートは、いずれも機能です。機能はサーフェスに組み込まれるものであり、それ自体がページではありません。
特定のページ名を挙げずに機能を説明できない場合、それはおそらく機能ではなくサーフェスの一部です。
6つの種類 — tool、interaction、transaction、gate、infrastructure、workflow — と、それぞれを示すコードパターンは references/feature-kinds.md にまとめられています。スキャン時のチェックリストとして使用してください。
実装が異なれば、別々の機能です。 同じ概念上の能力が、異なるサーフェスに独立した実装として存在することがよくあります。たとえば、チャットのユーザー向け「プロンプトウィザード」モーダルと、投稿管理エリアの管理者向け「プロンプトリミックスウィザード」です。必ず機能エントリを別々に作成し、それぞれ異なる名前を付けてください。1つのサーフェスから抽出した後、ほかのサーフェスのコンポーネントツリーをスキャンして類似パターンを探し、共有サービスのインポートをgrepで検索してください。これは、見落としやすい機能の代表例です。
各機能について、name、description、kind、surfaceIds、entityIds、implementations(特に重要なファイルを2~5個。すべてのファイルではありません)を記録します。
返却値: features 配列(compartmentIds は含めません。Compartment Dependencies が入力します)。
オペレーション
必要なもの: discover、entities。
各エントリーポイント(ルートハンドラー、サーバーアクション、API エンドポイント)について、次を確認します。
- 対象となるエンティティ。
- オペレーションの種類:
create、read、update、delete、またはdomain。 - 説明的な名前(例:「投稿を公開」「プレビューを生成」)。
- ほかのエンティティへの副作用。
- 実装箇所(ファイル+関数)。
返却値: operations 配列。
フロー
必要なもの: discover、surfaces、entities、features、operations。
- UI ページから始め、各ページでユーザーができることを確認します。
- UI 操作 → ハンドラー → サービス → DB の順にたどります。
- 各フローに、ユーザーに見える目標に基づいた名前を付けます。
- トリガーとアクター(user/admin/system)を特定します。
- オペレーションとエンティティにリンクしながら、ステップを順番に列挙します。
返却値: flows 配列。
コンパートメント
必要なもの: 発見、サーフェス、機能、エンティティ、操作。
コンパートメントとは、関連ファイルを機能単位でまとめた論理的なグループです。プロダクト側の視点(サーフェス、機能)と基盤となるコード構造をつなぎ、開発者が「この機能は何をするのか?」から「そのコードはどこにあるのか?」へとたどれるようにします。
- サーフェス、機能、エンティティ、操作を考慮しながら、ファイルツリーを確認します。
- 複数の手がかりを使ってファイルをグループ化します。
- フォルダー構造 — 同じディレクトリにあるファイルは、関連していることがよくあります。
- インポートグラフ — 相互に多くインポートしているファイルは、同じコンパートメントに属する可能性が高くなります。
- 機能との対応 — ある機能に属するファイルは、その機能に対応するコンパートメントにまとめます。
- ドメイン上の近さ — 同じエンティティやビジネス概念を扱うファイルは、まとめます。
- 命名規則 — 関連する名前(例:
image-*.ts、*-generation.*)を持つファイルは、コンパートメントを示している可能性があります。 - 共有インフラストラクチャ — 3 つ以上の機能で使用されるファイルは、独立したコンパートメントにまとめるか、複数のコンパートメントに含めます。
- コンパートメントは入れ子にできます — サブコンパートメントは任意の深さまで入れ子にできます。一般的な Web アプリでは 2〜3 階層です。
- ファイルは複数のコンパートメントに含められます — たとえば、
lib/prisma.tsは「データベースアクセス」と「共有インフラストラクチャ」の両方に含められます。 - 生成されたファイル以外のすべてのファイルを、少なくとも 1 つのコンパートメントに含める必要があります。 設定ファイルやビルドツールなどは「プロジェクトインフラストラクチャ」コンパートメントに含めます。
generated/、node_modules/、.next/、dist/は除外します。 - 各コンパートメントには、名前と説明(フォルダー名ではなく、機能を表す名前にします — 「Image Generation Pipeline」ではなく「app/chat/actions」)、タグ(
references/json-schema.mdの語彙に加えて、必要に応じてカスタムタグを使用)、ファイル(役割:component、hook、action、api、lib、type、config、style、test、other)、parentId(最上位の場合は null)、featureIds、surfaceIdsを指定します。
コンパートメントを有用に保つためのガイドライン:
- 1 つのファイルだけを含むコンパートメントは、本当に独立したモジュールでない限り作成しないでください。小さなグループは親に統合します。
- 一般的な Web アプリでは、最上位のコンパートメントを 8〜15 個にします。サブコンパートメントはそれ以上でも構いません。
- フォルダーと 1 対 1 で対応させるより、意味のあるグループ化を優先します。フォルダー内に無関係なファイルが混在している場合は分割します。関連ファイルが複数のフォルダーにまたがる場合はまとめます。
返却値: compartments 配列(dependsOn は含めません — Compartment Dependencies が設定します)。
ファイルツリーの重み
必要なもの: 発見、機能。
生成されたファイル以外のすべてのファイルについて、ファイルの目的のうち各機能に役立つ割合を推定します。
- discover バンドルからファイル一覧全体を取得します。
- 各ファイルを読み(非常に大きなファイルは一部をサンプリングし)、割合を推定します。
- プロダクト機能に属さないファイルには、唯一の機能の重みとして
"__infrastructure__"を指定します。 - 複数の機能に役立つファイルには、割合に応じた重みを付けます(例:共有フック → 50/50)。
- ファイルごとの重みの合計は 1.0 にする必要があります。
推定のガイド:
- インポート、関数名、コンポーネント名、ファイル全体の目的を確認します。
- 1 つの機能専用のファイル →
[{featureId: "that-feature", weight: 1.0}]。 - 複数の機能で使用される共有ユーティリティ → 割合に応じて分割します。
- 設定ファイル、汎用型定義、ビルド設定、ミドルウェア →
__infrastructure__。 - 1 ファイルあたりの機能数を増やして重みを細分化するより、機能数を絞って重みを大きくします。
返却値: {file, featureWeights: [{featureId, weight}]} エントリーの配列 — ファイルごとに 1 つ。
コンパートメントの依存関係
**必要なもの:**コンパートメント(補完にはサーフェスと機能も必要です)。
- すべてのコンパートメント内にあるすべてのファイルのインポートをたどります。
- インポートされた各ファイルが属するコンパートメントを特定します。
- これらを各コンパートメントの
dependsOnエッジとして記録します(コンパートメント間のみ。自己参照は含めません)。 - 機能の
compartmentIdsを設定します。各機能を実装するコンパートメントを特定します。 - サーフェスの
compartmentIdsを設定します。各サーフェスを提供するコンパートメントを特定します。
返されるもの: dependsOn が設定されたコンパートメント配列と、featureCompartmentIds マップおよび surfaceCompartmentIds マップです。
3. 分析
組み立てられた抽出データを分析します。
分析タスクの報告方法。 各分析タスクは、スコア、しきい値オブジェクト、1 行の summary、および findings[] 配列を含むメトリックレコードを出力します。スコアの根拠となるのは findings です。スコアを 100 未満にしたファイルや項目はすべて、具体的な推奨事項とともに finding に記載する必要があります。summary には「評価対象の 103 ファイルのうち 8 ファイルの配置が不適切」のように、正確な件数を含めてください。「ほとんどのファイルは適切に配置されています」のような曖昧な表現は避けてください。
スコアが 100 未満なのに findings がない場合、対処不能な状態です。有効な結果ではなく、出力の不具合として扱ってください。
各タスク固有の finding の形式は、references/json-schema.md のメトリック名のセクションに記載されています。
同一配置
プロジェクトの指示ファイル(AGENTS.md、CLAUDE.md など)を読み、同一配置に関する明示的な規約を抽出します。見つからない場合は、次の規則を適用します。
- 単一のサーフェスでのみ使用されるファイルは、そのサーフェスのディレクトリ内に配置します。
- 複数のサーフェスで共有され、1 つの機能を表すファイルは、
features/<capability>/に配置します。 - ルートの
components/、lib/、actions/は、3 つ以上のサーフェス/機能で使用される本当にグローバルなコード用に限定します。 components/ui/*は例外とし、適切な配置とみなします。
生成物ではなく、インフラストラクチャにも属さないファイルをすべて評価します。
- そのファイルをインポートするファイルをたどります。
- 実際にそのファイルを使用するサーフェス/機能を特定します。
- 現在の配置と、規則が定める配置を比較します。
- 二値の
pass/fail判定を付けます。
不合格のファイルごとに、action: "move"(サーフェスまたは機能のディレクトリ内に同一配置する)または action: "promote"(複数のサーフェスで使用されるため features/ に移動する)を指定した finding を出力します。file、verdict、reason、consumers[]、recommendation を含めてください。
スコア:(合格ファイル数 / 評価対象ファイル総数) * 100。
返されるもの: id: "co-location" を含むメトリックオブジェクト 1 件。
DRY 度
- 開始時のマップとして、機能とコンパートメントを使用します。
- ファイルを読む前に、重複候補を探します。
- 異なるサーフェスにまたがり、
kindが同じでentityIdsが重複する機能。 - 異なるサーフェスにある、名前やインポートパターンが類似したファイル。
- 説明やタグが類似している、または
featureIdsが重複するコンパートメント。 - 同じ外部 API やワークフローをラップするフック/アクション/クライアント。
- 異なるサーフェスにまたがり、
- 候補を読んで、実際に重複しているか確認します。機能上の重複(同じプロダクト上の問題を二重に解決していること)と、構造上の類似性(軽微な違いを伴い、同じ技術パターンが繰り返されていること)の両方を考慮します。
- 重複が確認されたものごとに、真に共有されている部分、実装固有のままにすべき部分、共有ロジックを配置すべき場所を特定します(同一配置の規則に従います)。
各 finding には、id、title、severity、implementations[]、sharedLogic[]、recommendation を含めます。
スコア:K = 200 / totalNonInfrastructureFiles。score = max(0, 100 - (findingCount * K))。
返されるもの: id: "dryness" と scalingFactor を含むメトリックオブジェクト 1 件。
デッドコード
- 生成ファイル以外のすべてのファイルについて、インポートマップを作成します(相対インポートと
@/パスエイリアスを解決します)。 references/dead-code-detection.mdにある、常に有効なエントリーポイントのリストを使用します。インポート元がゼロでも、これらがデッドとして扱われることはありません。- コードベースを調べ、
references/dead-code-detection.mdに記載されている次の5種類の検出項目を探します。dead-file— インポート元がゼロの非エントリーポイント。test-only-file— テストからのみインポートされる非テストファイル(情報提供のみで、スコアには影響しません)。orphaned-surface— ナビゲーション参照元がないサーフェス。orphaned-feature—surfaceIdsが空、またはすべてのサーフェスが孤立している機能。dead-entity— オペレーション、機能、クエリから参照されていない DB モデルまたは DTO。
各検出項目には、id、kind、severity、target、reason、evidence、recommendation が含まれます。
スコア:totalEvaluated = filesEvaluated + surfacesEvaluated + featuresEvaluated + entitiesEvaluated;deadItems = deadFiles + orphanedSurfaces + orphanedFeatures + deadEntities;score = ((totalEvaluated - deadItems) / totalEvaluated) * 100。テスト専用ファイルは分子と分母の両方から除外します。
戻り値: id: "dead-code" を持つメトリクスオブジェクト1つ。
不変条件
リポジトリのルートに cartograph-invariants.md がある場合にのみ実行します。それ以外の場合は null を返し、Assemble では invariants キーを完全に省略します。
cartograph-invariants.mdを読み取ります。- 各不変条件について、以下の不変条件の検証手順を実行します。
- 概要の件数(合計、合格、不合格、スキップ)を算出します。
verifiedAtに現在の ISO 8601 タイムスタンプを設定し、definitionsFileに"cartograph-invariants.md"を設定します。
戻り値: references/json-schema.md のスキーマに一致する invariants オブジェクト、または null。
4. Assemble
この作業は自分で実行します。すべてを .cartograph/mapping.json にマージします。
- 各サーフェスの
entityIds、operationIds、flowIds、compartmentIdsを、オペレーション、フロー、Compartment Dependencies の出力から設定します。 - 各機能の
compartmentIdsを、Compartment Dependencies の出力から設定します。"files": []を設定します(空配列は後方互換性のための形式であり、主要なコードマッピングはcompartmentIdsです)。 - Discover の
techStack配列をそのまま含めます。 - File Tree Weights 配列をそのまま
fileTreeの下に含めます。 - トップレベルに
codeHealthオブジェクトを追加します。analyzedAt = ISO timestamp、metrics = [coLocationMetric, drynessMetric, deadCodeMetric]とします。 - Invariants の分析で null 以外の結果が返された場合は、
"invariants": <result>を含めます。nullの場合はキーを省略します。 - リポジトリのルートに
.cartograph/mapping.jsonを書き込み、必要に応じて.cartograph/ディレクトリを作成します。最終的な形式はreferences/json-schema.mdに記載されています。 - ユーザーに次のように伝えます。"プロジェクトのルートから Cartograph UI を起動するには、まず
npm --prefix skills/cartograph/app installを実行し、次にnpm --prefix skills/cartograph/app startを実行してください。" 不変条件を検証した場合は、不変条件の概要も出力します(Standalone Verify と同じ形式)。
不変条件の追加フロー
ユーザーが新しい不変条件の追加を希望した場合:
- ユーザーの主張のテキスト(「add invariant:」の後、またはそれに類する表現の後に続く自然言語の主張)を抽出します。
- 主張を理解するためにコードベースを読みます。
- 主張に関連するファイル、関数、パターンを特定します。
- 関係するサーフェスと機能を特定します(以前の
.cartograph/mapping.jsonがある場合は、surfaceIdsとfeatureIdsにその ID を参照します)。 - 検証方法を整理します。
references/invariant-definitions-format.mdに従って、一文の主張を完全な不変条件の定義に展開します。- YAML フロントマターを記述します。一意なケバブケースの
idを生成し、severityを設定します(金銭、セキュリティ、データ整合性には critical、コア製品ロジックには high、規約には low)。関連するtagsを追加し、必要に応じてsurfaceIds/featureIdsを追加します。 - 本文のすべてのセクションを記述します。Assertion、Verification steps、Pass criteria、Known scope、Verification prompt。
- YAML フロントマターを記述します。一意なケバブケースの
- 不変条件をリポジトリのルートにある
cartograph-invariants.mdに追加します。ファイルが存在しない場合は、# Cartograph Invariantsという見出しを付けて作成します。 - 以下の不変条件の検証手順を使って、初回検証を実行します。
- 結果を報告します。
- 合格:「Invariant added and verified. Definition saved to
cartograph-invariants.md.」 - 不合格:「Invariant added but does NOT currently hold — definition saved anyway. Violations: [details]. Fix the code to make it pass, or edit the definition if the assertion needs adjusting.」
- 合格:「Invariant added and verified. Definition saved to
主張が曖昧すぎて検証手順を判断できない場合は、定義を記述する前に確認の質問をしてください。
単独検証フロー
全件スキャンを行わずに、既存の不変条件を検証する場合:
-
リポジトリのルートにある
cartograph-invariants.mdを読みます。ファイルが存在しない場合は、「No invariant definitions found. Add one with:/cartograph add this invariant: '...'」と応答します。 -
ファイル内のすべての不変条件に対して、以下の不変条件の検証手順を実行します。
-
合否の概要をコンソールに出力します。
Invariant Results (N checked) ────────────────────────────────── ✓ CRITICAL Invariant name Summary of passing result ✗ HIGH Invariant name Violation in file:line Brief description of violation N of M invariants passing. -
.cartograph/mapping.jsonが存在する場合は、invariantsキーのみを更新します(ほかのデータはすべて変更せずに残します)。references/json-schema.mdのスキーマに従ってinvariantsオブジェクトを書き込みます。 -
.cartograph/mapping.jsonが存在しない場合は、必要に応じて.cartograph/ディレクトリを作成し、metaとinvariantsキーのみを含む最小限の JSON を書き込みます。
不変条件の検証
「不変条件の追加フロー」、「単独検証フロー」、および全件スキャンの不変条件分析タスクで共通して使用する手順です。
- 不変条件を解析します。フロントマターのフィールドと本文のセクションを抽出します(
references/invariant-definitions-format.mdを参照)。 enabled: falseの場合は、"skipped"の結果を出力して終了します。- Verification steps セクションをガイドとして、Known scope に記載されたファイルに加え、手順で参照されているファイルも読みます。
- Pass criteria を満たしているか評価します。
- 合格:確認したファイルを記録し、空の violations 配列を設定して、
fixPromptをnullに設定します。 - 不合格:ファイルパス、行番号、期待された内容、見つかった内容、提案を含む具体的な違反を記録します。AI エージェントが具体的な違反を修正できるように、自己完結した
fixPromptを生成します。不変条件の名前、違反の詳細、影響を受けるパス/行番号、変更が必要な内容を含めます。
- 合格:確認したファイルを記録し、空の violations 配列を設定して、
- 合否にかかわらず、すべての結果で
verificationPromptに不変条件の定義にある Verification prompt を設定します。
結果の形式は、references/json-schema.md の invariants キーに記載されています。
重要
- 分析対象のコードベースは読み取り専用です — 変更しないでください。書き込みが行われるのは
.cartograph/mapping.jsonのみです(ユーザーから依頼があった場合はcartograph-invariants.mdも書き込まれます)。 - 迷った場合は、省略するよりも確信度を下げて含めることを優先します。
- 平易な表現で説明します — PM が読んで理解できる内容にしてください。
- 相対パスを使用します — すべてのファイルパスはリポジトリのルートからの相対パスです。
- 大規模なリポジトリの場合 — 機能またはルートのディレクトリごとに分析し、統合します。