关于 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
提取代码库的结构地图:界面、功能、实体、关系、操作、流程、分区和技术栈。四个正交维度——界面是你前往的地方(页面/入口点),功能是你可以执行的操作(独立能力),实体是应用处理的对象(数据),分区是代码的组织方式(连接产品概念与底层代码库的逻辑文件分组)。技术栈则全面列出项目使用的所有技术、框架和库。
工作流
意图检测
默认模式为全面扫描——生成完整的代码库结构地图和代码健康状况评估。除非用户的消息明确要求以下特定不变量模式之一,否则都运行此模式。
以下两种范围更窄的模式会覆盖默认模式:
- 添加不变量——消息包含“add invariant”“new invariant”或“add this invariant: '...'” → 添加不变量流程。
- 独立验证——消息包含“verify”“check invariants”“run invariants”或类似内容 → 独立验证流程。
全面扫描
扫描分为四个步骤:
- 发现——读取代码库,构建每项提取任务所需的上下文。
- 提取——生成结构地图。
- 分析——评估汇总后的地图,检查代码健康状况和不变量。
- 汇总——将所有内容合并到
.cartograph/mapping.json。
在提取和分析过程中,只要输入已就绪,就通过子 Agent 并行执行任务——不要在编排器中按顺序运行,因为运行时间很重要。自然的并行批次如下:
{ 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" - 组件:
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= 一个“创作工作室”界面)。 - 查找仅限管理员使用的区域、独立工具、仪表板和引导流程。
- 对于每个界面,确定:入口点(主页面文件和路由)、使用者(用户/管理员/系统)、描述(该界面作为独立体验的功能)。
返回: 界面数组(不包含 entityIds、operationIds、flowIds 或 compartmentIds——这些会由后续任务和汇总步骤补充)。
实体 + 关系
依赖: discover。
实体 — 阅读架构/类型定义并提取领域对象:
- 数据库模型(高置信度)— Prisma 模型、TypeORM 实体、Mongoose 架构。
- TypeScript 类型/接口(中置信度)— 用作 API 负载、表单数据、状态的类型。
- 枚举(高置信度)— 表示领域概念的枚举定义。
- 派生类型(中置信度)— 类似
PostWithAuthor的转换版本。
对于每个实体:记录 id、名称、种类、描述、源位置、关键字段(最重要的 3–8 个)和置信度。
关系 — 映射实体间的连接:
- 架构中的外键和引用 →
has-many、belongs-to、has-one。 - 嵌套的 includes/joins → 确认关系。
- 类型组合 →
derives-from。 - 较宽松的引用 →
references。
返回: 两个数组 — entities 和 relationships。
功能
依赖: discover、surfaces、entities。
功能是嵌入在界面中的独立能力 — 即你在应用中能做什么,而不是去哪里。点赞按钮、提示词向导、积分购买、年龄门禁都是功能。它们组合成界面;它们本身不是页面。
如果描述某项功能时离不开具体页面的名称,那么它很可能属于界面,而不是功能。
六种类型 — 工具、交互、交易、门禁、基础设施、工作流 — 以及标志每种类型的代码模式,都列在 references/feature-kinds.md 中。将其用作扫描清单。
不同实现应视为不同功能。 同一概念能力通常会在不同界面中以独立实现的形式存在 — 例如聊天中的面向用户的“提示词向导”模态框,以及帖子管理区域中的管理端“提示词改编向导”。务必分别创建功能条目,并为它们指定不同的名称。从一个界面提取功能后,还要扫描其他界面的组件树,查找类似模式,并 grep 共享服务导入 — 这是最容易遗漏的一类功能。
对于每项功能,记录:名称、描述、种类、surfaceIds、entityIds、实现(2–5 个最重要的文件,而非全部文件)。
返回: features 数组(不含 compartmentIds — 由 Compartment Dependencies 填充)。
操作
依赖: discover、entities。
对于每个入口点(路由处理程序、服务端操作、API 端点):
- 它针对哪个实体。
- 操作类型:
create、read、update、delete或domain。 - 描述性名称(例如,“发布帖子”“生成预览”)。
- 对其他实体的副作用。
- 实现位置(文件 + 函数)。
返回: operations 数组。
流程
依赖: discover、surfaces、entities、features、operations。
- 从 UI 页面入手 — 用户在每个页面上能做什么?
- 追踪:UI 操作 → 处理程序 → 服务 → DB。
- 按用户可见的目标为每个流程命名。
- 确定触发条件和执行者(用户/管理员/系统)。
- 按顺序列出步骤,并关联到操作和实体。
返回: flows 数组。
功能模块
需要: 发现、界面、功能、实体、操作。
功能模块是将相关文件归为一组的逻辑单元,构成连贯的功能单元。它们连接了产品视角(界面、功能)与底层代码结构,让开发者能够从“这项功能有什么作用?”找到“相关代码在哪里?”。
- 扫描文件树,并结合界面、功能、实体和操作作为上下文。
- 使用多种信号对文件进行分组:
- 文件夹结构——同一目录中的文件通常彼此相关。
- 导入关系图——相互导入频繁的文件可能属于同一功能模块。
- 功能对应关系——属于某项功能的文件应归入对应的功能模块。
- 领域关联度——处理同一实体或业务概念的文件应归为一组。
- 命名约定——名称相关的文件(例如,
image-*.ts、*-generation.*)可能属于同一功能模块。 - 共享基础设施——供 3 项或更多功能使用的文件可能需要单独设立功能模块,也可能出现在多个功能模块中。
- 功能模块可以嵌套——子模块可按任意深度嵌套。典型 Web 应用通常有 2–3 层。
- 文件可以属于多个模块——同一文件可以出现在多个功能模块中(例如,
lib/prisma.ts同时属于“数据库访问”和“共享基础设施”)。 - **每个非生成文件都必须至少属于一个功能模块。**配置文件、构建工具等应归入“项目基础设施”模块。排除
generated/、node_modules/、.next/、dist/。 - 对每个功能模块,提供:名称和描述(根据其功能命名,而非文件夹名称——“图像生成流水线”,而非“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 个。子模块可以更多。
- 优先采用有意义的分组,而不是与文件夹一一对应。如果文件夹中包含无关文件,应拆分处理。如果相关文件分布在多个文件夹中,则应归为一组。
**返回:**功能模块数组(不含 dependsOn——该字段由 Compartment Dependencies 填充)。
文件树权重
需要: 发现、功能。
为每个非生成文件估算其用途中服务于各项功能的比例。
- 从发现结果包中获取完整文件列表。
- 阅读每个文件(或抽样阅读特别大的文件),并估算各项比例。
- 不属于任何产品功能的文件,其唯一功能权重应设为
"__infrastructure__"。 - 服务于多项功能的文件应按比例分配权重(例如,共享 hook → 各占 50%)。
- 每个文件的所有权重之和必须为 1.0。
估算指南:
- 查看导入项、函数名称、组件名称以及文件的整体用途。
- 完全专用于一项功能的文件 →
[{featureId: "that-feature", weight: 1.0}]。 - 被多项功能使用的共享工具 → 按比例拆分。
- 配置文件、通用类型定义、构建配置、中间件 →
__infrastructure__。 - 优先为每个文件分配较少的功能及较高的权重,避免分配给过多功能且权重极低。
返回:{file, featureWeights: [{featureId, weight}]} 条目数组,每个文件对应一项。
组件依赖关系
需要: 组件(以及用于回填的界面和功能)。
- 遍历每个组件中每个文件的导入项。
- 将每个导入文件映射到它所属的组件。
- 将这些依赖记录为每个组件上的
dependsOn边(仅限组件间依赖,不包括自身引用)。 - 在功能上填充
compartmentIds— 确定每项功能由哪些组件实现。 - 在界面上填充
compartmentIds— 确定每个界面由哪些组件提供服务。
返回: 更新后的组件数组(已填充 dependsOn),以及 featureCompartmentIds 映射和 surfaceCompartmentIds 映射。
3. 分析
对组装完成的提取结果运行分析。
分析任务的报告方式。 每个分析任务都会输出一条指标记录,其中包含分数、阈值对象、一行 summary,以及一个 findings[] 数组。发现项用于解释分数 — 每个导致分数低于 100 的文件或条目都必须作为发现项列出,并提供具体建议。摘要必须包含准确数量(“103 个受评估文件中有 8 个位置不当”),不能使用含糊的描述(“大多数文件的位置都正确”)。
分数低于 100 却没有发现项,就无法采取行动 — 请将其视为输出中的错误,而不是有效结果。
每项任务的具体发现项结构见 references/json-schema.md 中对应指标的说明。
位置共置
读取项目说明文件(AGENTS.md、CLAUDE.md 或同等文件),提取明确的位置共置约定。如果没有找到,则使用以下默认规则:
- 仅供单个界面使用的文件应放在该界面的目录中。
- 供多个界面使用、但代表一项功能的文件应放在
features/<capability>/中。 - 根目录下的
components/、lib/和actions/仅用于供 3 个或更多界面/功能使用的全局代码。 components/ui/*不受此规则限制,视为位置正确。
评估每个非生成、非基础设施文件:
- 追踪导入该文件的所有文件。
- 确定实际使用该文件的界面/功能。
- 将其当前位置与规则要求的位置进行比较。
- 判定为二元
pass/fail。
对于每个未通过的文件,输出一条发现项,并将 action 设为 "move"(移入界面或功能目录以实现共置)或 "promote"(将其移至 features/,因为它服务于多个界面)。包含 file、verdict、reason、consumers[] 和 recommendation。
分数:(通过的文件数 / 受评估文件总数) * 100。
返回: 一个 id: "co-location" 的指标对象。
DRY 程度
- 以功能和组件作为起始映射。
- 在读取文件之前查找可能的重复项:
- 不同界面中
kind相同且entityIds有重叠的功能。 - 位于不同界面中、名称或导入模式相似的文件。
- 描述、标签相似或
featureIds有重叠的组件。 - 封装相同外部 API 或工作流的钩子/操作/客户端。
- 不同界面中
- 阅读候选项以确认是否确实重叠 — 同时考虑功能重叠(重复解决相同的产品问题)和结构相似性(以少量变化重复相同的技术模式)。
- 对每项已确认的重复,指出哪些内容确实可以共享、哪些必须保留为特定实现,以及共享逻辑应放置在哪里(遵循位置共置规则)。
每条发现项都包含 id、title、severity、implementations[]、sharedLogic[] 和 recommendation。
分数:K = 200 / totalNonInfrastructureFiles;score = max(0, 100 - (findingCount * K))。
返回: 一个 id: "dryness" 且包含 scalingFactor 的指标对象。
死代码
- 为每个非生成文件构建导入映射(解析相对导入和
@/路径别名)。 - 使用
references/dead-code-detection.md中的始终有效入口点列表——即使没有任何导入者,这些入口点也永远不算死代码。 - 遍历代码库,查找
references/dead-code-detection.md中记录的五种发现类型:dead-file— 非入口点且没有导入者。test-only-file— 仅被测试导入的非测试文件(仅供参考;不影响分数)。orphaned-surface— 没有入站导航引用的界面。orphaned-feature—surfaceIds为空或所有界面均为孤立界面的功能。dead-entity— 没有操作、功能或查询引用的数据库模型或 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" 的指标对象。
不变量
仅当仓库根目录存在 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:
- 根据操作、流程和 Compartment Dependencies 输出,为每个界面填充
entityIds、operationIds、flowIds和compartmentIds。 - 根据 Compartment Dependencies 输出,为每个功能填充
compartmentIds。设置"files": [](空数组是向后兼容的格式;compartmentIds是主要的代码映射)。 - 原样包含 Discover 中的
techStack数组。 - 在
fileTree下原样包含 File Tree Weights 数组。 - 添加顶层
codeHealth对象:analyzedAt = ISO timestamp,metrics = [coLocationMetric, drynessMetric, deadCodeMetric]。 - 如果不变量分析返回了非空结果,则包含
"invariants": <result>。如果结果为null,则省略此键。 - 在仓库根目录写入
.cartograph/mapping.json,必要时创建.cartograph/目录。最终结构见references/json-schema.md。 - 告知用户:“在项目根目录运行
npm --prefix skills/cartograph/app install一次以启动 Cartograph UI,然后运行npm --prefix skills/cartograph/app start。”如果已验证不变量,还要打印不变量摘要(格式与独立验证相同)。
添加不变量流程
当用户想要添加新不变量时:
- 提取用户的断言文本(“add invariant:”或类似表述后面的自然语言声明)。
- 阅读代码库以理解该断言:
- 找出与该断言相关的文件、函数和模式。
- 确定涉及哪些界面和功能(如果之前已有
.cartograph/mapping.json,则参考其中的 ID 填写surfaceIds和featureIds)。 - 梳理验证方法。
- 按照
references/invariant-definitions-format.md,将单行描述扩展为完整的不变量定义:- 编写 YAML frontmatter:生成唯一的 kebab-case
id;设置severity(涉及资金/安全/数据完整性时为 critical,涉及核心产品逻辑时为 high,涉及约定时为 low);添加相关的tags;可选择添加surfaceIds/featureIds。 - 编写所有正文部分:断言、验证步骤、通过标准、已知范围、验证提示词。
- 编写 YAML frontmatter:生成唯一的 kebab-case
- 将不变量追加到仓库根目录的
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。
验证不变量流程
添加不变量流程、独立验证流程和完整扫描中的不变量分析任务共用此流程。
- 解析不变量:提取 frontmatter 字段和正文部分(参见
references/invariant-definitions-format.md)。 - 如果
enabled: false,则输出"skipped"结果并停止。 - 以验证步骤部分为指南;读取已知范围中列出的文件,以及步骤中引用的任何文件。
- 评估通过标准是否满足:
- 通过:记录已检查的文件,使用空的 violations 数组,并将
fixPrompt设为null。 - 未通过:记录具体违规项,包括文件路径、行号、预期内容、实际内容和建议。生成一条完整自足的
fixPrompt,供 AI Agent 修复具体违规项使用;其中须包含不变量名称、违规详情、受影响的路径/行号以及需要修改的内容。
- 通过:记录已检查的文件,使用空的 violations 数组,并将
- 对每个结果(通过或未通过)都设置
verificationPrompt,其值为不变量定义中的验证提示词。
结果结构位于 references/json-schema.md 的 invariants 键下。
重要说明
- 对分析中的代码库只读 — 切勿修改。仅写入
.cartograph/mapping.json,以及(根据用户要求)cartograph-invariants.md。 - 不确定时,优先纳入并降低置信度,而不是省略。
- 使用通俗易懂的描述 — 产品经理也应能读懂。
- 使用相对路径 — 所有文件路径均相对于仓库根目录。
- 大型仓库 — 按功能或路由目录进行分析,然后合并。