cartograph
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCartograph
Cartograph
Extract a structural map of a codebase: surfaces, features, entities, relationships, operations, flows, compartments, and tech stack. Four orthogonal axes — surfaces are where you go (pages/entry points), features are what you can do (standalone capabilities), entities are what the app works with (data), and compartments are how the code is organized (logical file groupings that bridge product concepts to the underlying codebase). The tech stack provides a comprehensive inventory of all technologies, frameworks, and libraries the project uses.
提取代码库的结构映射:包括surfaces(界面入口)、features(功能模块)、entities(实体)、关系、操作、flows(业务流程)、compartments(逻辑代码模块)以及技术栈。四个核心维度——surfaces是用户访问的入口(页面/接入点),features是用户可执行的独立功能,entities是应用处理的数据对象,compartments是代码的逻辑组织方式(连接产品概念与底层代码库的文件分组)。技术栈则列出项目使用的所有技术、框架和库的完整清单。
Workflow
工作流程
Intent Detection
意图检测
The default mode is Full Scan — produce a full structural map of the codebase plus code health. Run this unless the user's message clearly asks for one of the invariant-specific modes below.
Two narrower modes override the default:
- Add Invariant — message contains "add invariant", "new invariant", or "add this invariant: '...'" → Add Invariant Flow.
- Standalone Verify — message contains "verify", "check invariants", "run invariants", or similar → Standalone Verify Flow.
默认模式为完整扫描——生成代码库的完整结构映射及代码健康报告。除非用户明确要求以下特定的不变量模式,否则默认执行此模式。
两种窄范围模式会覆盖默认设置:
- 添加不变量——消息包含"add invariant"、"new invariant"或"add this invariant: '...'" → 执行添加不变量流程。
- 独立验证——消息包含"verify"、"check invariants"、"run invariants"或类似表述 → 执行独立验证流程。
Full Scan
完整扫描
A scan has four steps:
- Discover — read the codebase to build the context every extract task needs.
- Extract — produce the structural map.
- Analyze — assess the assembled map for code health and invariants.
- Assemble — merge everything into .
.cartograph/mapping.json
Within Extract and Analyze, fan out via subagents on anything whose inputs are ready — don't run them serially in the orchestrator, wall time matters. The natural parallel batches are:
{ Surfaces, Entities }
→ { Features, Operations }
→ { Flows, Compartments, File Tree Weights }
→ { Compartment Dependencies }
→ { Co-location, DRYness, Dead Code, Invariants }Every task below names its inputs and what it returns. All return shapes conform to .
references/json-schema.md扫描包含四个步骤:
- 发现阶段——读取代码库,构建所有提取任务所需的上下文。
- 提取阶段——生成结构映射。
- 分析阶段——评估已组装的映射,生成代码健康度和不变量报告。
- 组装阶段——将所有结果合并到中。
.cartograph/mapping.json
在提取和分析阶段,只要子任务的输入准备就绪,就通过子代理并行执行——不要在编排器中串行运行,耗时至关重要。天然的并行批次如下:
{ Surfaces, Entities }
→ { Features, Operations }
→ { Flows, Compartments, File Tree Weights }
→ { Compartment Dependencies }
→ { Co-location, DRYness, Dead Code, Invariants }以下每个任务都会说明其输入和返回内容。所有返回格式均符合的定义。
references/json-schema.md1. Discover
1. 发现阶段
Run this yourself before fanning out — it's fast and every Extract task needs it.
- Read for project name and dependencies (framework detection).
package.json - Glob for key structural files:
- Schema: ,
**/*.prisma,**/schema.***/models/** - Routes/Pages: ,
app/**/page.{tsx,ts,jsx,js},app/api/**/*.{ts,js}pages/**/*.{tsx,ts} - Server actions: grep for
"use server" - Components:
components/**/*.{tsx,jsx} - Lib/services: ,
lib/**/*.{ts,js}services/**/*.{ts,js}
- Schema:
- Read the directory tree to understand the overall shape.
- Detect the tech stack. For each technology in use, record name, version, category, source (where you found it), and confidence (high = explicit dependency + matching config; medium = dependency only; low = inferred from patterns). The full catalog of detection signals — config files, file patterns, import patterns — lives in . The category list lives in
references/tech-stack-detection.md.references/json-schema.md - Collect the full non-generated file inventory.
Returns the discover bundle: file inventory + tech stack array. Pass this to every Extract and Analyze task.
在并行执行前自行运行此阶段——速度快,且所有提取任务都需要它的结果。
- 读取获取项目名称和依赖项(用于框架检测)。
package.json - 查找关键结构文件:
- Schema:、
**/*.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}
- Schema:
- 读取目录树,了解代码库的整体结构。
- 检测技术栈。对于每个使用的技术,记录名称、版本、类别、来源(发现位置)和置信度(高=明确依赖+匹配配置;中=仅依赖;低=从模式推断)。完整的检测信号目录——配置文件、文件模式、导入模式——位于。类别列表位于
references/tech-stack-detection.md。references/json-schema.md - 收集所有非生成文件的清单。
返回发现包:文件清单 + 技术栈数组。将此传递给所有提取和分析任务。
2. Extract
2. 提取阶段
Surfaces
Surfaces(界面入口)
Needs: discover.
Surfaces are entry points — self-contained user-facing experiences. Each app is fundamentally a collection of surfaces.
- Walk the route tree () and identify each distinct user-facing experience.
app/**/page.tsx - Group related routes into surfaces (e.g., +
/create= one "Creation Studio" surface)./create/[id]/edit - Look for admin-only areas, standalone tools, dashboards, and onboarding flows.
- For each surface determine: entrypoint (main page file and route), actor (user/admin/system), description (what this surface does as a standalone experience).
Returns: surfaces array (without , , , or — those get back-filled by later tasks and Assemble).
entityIdsoperationIdsflowIdscompartmentIds所需输入:发现包。
Surfaces是入口点——独立的用户面向体验。每个应用本质上都是一组Surfaces的集合。
- 遍历路由树(),识别每个独特的用户面向体验。
app/**/page.tsx - 将相关路由分组为Surfaces(例如:+
/create= 一个"创作工作室"Surface)。/create/[id]/edit - 查找仅管理员可用的区域、独立工具、仪表板和引导流程。
- 为每个Surface确定:入口点(主页面文件和路由)、角色(用户/管理员/系统)、描述(此Surface作为独立体验的功能)。
返回:surfaces数组(不含、、或——这些会在后续任务和组装阶段补全)。
entityIdsoperationIdsflowIdscompartmentIdsEntities + Relationships
Entities(实体)+ 关系
Needs: discover.
Entities — read schema/type definitions and extract domain objects:
- DB models (high confidence) — Prisma models, TypeORM entities, Mongoose schemas.
- TypeScript types/interfaces (medium confidence) — types used as API payloads, form data, state.
- Enums (high confidence) — enum definitions representing domain concepts.
- Derived types (medium confidence) — transformed versions like .
PostWithAuthor
For each entity: id, name, kind, description, source location, key fields (3–8 most important), confidence.
Relationships — map connections between entities:
- Foreign keys and references in schema → ,
has-many,belongs-to.has-one - Nested includes/joins → confirm relationships.
- Type compositions → .
derives-from - Looser references → .
references
Returns: two arrays — and .
entitiesrelationships所需输入:发现包。
Entities——读取Schema/类型定义,提取领域对象:
- 数据库模型(高置信度)——Prisma模型、TypeORM实体、Mongoose Schema。
- TypeScript类型/接口(中置信度)——用作API负载、表单数据、状态的类型。
- 枚举(高置信度)——代表领域概念的枚举定义。
- 派生类型(中置信度)——如这类转换后的类型。
PostWithAuthor
为每个实体记录:id、名称、类型、描述、源位置、关键字段(3–8个最重要的)、置信度。
关系——映射实体之间的关联:
- Schema中的外键和引用 → 、
has-many、belongs-to。has-one - 嵌套包含/连接 → 确认关系。
- 类型组合 → 。
derives-from - 松散引用 → 。
references
返回:两个数组——和。
entitiesrelationshipsFeatures
Features(功能模块)
Needs: discover, surfaces, entities.
Features are standalone capabilities embedded within surfaces — what you can do in the app, as distinct from where you go. A like button, a prompt wizard, a credit purchase, an age gate are all features. They compose into surfaces; they aren't themselves pages.
If you can't describe a feature without naming a specific page, it's probably part of a surface, not a feature.
The six kinds — tool, interaction, transaction, gate, infrastructure, workflow — and the code patterns that signal each are catalogued in . Use that as your scanning checklist.
references/feature-kinds.mdSeparate implementations are separate features. The same conceptual capability often exists as independent implementations in different surfaces — a user-facing "Prompt Wizard" modal in chat and an admin "Prompt Remix Wizard" in the post-management area. Always create separate feature entries; name them distinctly. After extracting from one surface, scan the others' component trees for similar patterns and grep for shared service imports — this is the easiest class of feature to miss.
For each feature record: name, description, kind, , , implementations (2–5 most important files, not every file).
surfaceIdsentityIdsReturns: features array (without — Compartment Dependencies fills that in).
compartmentIds所需输入:发现包、surfaces、entities。
Features是嵌入在Surfaces中的独立功能——用户在应用中可以执行的操作,区别于用户访问的入口。点赞按钮、提示向导、积分购买、年龄验证都是Features。它们组合成Surfaces,但本身不是页面。
如果描述某个功能时必须提到特定页面,那它可能是Surface的一部分,而非独立Feature。
六种类型——工具、交互、事务、验证、基础设施、工作流——以及每种类型对应的代码模式都记录在中。以此作为扫描清单。
references/feature-kinds.md独立实现即为独立Feature。同一概念功能通常在不同Surfaces中有独立实现——例如聊天中的用户端"提示向导"模态框,和帖子管理区域的管理员端"提示重制向导"。始终创建独立的Feature条目;名称要区分开。从一个Surface提取后,扫描其他Surface的组件树寻找相似模式,并搜索共享服务的导入——这是最容易遗漏的Feature类别。
为每个Feature记录:名称、描述、类型、、、实现文件(2–5个最重要的文件,无需全部)。
surfaceIdsentityIds返回:features数组(不含——由模块依赖阶段补全)。
compartmentIdsOperations
Operations(操作)
Needs: discover, entities.
For each entry point (route handler, server action, API endpoint):
- Which entity it targets.
- Operation type: ,
create,read,update, ordelete.domain - Descriptive name (e.g., "Publish Post", "Generate Preview").
- Side effects on other entities.
- Implementation location (file + function).
Returns: operations array.
所需输入:发现包、entities。
针对每个入口点(路由处理器、服务器操作、API端点):
- 它针对的实体。
- 操作类型:、
create、read、update或delete。domain - 描述性名称(例如:"发布帖子"、"生成预览")。
- 对其他实体的副作用。
- 实现位置(文件 + 函数)。
返回:operations数组。
Flows
Flows(业务流程)
Needs: discover, surfaces, entities, features, operations.
- Start from UI pages — what can a user do on each page?
- Trace: UI action → handler → service → DB.
- Name each flow by its user-visible goal.
- Identify trigger and actor (user/admin/system).
- List steps in order, linking to operations and entities.
Returns: flows array.
所需输入:发现包、surfaces、entities、features、operations。
- 从UI页面开始——用户在每个页面可以执行什么操作?
- 追踪:UI操作 → 处理器 → 服务 → 数据库。
- 根据用户可见的目标为每个流程命名。
- 识别触发因素和角色(用户/管理员/系统)。
- 按顺序列出步骤,关联到对应的操作和实体。
返回:flows数组。
Compartments
Compartments(逻辑代码模块)
Needs: discover, surfaces, features, entities, operations.
Compartments are logical groupings of related files that form cohesive units of functionality. They bridge the product-side view (surfaces, features) with the underlying code structure, so a developer can navigate from "what does this feature do?" to "where does that code live?".
- Scan the file tree, using surfaces, features, entities, and operations as context.
- Group files using multiple signals:
- Folder structure — files in the same directory often belong together.
- Import graph — files that heavily import each other are likely in the same compartment.
- Feature alignment — files belonging to a feature should cluster into compartments mapping to those features.
- Domain proximity — files dealing with the same entity or business concept belong together.
- Naming conventions — files with related names (e.g., ,
image-*.ts) suggest a compartment.*-generation.* - Shared infrastructure — files used by 3+ features may warrant their own compartment, or may appear in multiple compartments.
- Compartments are nestable — sub-compartments can be nested to any depth. A typical web app has 2–3 levels.
- Files are non-exclusive — a file can appear in multiple compartments (e.g., in both "Database Access" and "Shared Infrastructure").
lib/prisma.ts - Every non-generated file must appear in at least one compartment. Config files, build tooling, etc. go into a "Project Infrastructure" compartment. Exclude ,
generated/,node_modules/,.next/.dist/ - For each compartment: name and description (name after what it does, not folder names — "Image Generation Pipeline" not "app/chat/actions"), tags (from the vocabulary in , plus custom as needed), files (with role: component, hook, action, api, lib, type, config, style, test, other), parentId (null for top-level), featureIds, surfaceIds.
references/json-schema.md
Guidelines that keep compartments useful:
- Don't create compartments with only 1 file unless it's a genuinely standalone module — merge small groupings into their parent.
- Keep top-level compartments to 8–15 for a typical web app. Sub-compartments can be more.
- Prefer meaningful groupings over 1:1 folder mapping. If a folder mixes unrelated files, split them. If related files span folders, group them.
Returns: compartments array (without — Compartment Dependencies fills that in).
dependsOn所需输入:发现包、surfaces、features、entities、operations。
Compartments是相关文件的逻辑分组,形成内聚的功能单元。它们连接产品视角(surfaces、features)与底层代码结构,让开发者可以从"这个功能做什么?"导航到"代码在哪里?"。
- 扫描文件树,以surfaces、features、entities和operations为上下文。
- 通过多种信号分组文件:
- 文件夹结构——同一目录下的文件通常属于同一组。
- 导入图谱——频繁互相导入的文件可能属于同一模块。
- 功能对齐——属于某个Feature的文件应聚类到对应Feature的模块中。
- 领域相关性——处理同一实体或业务概念的文件属于同一组。
- 命名约定——名称相关的文件(例如、
image-*.ts)暗示属于同一模块。*-generation.* - 共享基础设施——被3个以上Feature使用的文件可能需要独立模块,或属于多个模块。
- Compartments可嵌套——子模块可以嵌套任意深度。典型Web应用有2–3层。
- 文件非排他——一个文件可以属于多个模块(例如同时属于"数据库访问"和"共享基础设施"模块)。
lib/prisma.ts - 所有非生成文件必须至少属于一个模块。配置文件、构建工具等归入"项目基础设施"模块。排除、
generated/、node_modules/、.next/目录。dist/ - 为每个模块记录:名称和描述(按功能命名,而非文件夹名——如"图片生成流水线"而非"app/chat/actions")、标签(来自中的词汇,必要时可自定义)、文件(带角色:组件、钩子、操作、API、库、类型、配置、样式、测试、其他)、parentId(顶级模块为null)、featureIds、surfaceIds。
references/json-schema.md
保持模块实用性的准则:
- 除非是真正独立的模块,否则不要创建仅含1个文件的模块——将小组合并入父模块。
- 典型Web应用的顶级模块保持在8–15个。子模块可以更多。
- 优先选择有意义的分组,而非与文件夹1:1映射。如果文件夹混合了无关文件,拆分它们;如果相关文件跨文件夹,合并它们。
返回:compartments数组(不含——由模块依赖阶段补全)。
dependsOnFile Tree Weights
File Tree Weights(文件树权重)
Needs: discover, features.
For every non-generated file, estimate what proportion of the file's purpose serves each feature.
- Take the full file list from the discover bundle.
- For each file, read it (or sample very large files) and estimate proportions.
- Files that don't belong to any product feature get as their sole feature weight.
"__infrastructure__" - Files serving multiple features get proportional weights (e.g., a shared hook → 50/50).
- All weights for a file must sum to 1.0.
Estimation guidance:
- Look at imports, function names, component names, and the overall purpose of the file.
- A file 100% dedicated to one feature → .
[{featureId: "that-feature", weight: 1.0}] - A shared utility used by multiple features → split proportionally.
- Config files, generic type definitions, build config, middleware → .
__infrastructure__ - Prefer fewer features per file with higher weights over many features with tiny weights.
Returns: array of entries — one per file.
{file, featureWeights: [{featureId, weight}]}所需输入:发现包、features。
针对每个非生成文件,估算文件用途对每个Feature的贡献比例。
- 从发现包中获取完整文件列表。
- 读取每个文件(大文件可抽样)并估算比例。
- 不属于任何产品Feature的文件,其唯一Feature权重为。
"__infrastructure__" - 服务于多个Feature的文件按比例分配权重(例如共享钩子 → 50/50)。
- 单个文件的所有权重总和必须为1.0。
估算指南:
- 查看导入、函数名、组件名以及文件的整体用途。
- 100%专注于一个Feature的文件 → 。
[{featureId: "that-feature", weight: 1.0}] - 被多个Feature使用的共享工具 → 按比例拆分。
- 配置文件、通用类型定义、构建配置、中间件 → 。
__infrastructure__ - 优先选择每个文件关联较少Feature且权重较高,而非关联多个Feature且权重极低。
返回:条目数组——每个文件对应一条。
{file, featureWeights: [{featureId, weight}]}Compartment Dependencies
Compartment Dependencies(模块依赖)
Needs: compartments (plus surfaces and features for back-filling).
- Walk the imports of every file in every compartment.
- Map each imported file to the compartment(s) it belongs to.
- Record these as edges on each compartment (inter-compartment only, no self-references).
dependsOn - Populate on features — for each feature, determine which compartments implement it.
compartmentIds - Populate on surfaces — for each surface, determine which compartments serve it.
compartmentIds
Returns: updated compartments array (with populated), plus a map and a map.
dependsOnfeatureCompartmentIdssurfaceCompartmentIds所需输入:compartments(加上surfaces和features用于补全)。
- 遍历每个模块中所有文件的导入。
- 将每个导入的文件映射到其所属的模块。
- 在每个模块上记录这些依赖边(仅模块间依赖,无自引用)。
dependsOn - 为features填充——针对每个Feature,确定哪些模块实现了它。
compartmentIds - 为surfaces填充——针对每个Surface,确定哪些模块为它提供支持。
compartmentIds
返回:更新后的compartments数组(已填充),以及映射和映射。
dependsOnfeatureCompartmentIdssurfaceCompartmentIds3. Analyze
3. 分析阶段
Runs on the assembled extract.
How analysis tasks report. Each analysis task emits a metric record with a score, a thresholds object, a one-line , and a array. The findings are the explanation for the score — every file or item that pulled the score below 100 must appear as a finding, with a concrete recommendation. The summary must include exact counts ("8 of 103 evaluated files are misplaced"), not vague prose ("most files are correctly placed").
summaryfindings[]A sub-100 score with no findings is unactionable — treat it as a bug in your output, not a valid result.
Each task's specific finding shape lives in under the metric's name.
references/json-schema.md基于已组装的提取结果运行。
分析任务的报告方式。每个分析任务都会生成一条指标记录,包含分数、阈值对象、一行摘要和数组。是分数的解释依据——任何导致分数低于100的文件或项都必须作为finding列出,并附带具体建议。摘要必须包含精确计数("103个评估文件中有8个位置错误"),而非模糊表述("大多数文件位置正确")。
summaryfindings[]findings分数低于100但无findings的结果是不可执行的——视为输出错误,而非有效结果。
每个任务的具体finding格式位于中对应指标的名称下。
references/json-schema.mdCo-location
Co-location(代码共置)
Read project instructions (, , or equivalent) and extract explicit co-location conventions. If none are found, fall back to:
AGENTS.mdCLAUDE.md- Files used by a single surface should live inside that surface's directory.
- Files shared by multiple surfaces but representing one capability belong in .
features/<capability>/ - Root ,
components/, andlib/are reserved for truly global code used by 3+ surfaces/features.actions/ - is exempt and considered correctly placed.
components/ui/*
Evaluate every non-generated, non-infrastructure file:
- Trace which files import it.
- Determine which surfaces/features actually consume it.
- Compare its current location to where the rules say it should live.
- Assign a binary /
passverdict.fail
For each failing file, emit a finding with (co-locate inside a surface or feature directory) or (move up into because it serves multiple surfaces). Include , , , , and .
action: "move"action: "promote"features/fileverdictreasonconsumers[]recommendationScore: .
(passing files / total evaluated files) * 100Returns: one metric object with .
id: "co-location"读取项目说明(、或等效文件),提取明确的代码共置约定。如果未找到,默认遵循:
AGENTS.mdCLAUDE.md- 仅被单个Surface使用的文件应放在该Surface的目录内。
- 被多个Surface使用但代表单一功能的文件应放在目录下。
features/<capability>/ - 根目录的、
components/和lib/保留给真正被3个以上Surfaces/Features使用的全局代码。actions/ - 目录例外,视为位置正确。
components/ui/*
评估所有非生成、非基础设施文件:
- 追踪哪些文件导入了它。
- 确定哪些Surfaces/Features实际使用了它。
- 将其当前位置与规则要求的位置进行比较。
- 分配/
pass二元判定。fail
针对每个判定为fail的文件,生成一条finding,包含(移至Surface或Feature目录内共置)或(移至目录,因为它服务于多个Surfaces)。包含、、、和。
action: "move"action: "promote"features/fileverdictreasonconsumers[]recommendation分数:。
(通过文件数 / 总评估文件数) * 100返回:一个的指标对象。
id: "co-location"DRYness
DRYness(无重复代码)
- Use features and compartments as the starting map.
- Look for candidate duplication before reading files:
- Features with the same and overlapping
kindacross different surfaces.entityIds - Files in different surfaces with similar names or import patterns.
- Compartments with similar descriptions, tags, or overlapping .
featureIds - Hooks/actions/clients that wrap the same external API or workflow.
- Features with the same
- Read the candidates to confirm real overlap — weigh both functional overlap (same product problem solved twice) and structural similarity (same technical pattern repeated with light variation).
- For each confirmed duplication: identify what's genuinely shared, what must stay implementation-specific, and where shared logic should live (respecting co-location rules).
Each finding includes , , , , , and .
idtitleseverityimplementations[]sharedLogic[]recommendationScore: ; .
K = 200 / totalNonInfrastructureFilesscore = max(0, 100 - (findingCount * K))Returns: one metric object with and .
id: "dryness"scalingFactor- 以features和compartments为起始映射。
- 在读取文件前寻找重复候选:
- 不同Surfaces中类型相同且重叠的Features。
entityIds - 不同Surfaces中名称或导入模式相似的文件。
- 描述、标签或重叠的Compartments。
featureIds - 包装同一外部API或工作流的钩子/操作/客户端。
- 不同Surfaces中类型相同且
- 读取候选文件确认真实重叠——同时考量功能重叠(同一产品问题被解决两次)和结构相似性(相同技术模式重复,仅轻微变化)。
- 针对每个确认的重复:识别真正共享的部分、必须保留的实现特定部分,以及共享逻辑应放置的位置(遵循代码共置规则)。
每个finding包含、、、、和。
idtitleseverityimplementations[]sharedLogic[]recommendation分数:;。
K = 200 / 非基础设施文件总数score = max(0, 100 - (finding数量 * K))返回:一个的指标对象,包含。
id: "dryness"scalingFactorDead Code
Dead Code(死代码)
- Build an import map for every non-generated file (resolve relative imports and path aliases).
@/ - Use the always-live entry-point list from — those never count as dead even with zero importers.
references/dead-code-detection.md - Walk the codebase looking for the five finding kinds documented in :
references/dead-code-detection.md- — non-entry-point with zero importers.
dead-file - — non-test file imported only by tests (informational; doesn't affect the score).
test-only-file - — surface with no inbound navigation references.
orphaned-surface - — feature with empty
orphaned-featureor all-orphaned surfaces.surfaceIds - — DB model or DTO with no operation, feature, or query reference.
dead-entity
Each finding includes , , , , , , .
idkindseveritytargetreasonevidencerecommendationScore: ; ; . Exclude test-only files from both numerator and denominator.
totalEvaluated = filesEvaluated + surfacesEvaluated + featuresEvaluated + entitiesEvaluateddeadItems = deadFiles + orphanedSurfaces + orphanedFeatures + deadEntitiesscore = ((totalEvaluated - deadItems) / totalEvaluated) * 100Returns: one metric object with .
id: "dead-code"- 为每个非生成文件构建导入图谱(解析相对导入和路径别名)。
@/ - 使用中的永久活跃入口点列表——即使没有导入者,这些文件也永远不会被视为死代码。
references/dead-code-detection.md - 遍历代码库,寻找中记录的五种finding类型:
references/dead-code-detection.md- ——非入口点且无导入者的文件。
dead-file - ——仅被测试文件导入的非测试文件(信息性,不影响分数)。
test-only-file - ——无入站导航引用的Surface。
orphaned-surface - ——
orphaned-feature为空或所有关联Surfaces均为孤立状态的Feature。surfaceIds - ——无操作、Feature或查询引用的数据库模型或DTO。
dead-entity
每个finding包含、、、、、、。
idkindseveritytargetreasonevidencerecommendation分数:;;。测试专用文件从分子和分母中排除。
总评估数 = 文件评估数 + Surface评估数 + Feature评估数 + 实体评估数死项数 = 死文件数 + 孤立Surface数 + 孤立Feature数 + 死实体数score = ((总评估数 - 死项数) / 总评估数) * 100返回:一个的指标对象。
id: "dead-code"Invariants
Invariants(不变量)
Runs only if exists at the repo root. Otherwise return and Assemble omits the key entirely.
cartograph-invariants.mdnullinvariants- Read .
cartograph-invariants.md - For every invariant, run the Verifying an invariant procedure below.
- Compute summary counts (total, passing, failing, skipped).
- Set to the current ISO 8601 timestamp and
verifiedAttodefinitionsFile."cartograph-invariants.md"
Returns: the object matching the schema in , or .
invariantsreferences/json-schema.mdnull仅当仓库根目录存在时运行。否则返回,组装阶段会完全省略键。
cartograph-invariants.mdnullinvariants- 读取。
cartograph-invariants.md - 针对每个不变量,执行下面的验证不变量流程。
- 计算汇总统计(总数、通过数、失败数、跳过数)。
- 将设置为当前ISO 8601时间戳,
verifiedAt设置为definitionsFile。"cartograph-invariants.md"
返回:符合中schema的对象,或。
references/json-schema.mdinvariantsnull4. Assemble
4. 组装阶段
Run this yourself. Merge everything into :
.cartograph/mapping.json- Populate ,
entityIds,operationIds, andflowIdson each surface — from operations, flows, and the Compartment Dependencies output.compartmentIds - Populate on each feature — from the Compartment Dependencies output. Set
compartmentIds(the empty array is the back-compat shape;"files": []is the primary code mapping).compartmentIds - Include the array from Discover as-is.
techStack - Include the File Tree Weights array as-is under .
fileTree - Add a top-level object:
codeHealth,analyzedAt = ISO timestamp.metrics = [coLocationMetric, drynessMetric, deadCodeMetric] - If the Invariants analysis returned a non-null result, include . If
"invariants": <result>, omit the key.null - Write at the repo root, creating the
.cartograph/mapping.jsondirectory if needed. The final shape lives in.cartograph/.references/json-schema.md - Tell the user: "Start the Cartograph UI from your project root with once, then
npm --prefix skills/cartograph/app install." If invariants were verified, also print the invariant summary (same format as Standalone Verify).npm --prefix skills/cartograph/app start
自行运行此阶段。将所有结果合并到中:
.cartograph/mapping.json- 为每个Surface填充、
entityIds、operationIds和flowIds——来自operations、flows和模块依赖阶段的输出。compartmentIds - 为每个Feature填充——来自模块依赖阶段的输出。设置
compartmentIds(空数组为兼容格式;"files": []是主要代码映射)。compartmentIds - 原样包含发现阶段的数组。
techStack - 原样包含File Tree Weights数组,放在下。
fileTree - 添加顶级对象:
codeHealth,analyzedAt = ISO时间戳。metrics = [coLocationMetric, drynessMetric, deadCodeMetric] - 如果不变量分析返回非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
Add Invariant Flow
添加不变量流程
When the user wants to add a new invariant:
- Extract the user's assertion text (the natural-language claim after "add invariant:" or similar phrasing).
- Read the codebase to understand the assertion:
- Identify relevant files, functions, and patterns related to the assertion.
- Determine which surfaces and features are involved (if a previous exists, reference its IDs for
.cartograph/mapping.jsonandsurfaceIds).featureIds - Map out the verification approach.
- Expand the one-liner into a full invariant definition following :
references/invariant-definitions-format.md- Write the YAML frontmatter: generate a unique kebab-case ; set
id(critical for money/security/data integrity, high for core product logic, low for conventions); add relevantseverity; optionally addtags/surfaceIds.featureIds - Write all body sections: Assertion, Verification steps, Pass criteria, Known scope, Verification prompt.
- Write the YAML frontmatter: generate a unique kebab-case
- Append the invariant to at the repo root. Create the file with a
cartograph-invariants.mdheading if it doesn't exist.# Cartograph Invariants - Run an initial verification using the Verifying an invariant procedure below.
- Report the result:
- Passing: "Invariant added and verified. Definition saved to ."
cartograph-invariants.md - Failing: "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."
- Passing: "Invariant added and verified. Definition saved to
If the assertion is too vague to determine verification steps, ask a clarifying question before writing the definition.
当用户想要添加新不变量时:
- 提取用户的断言文本("add invariant:"或类似表述后的自然语言声明)。
- 读取代码库以理解断言:
- 识别与断言相关的文件、函数和模式。
- 确定涉及的Surfaces和Features(如果之前存在,引用其ID作为
.cartograph/mapping.json和surfaceIds)。featureIds - 规划验证方法。
- 将单行断言扩展为完整的不变量定义,遵循:
references/invariant-definitions-format.md- 编写YAML前置元数据:生成唯一的短横线命名;设置
id(关键=涉及资金/安全/数据完整性,高=核心产品逻辑,低=约定);添加相关severity;可选添加tags/surfaceIds。featureIds - 编写所有正文部分:断言、验证步骤、通过标准、已知范围、验证提示。
- 编写YAML前置元数据:生成唯一的短横线命名
- 将不变量追加到仓库根目录的中。如果文件不存在,创建并添加
cartograph-invariants.md标题。# Cartograph Invariants - 使用下面的验证不变量流程执行初始验证。
- 报告结果:
- 通过:"不变量已添加并验证。定义已保存到。"
cartograph-invariants.md - 失败:"不变量已添加,但当前不成立——定义仍已保存。违规详情:[具体内容]。修复代码使其通过,或调整断言以修改定义。"
- 通过:"不变量已添加并验证。定义已保存到
如果断言过于模糊无法确定验证步骤,在编写定义前先询问澄清问题。
Standalone Verify Flow
独立验证流程
When the user wants to verify existing invariants without a full scan:
-
Readfrom the repo root. If the file doesn't exist: respond "No invariant definitions found. Add one with:
cartograph-invariants.md"./cartograph add this invariant: '...' -
Run the Verifying an invariant procedure below on every invariant in the file.
-
Print a pass/fail summary to the console:
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. -
Ifexists, update only the
.cartograph/mapping.jsonkey (leave all other data untouched). Write theinvariantsobject following the schema ininvariants.references/json-schema.md -
Ifdoesn't exist, create the
.cartograph/mapping.jsondirectory if needed and write a minimal JSON with only.cartograph/andmetakeys.invariants
当用户想要验证现有不变量而不执行完整扫描时:
-
读取仓库根目录的。如果文件不存在:回复"未找到不变量定义。使用
cartograph-invariants.md添加一个。"/cartograph add this invariant: '...' -
对文件中的每个不变量执行下面的验证不变量流程。
-
在控制台打印通过/失败摘要:
不变量结果(已检查N个) ────────────────────────────────── ✓ CRITICAL 不变量名称 通过结果摘要 ✗ HIGH 不变量名称 违规位置:文件:行号 违规简要描述 M个不变量中有N个通过。 -
如果存在,仅更新**
.cartograph/mapping.json键**(保留其他所有数据不变)。按照invariants中的schema写入references/json-schema.md对象。invariants -
如果不存在,必要时创建
.cartograph/mapping.json目录,并写入仅包含.cartograph/和meta键的最小JSON文件。invariants
Verifying an invariant
验证不变量
The shared procedure used by Add Invariant Flow, Standalone Verify Flow, and the Invariants analysis task in Full Scan.
- Parse the invariant: extract frontmatter fields and body sections (see ).
references/invariant-definitions-format.md - If , emit a
enabled: falseresult and stop."skipped" - Follow the Verification steps section as a guide; read files listed in Known scope plus anything the steps reference.
- Evaluate whether the Pass criteria hold:
- Passing: record checked files, an empty violations array, and set to
fixPrompt.null - Failing: record specific violations with file paths, line numbers, what was expected, what was found, and a suggestion. Generate a self-contained that an AI agent can use to fix the specific violations — include the invariant name, violation details, affected paths/lines, and what needs to change.
fixPrompt
- Passing: record checked files, an empty violations array, and set
- Set on every result (passing or failing) to the Verification prompt from the invariant definition.
verificationPrompt
The result shape lives in under the key.
references/json-schema.mdinvariants添加不变量流程、独立验证流程和完整扫描中不变量分析任务共用的流程。
- 解析不变量:提取前置元数据字段和正文部分(参见)。
references/invariant-definitions-format.md - 如果,生成
enabled: false结果并停止。"skipped" - 按照验证步骤部分的指引操作;读取已知范围中列出的文件以及步骤引用的任何文件。
- 评估通过标准是否成立:
- 通过:记录已检查文件,违规数组为空,设为
fixPrompt。null - 失败:记录具体违规,包含文件路径、行号、预期结果、实际结果和建议。生成AI代理可用于修复特定违规的独立——包含不变量名称、违规详情、受影响路径/行号以及需要修改的内容。
fixPrompt
- 通过:记录已检查文件,违规数组为空,
- 为每个结果(通过或失败)设置,值为不变量定义中的验证提示。
verificationPrompt
结果格式位于的键下。
references/json-schema.mdinvariantsImportant
重要说明
- Read-only on the analyzed codebase — never modify it. Only and (on user request)
.cartograph/mapping.jsonare written.cartograph-invariants.md - Prefer inclusion with lower confidence over omission when unsure.
- Plain-language descriptions — a PM should be able to read them.
- Relative paths — all file paths relative to repo root.
- Large repos — analyze by feature/route directory and merge.
- 仅读取被分析的代码库——绝不修改它。仅写入和(用户请求时)
.cartograph/mapping.json。cartograph-invariants.md - 不确定时优先低置信度包含,而非遗漏。
- 使用通俗易懂的描述——产品经理应能读懂。
- 使用相对路径——所有文件路径相对于仓库根目录。
- 大型仓库——按功能/路由目录分析后合并结果。