关于 code-to-catalog
code-to-catalog 通过基于代码证据的访谈分析代码库,并生成 EventCatalog 文档计划。它既支持从零规划目录,也支持将现有目录与当前代码对照。
主要功能
- 01代码库发现与盘点
- 02检查现有目录的差异
- 03引用证据的结构访谈
- 04生成待审批计划文件
- 05移交文档生成
适用场景
- 01为尚无文档的代码库规划目录
- 02发现新增或变更的架构资源
- 03复核代码中未找到的目录条目
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ event-catalog/ skills --skill code-to-catalog安装后在 Claude Code 中输入/code-to-catalog确认已加载。
附带文件references/discovery.mdreferences/grilling.md
详细介绍
代码转目录
通过引导式、基于证据的访谈,将代码库转换为 EventCatalog 文档。适用于两种情况:
- 尚无目录 — 从头开始记录不熟悉或尚未记录的代码库。
- 已有目录 — 根据当前代码协调目录(添加新资源、标记偏差、找出过时条目)。
此技能本身不会编写目录文件。它会生成一个计划文件(.catalog-plan.md),记录双方达成一致的架构模型,然后交由 catalog-documentation-creator 技能生成实际文档。
此技能的工作方式
此技能分为六个阶段。请按顺序执行——后续阶段依赖前面的阶段。
- 定位并清点 — 找到代码目录和任何现有目录
- 探索扫描 — 阅读代码并形成假设
- 协调现有目录 — 将发现分类为
new/update/unchanged/investigate - 分层提问 — 只就结构性决策访谈用户
- 生成计划文件 — 编写
.catalog-plan.md并征求批准 - 交接 — 询问用户是现在生成目录,还是止步于计划
对话风格(全程适用)
- 一次只问一个问题。 不要一次提出多个问题。用户回答后再继续。
- 始终提供建议答案。 每个问题都要包含你认为正确的答案及其依据(文件路径 + 行号)。用户可以确认、纠正或推翻。
- 引用代码。 提出发现时,指出你发现它的文件,例如
src/orders/events.ts:42。用户应能自行核实,而不必盲目信任你。 - 如实说明不确定之处。 如果代码无法说明某项内容是事件还是命令,就要明说,不要默默猜测。
- 指出冲突,不要擅自决定。 目录与代码不一致时,由用户决定。未经确认,绝不覆盖。
- 尊重用户的时间。 分层提问是有意为之——只询问结构性决策。不要针对各资源字段(摘要、所有者、架构)提问。
- 不删除目录中的资源。 对于目录中存在但在代码中找不到的资源,标记为
investigate——绝不自动删除。
阶段 1:定位并清点
查找代码库
询问用户:“应该分析哪个代码目录?”
确认目录存在且看起来是一个代码项目(包含 package.json、pom.xml、go.mod、Cargo.toml、pyproject.toml、源代码目录等)。如果目录范围不明确(例如单体仓库),请确认分析范围:整个仓库,还是某个特定子目录。
查找目录
询问用户:“你已经有 EventCatalog 项目了吗?还是想从头开始?”
如果用户已经有一个:
- 询问路径。检查
eventcatalog.config.js或标准目录(services/、agents/、events/、commands/、queries/、domains/、systems/、channels/、containers/、flows/),以确认这是一个 EventCatalog 项目。 - 清点现有内容。如果已连接 EventCatalog MCP 服务,则使用
getResources、getResource、findResourcesByOwner。否则,直接读取文件系统并解析每个index.md/index.mdx的 frontmatter。 - 记录每项资源的:
id、name、version、type、summary,以及(对于服务和 Agent)sends/receives关系。 - 记录目录的惯例:嵌套结构(
domains/X/systems/S/services/Y/events/Z)还是扁平结构、PascalCase 还是 kebab-case ID、现有所有者,以及正在使用的架构格式。
如果用户没有目录:
- 没关系。请注明将在交接时通过
catalog-documentation-creator创建脚手架(该技能会运行npx @eventcatalog/create-eventcatalog@latest <name> --empty)。 - 阶段 3(协调)将不执行任何操作——所有发现都将标记为
new。
阶段 2:发现扫描
阅读代码库并形成假设。暂时不要向用户展示你的发现——你会在阶段 4 中以问题的形式提出,并提供证据支持。
有关各语言/框架(Node.js、Python、Go、Java、.NET)的详细检测启发,请参阅 references/discovery.md。如果代码库使用的技术栈需要相关指引,请现在阅读该文件。
检测:
项目结构
- 单体仓库还是单个服务(查找工作区配置:
pnpm-workspace.yaml、带有workspaces的package.json、nx.json、turbo.json、lerna.json,以及带有各自清单文件的多个顶层服务目录)。 - 各服务或 Agent 使用的语言和框架。
- 构建/部署单元(Dockerfiles、Helm charts、
serverless.yml、cdkstacks、k8s manifests)。
服务边界
服务是可独立部署、可独立负责的单元。参考信号:
- 拥有自己清单文件的独立包
- 独立的 Dockerfile/部署配置
- 自己的入口点(
main.ts、main.go、app.py等) - 通过网络边界(HTTP、消息总线)供其他服务调用
如有疑问,将其标记为候选项,并在阶段 4 中向用户深入确认。
系统(候选项)
系统由构成某个产品或平台的服务、Agent 和数据存储组成(L1 图会在某个领域内展示这些内容)。参考信号:
- 会一并部署多个服务的代码库、单体仓库应用组,或 Helm umbrella chart/CDK app
- 多个服务共用的产品名称(
billing-api、billing-worker、billing-db→Billing系统) - 仅由某一组服务共用的数据存储
单服务代码库通常不需要系统。将候选项标记出来,并在主题 1 中确认。
外部系统
代码会调用的第三方 API 和 SaaS(Stripe、Twilio、Salesforce、SendGrid——SDK 导入、基础 URL、API 密钥环境变量)。这些会成为外部系统(scope: external 的 systems),供内部系统关联。如果用户更倾向于其他方式,第三方也可以作为带有 externalSystem: true 的服务。不要将它们建模为消息或容器。
Agent 边界
Agent 是由 AI/大模型驱动的运行时或工作进程,能够进行推理、调用工具或自动执行决策。参考信号:
- 明确的名称:带有大模型/工具编排功能的
*Agent、*Assistant、*Copilot、*Worker - 使用大模型 SDK:OpenAI、Anthropic、Gemini、Vercel AI SDK、LangChain、LlamaIndex、Mastra、CrewAI、AutoGen
- 工具注册表或可调用工具:MCP 客户端/服务、
tools、function_call、tool_choice、executeTool - Agent 框架:
Agent、createAgent、runAgent,以及使用大模型的图/工作流节点 - Agent 使用的记忆/状态存储:向量数据库、Redis、Postgres、Supabase、Pinecone、Qdrant、Chroma
不要仅仅因为普通服务调用了一次大模型,就将其归类为 Agent。当代码拥有持久的助手/工作进程边界、工具集、模型策略、记忆或自主工作流时,才将其视为 Agent。
消息(事件、命令、查询)
候选项来源:
- 命名模式——
*Created、*Placed、*Updated、*Deleted(可能是事件);Place*、Create*、Cancel*、Process*(可能是命令);Get*、Find*、List*(可能是查询)。 - 消息总线客户端——Kafka(
kafkajs、confluent-kafka、sarama)、RabbitMQ(amqplib、pika)、NATS、AWS SNS/SQS/EventBridge、GCP PubSub、Azure Service Bus。 - 架构文件——JSON Schema(
.schema.json)、Avro(.avsc)、Protobuf(.proto)。这些都是消息契约的强信号。 - DTO / 类型定义——尤其是看起来像负载(扁平、仅含数据、以领域事件命名)的定义。
根据证据,将每个候选项分类为事件、命令或查询:
- 事件:过去时,发布到主题/交换机,可能有多个消费者,不期待直接回复。
- 命令:祈使语气,发送给一个特定处理程序,期待被处理。
- 查询:只读,期待响应。
如果证据模糊(很常见),标记为不确定,并在第 4 阶段仔细追问——不要擅自选择。
通道
消息通过命名基础设施流动的位置:
- Kafka 主题(传入
producer.send({ topic: '...' })的字符串字面量) - RabbitMQ 队列/交换机
- SNS 主题、SQS 队列(队列始终是通道,不是容器)
- 查询服务的 HTTP 端点(
GET /users/:id)
领域(候选项)
强信号:
- 顶层文件夹分组(
src/orders/、src/payments/、src/shipping/) - README、模块文档中的限界上下文线索
- 包命名空间(
com.company.orders.*) - 所有权文件(
CODEOWNERS、.codeowners)
置信度较低时不要猜测领域。如果不明确,建议“单一领域 = 整个代码库”,并让用户在第 4 阶段拆分。
容器(数据存储)
配置、环境变量或客户端实例化中引用的数据库、缓存和存储。每个容器都需要一个 container_type,取值为 database、cache、objectStore、searchIndex、dataWarehouse、dataLake、externalSaaS、other 之一,并在 technology 中填写引擎:
- Postgres / MySQL / SQLite / Mongo / DynamoDB / Cassandra →
database - Redis / Memcached →
cache - S3 存储桶、GCS 存储桶 →
objectStore - Elasticsearch / OpenSearch →
searchIndex;Snowflake / BigQuery / Redshift →dataWarehouse
队列和主题是通道,不是容器。
第 2 阶段的输出
内部草稿映射:
domains:
- name: <candidate>
confidence: high|medium|low
systems: [...]
services: [...]
agents: [...]
systems:
- name: <candidate>
scope: internal|external
services: [...]
containers: [...]
relationships: [<other system>: <label>]
services:
- name: <candidate>
path: <dir>
sends: [...]
receives: [...]
channels: [...]
containers: [...]
agents:
- name: <candidate>
path: <dir>
model: <provider/name/version if found>
tools: [...]
sends: [...]
receives: [...]
channels: [...]
containers: [...]
flows: [...]
messages:
- name: <candidate>
classification: event|command|query|uncertain
evidence: <file:line>
producer: <service or agent>
consumer: <service, agent, or unknown>
channels: [...]
containers:
- name: <candidate>
container_type: database|cache|objectStore|...
technology: <postgres, redis, ...>
在内部保留此映射,用它来驱动第 3 阶段和第 4 阶段。
第 3 阶段:与现有目录核对
如果没有现有目录,则跳过此阶段——发现的所有内容都是 new。
对于草稿映射中的每个项目,在目录清单中查找匹配的资源(依次按 ID、名称、名称 + 类型的模糊匹配进行匹配)。分配一个状态:
| 状态 | 含义 |
|---|---|
unchanged | 资源存在于目录中,且与代码中的内容匹配。无需向用户追问。 |
update | 资源存在于目录中,但代码已发生偏移——新增消息、字段重命名、架构变更、新增发送/接收关系。 |
new | 在代码中找到,但不在目录中。可作为新资源候选项。 |
investigate | 存在于目录中,但未在代码中找到。可能已过时、可能已移除,也可能位于其他仓库中。绝不删除——只需提示。 |
对于 update 项,记录具体发生的偏移:
- 目录中的
OrderService发送[OrderPlaced],代码还会发送OrderCancelled→ 偏移:新增发送。 PaymentService的架构字段从amount_cents重命名为amountCents→ 偏移:架构变更。- 目录中的
OrderSupportAgent没有工具,代码却定义了orderLookup和zendeskNotesMCP 工具 → 偏移:新增工具。
此分类用于驱动第 4 阶段——只对 update、有歧义的 new 和 investigate 项追问。对 unchanged 资源不作提示。
第 4 阶段:分层确认
只针对结构性决策进行确认。 单项资源的细节(摘要文本、负责人姓名、架构字段、徽章样式)不在你的关注范围内——这些由 catalog-documentation-creator 处理。
如需查看包含推荐答案模板的完整问题库,请参阅 references/grilling.md。现在就阅读。
按以下顺序逐项讨论。依赖关系由上而下——先解决前面的主题,再处理后面的主题。
主题 1:领域与边界
首先询问领域分组,因为服务的归属取决于此。
- 如果你发现了明确的领域候选项:列出每个候选项及其建议的系统、服务和 Agent,然后请用户确认。
- 如果没有发现候选项:建议“整个代码库使用单一领域”,并询问用户是否想拆分。
- 对任何归属不明确的服务或 Agent(“
OrderSupportAgent属于Orders,还是应该归入自己的Support领域?”),都要确认清楚。 - 然后确认每个领域内的系统分组(“
billing-api、billing-worker和billing-db一起部署——要将它们归为一个Billing系统吗?”),以及哪些第三方应成为外部系统。
主题 2:服务边界
- 确认每个服务候选项,并列出相关证据(路径、入口点、Dockerfile)。
- 对归属不明确的情况(“这个模块可以作为独立服务,也可以归入另一个服务”),结合建议答案进行确认。
- 处理单体仓库的边缘情况:共享的
lib/包算不算服务?(可能不算——它属于基础设施。)
主题 3:Agent 边界
- 确认每个 Agent 候选项,并列出相关证据(LLM SDK 使用情况、模型配置、工具注册表、MCP 工具、记忆存储、入口点)。
- 对归属不明确的情况(“这个服务只调用一次大模型;它应当是集成了大模型的服务,还是一等 Agent?”),结合建议答案进行确认。
- 将模型/提供方和工具名称作为证据记录下来,但不要逐一确认每个提示词或底层工具参数。
主题 4:消息分类
这是最容易判断错误的环节。要仔细确认。
对于发现阶段标记为 uncertain 的每条消息:
我在
src/orders/handlers.ts:18找到了OrderReceived。它从队列中消费,且没有回复路径,因此我会将其归类为 事件。你同意吗?
对于分类把握较高的消息,请列出来供用户快速批量确认:
根据过去时命名和发布/订阅模式,我将这些识别为事件:
OrderPlaced、OrderCancelled、PaymentProcessed。其中有需要重新分类的吗?
主题 5:差异核对 (仅限已有目录)
对于每个 update 项:
目录记录
PaymentService会发送[PaymentProcessed]。代码还在src/payments/refund.ts:24发出了PaymentRefunded。要将PaymentRefunded添加到该服务的发送列表中吗?我认为应该添加。
对于每个 investigate 项:
目录中有
LegacyPaymentConfirmed(事件,v0.0.3)。我在代码中没有找到它。它可能位于另一个仓库,也可能已经移除。我会在计划中将其标记为investigate——用户之后可以决定如何处理。可以吗?
不要建议删除,只需指出。
不要确认的内容
- 每项资源的摘要文本
- 负责人/团队分配(除非信息来自
CODEOWNERS且存在歧义) - Agent 的提示词措辞和底层工具参数
- 架构字段级别的细节
- 徽章、视觉自定义项
- 流程图(由
flow-wizard处理)
这些内容会使用合理的默认值交由 catalog-documentation-creator 处理。
留意用户是否厌倦了问答
如果确认过程持续过久(例如,问题超过约 15 个):
- 总结进度:“这是目前已达成一致的内容——领域 X、Y;服务 A、B、C;已分类 12 条消息。”
- 提议先暂停并写入计划文件:“我们可以先到这里,写好计划,之后再补充细节。”
阶段 5:生成计划文件
将计划写入 .catalog-plan.md。默认位置:代码目录的根目录。询问用户是否希望将其放在其他位置。
使用以下确切结构:
# Catalog Plan
**Generated:** YYYY-MM-DD
**Codebase:** /absolute/path/to/repo
**Existing catalog:** /absolute/path/to/catalog (or "none — will be created")
## Summary
<1–2 paragraph narrative of what was found and the agreed architectural model>
## Domains
- **Orders** (status: new)
- Systems: OrderManagement
- Agents: OrderSupportAgent
- Rationale: both deal with the order lifecycle; confirmed with user
- **Payments** (status: unchanged)
- Services: PaymentService
## Systems
- **OrderManagement** (internal, status: new)
- Domain: Orders
- Services: OrderService, ShippingService
- Containers: orders-db
- Relationships: Stripe ("charges cards via")
- **Stripe** (external, status: new) — called from /services/orders/payments.ts
## Services
### OrderService (status: new)
- Domain: Orders
- System: OrderManagement
- Path in code: /services/orders
- Receives: PlaceOrder (command)
- Sends: OrderPlaced (event), OrderCancelled (event)
- Channels: orders.commands, orders.events
- Containers: orders-db (database, postgres)
### PaymentService (status: update)
- Domain: Payments
- Path in code: /services/payments
- Drift: code emits new PaymentRefunded event not in catalog
- Sends (after update): PaymentProcessed, PaymentRefunded
## Agents
### OrderSupportAgent (status: new)
- Domain: Orders
- Path in code: /agents/order-support
- Model: OpenAI / gpt-4.1-mini
- Tools: order-lookup (mcp), support-case-notes (mcp)
- Receives: OrderConfirmed, OrderCancelled
- Reads from: orders-db
- Flows: PlaceOrderFlow
### FraudReviewAgent (status: update)
- Domain: Payments
- Path in code: /agents/fraud-review
- Drift: code added fraud-case-queue MCP tool not in catalog
- Receives (after update): PaymentInitiated, RiskScoreCalculated, FraudDetected
## Messages
- **OrderPlaced** (event, status: new) — emitted by OrderService via orders.events
- **OrderCancelled** (event, status: new) — emitted by OrderService via orders.events
- **PlaceOrder** (command, status: new) — handled by OrderService
- **PaymentRefunded** (event, status: new) — emitted by PaymentService
- **LegacyPaymentConfirmed** (event, status: investigate) — in catalog, not found in code
## Channels
- orders.events (Kafka topic, status: new)
- orders.commands (Kafka topic, status: new)
## Containers
- orders-db (database, technology: postgres, status: new) — used by OrderService
## Open decisions / rationale
- Classified `CancelOrder` as a command (user confirmed — it expects a handler)
- Kept Shipping as a sub-area of Orders rather than splitting (user preference)
- Flagged `LegacyPaymentConfirmed` for manual review — may live in a different repo
## Next step
Run `catalog-documentation-creator` with this plan to generate resources marked `new` or `update`.
状态值(必须完全使用以下值):new、update、unchanged、investigate。
写入后,向用户展示计划并征求明确批准:“这是计划。与我们商定的内容一致吗?在继续之前,有什么需要添加、修改或删除的吗?”
根据用户的修改意见反复调整,直到用户批准。
阶段 6:移交
计划获批后,询问:
“现在生成目录,还是到此为止,只保留计划?”
如果现在生成:
- 调用
catalog-documentation-creator技能,并传入计划文件路径。 - 告诉它仅创建或更新标记为
new或update的资源。跳过unchanged。将investigate项作为列表报告给用户——不要自动处理。 - 如果用户没有现有目录,
catalog-documentation-creator会先搭建一个目录。
如果到此为止:
- 确认计划文件的位置。
- 告诉用户如何继续:“准备好后,运行
catalog-documentation-creator并指定此计划文件。它会生成new和update资源。”
移交后
告知用户:
- 计划保存的位置。
- (如果已生成)创建或更新了哪些资源。
- 哪些
investigate项需要人工审核。 - 如果用户想记录整个目录中的业务流程,可以接着运行
flow-wizard。
质量检查清单
完成前,验证以下事项:
- 计划文件存在于商定的路径。
- 每个域、系统、服务、Agent、消息、通道和容器都有一个状态:
new/update/unchanged/investigate。 - 每个
update项都列出了具体发生了哪些偏差。 - 每个
investigate项都已标记,未被删除。 - 消息分类(事件 / 命令 / 查询)已由用户确认,或有明确证据支持的建议。
- 每个服务和 Agent 都明确映射到域;服务也可以映射到系统。
- 没有针对每项资源进行盘问(摘要、负责人、架构等内容由
catalog-documentation-creator处理)。 - 如果要移交,
catalog-documentation-creator已获得计划路径,并收到跳过unchanged项的指示。