Code to Catalog
Turn a codebase into EventCatalog documentation through a guided, evidence-based interview. Works for two situations:
- No catalog yet — document an unfamiliar or undocumented codebase from scratch.
- Existing catalog — reconcile the catalog with the current code (add new resources, flag drift, surface stale entries).
This skill does not write catalog files itself. It produces a plan file (.catalog-plan.md) that captures the agreed architectural model, then hands off to the catalog-documentation-creator skill to generate the actual documentation.
How this skill works
The skill runs in six phases. Follow them in order — later phases depend on earlier ones.
- Locate & inventory — find the code directory and any existing catalog
- Discovery scan — read the code, form a hypothesis
- Reconcile with existing catalog — categorize findings as
new / update / unchanged / investigate
- Tiered grilling — interview the user on structural decisions only
- Produce the plan file — write
.catalog-plan.md, get approval
- Handoff — ask whether to generate the catalog now or stop at the plan
Conversational style (applies throughout)
- One question at a time. Never batch questions. The user answers, then move on.
- Always provide a recommended answer. Every question includes what you think is true, with evidence (file path + line number). The user confirms, corrects, or overrides.
- Cite the code. When you present a finding, point at the file where you saw it — e.g.,
src/orders/events.ts:42. The user should be able to verify without trusting you.
- Be honest about uncertainty. If the code does not tell you whether something is an event or a command, say so. Do not guess silently.
- Surface conflicts, do not pick silently. When catalog and code disagree, the user decides. Never overwrite without confirmation.
- Respect the user's time. Grilling is tiered on purpose — structural decisions only. Do not grill on per-resource fields (summaries, owners, schemas).
- No catalog deletions. Resources in the catalog that you cannot find in code are flagged
investigate — never removed automatically.
Phase 1: Locate & inventory
Find the codebase
Ask the user: "Which code directory should I analyze?"
Verify the directory exists and looks like a code project (has a package.json, pom.xml, go.mod, Cargo.toml, pyproject.toml, source directories, etc.). If the directory is ambiguous (e.g., a monorepo), confirm the scope: the whole repo, or a specific subdirectory.
Find the catalog
Ask the user: "Do you already have an EventCatalog project, or do you want to start fresh?"
If they already have one:
- Ask for the path. Verify it's an EventCatalog project by checking for
eventcatalog.config.js or the standard directories (services/, agents/, events/, commands/, queries/, domains/, channels/, flows/).
- Build an inventory of what already exists. If the EventCatalog MCP server is connected, use
getResources, getResource, findResourcesByOwner. Otherwise read the filesystem directly and parse the frontmatter of each index.md/index.mdx.
- Record for each resource:
id, name, version, type, summary, and (for services and agents) sends / receives relationships.
- Note the catalog's conventions: nested (
domains/X/services/Y/events/Z) vs flat, PascalCase vs kebab-case IDs, existing owners, schema formats in use.
If they do not have a catalog:
- That's fine. Note that scaffolding will happen at handoff time through
catalog-documentation-creator (which runs npx @eventcatalog/create-eventcatalog@latest <name> --empty).
- Phase 3 (reconciliation) becomes a no-op — everything discovered will be
new.
Phase 2: Discovery scan
Read the codebase and form a hypothesis. Do not show the user your findings yet — you'll present them as questions in Phase 4, backed by evidence.
For detailed detection heuristics per language/framework (Node.js, Python, Go, Java, .NET), see references/discovery.md. Read that file now if the codebase uses a stack you need guidance on.
Detect:
Project structure
- Monorepo vs single service (look for workspace configs:
pnpm-workspace.yaml, package.json with workspaces, nx.json, turbo.json, lerna.json, multiple top-level service directories with their own manifests).
- Language and framework per service or agent.
- Build/deploy units (Dockerfiles, Helm charts,
serverless.yml, cdk stacks, k8s manifests).
Service boundaries
A service is an independently-deployable, independently-ownable unit. Signals:
- Separate package with its own manifest
- Separate Dockerfile / deployment config
- Its own entrypoint (
main.ts, main.go, app.py, etc.)
- Consumed by others over a network boundary (HTTP, message bus)
When in doubt, mark as a candidate and grill the user in Phase 4.
Agent boundaries
An agent is an AI/LLM-powered runtime or worker that reasons, calls tools, or automates decisions. Signals:
- Explicit names:
*Agent, *Assistant, *Copilot, *Worker with LLM/tool orchestration
- LLM SDK usage: OpenAI, Anthropic, Gemini, Vercel AI SDK, LangChain, LlamaIndex, Mastra, CrewAI, AutoGen
- Tool registries or callable tools: MCP clients/servers,
tools, function_call, tool_choice, executeTool
- Agent frameworks:
Agent, createAgent, runAgent, graph/workflow nodes using an LLM
- Memory/state stores used by the agent: vector DBs, Redis, Postgres, Supabase, Pinecone, Qdrant, Chroma
Do not classify a plain service as an agent just because it calls an LLM once. Treat it as an agent when the code owns a durable assistant/worker boundary, tool set, model policy, memory, or autonomous workflow.
Messages (events, commands, queries)
Candidates come from:
- Naming patterns —
*Created, *Placed, *Updated, *Deleted (likely events); Place*, Create*, Cancel*, Process* (likely commands); Get*, Find*, List* (likely queries).
- Message bus clients — Kafka (
kafkajs, confluent-kafka, sarama), RabbitMQ (amqplib, pika), NATS, AWS SNS/SQS/EventBridge, GCP PubSub, Azure Service Bus.
- Schema files — JSON Schema (
.schema.json), Avro (.avsc), Protobuf (.proto). These are strong signals of a message contract.
- DTO / type definitions — especially if they look like payloads (flat, data-only, named after a domain event).
Classify each candidate as event, command, or query based on evidence:
- Event: past tense, published to a topic/exchange, multiple consumers possible, no direct reply expected.
- Command: imperative, sent to one specific handler, expects to be processed.
- Query: read-only, expects a response.
If evidence is ambiguous (common), mark it as uncertain and grill in Phase 4 — do not silently pick.
Channels
Anywhere messages flow through named infrastructure:
- Kafka topics (string literals passed to
producer.send({ topic: '...' }))
- RabbitMQ queues/exchanges
- SNS topics, SQS queues
- HTTP endpoints for query services (
GET /users/:id)
Domains (candidates)
Strong signals:
- Top-level folder grouping (
src/orders/, src/payments/, src/shipping/)
- Bounded-context hints in READMEs, module docs
- Package namespaces (
com.company.orders.*)
- Ownership files (
CODEOWNERS, .codeowners)
Do not guess domains with low confidence. If unclear, propose "single domain = whole codebase" and let the user split in Phase 4.
Containers
Databases, caches, queues referenced in config, env vars, or client instantiation:
- Postgres / MySQL / SQLite / Mongo / DynamoDB / Cassandra
- Redis / Memcached
- S3 buckets, GCS buckets
Output of Phase 2
An internal draft map:
domains:
- name: <candidate>
confidence: high|medium|low
services: [...]
agents: [...]
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: [...]
Hold this map internally. You'll use it to drive Phase 3 and Phase 4.
Phase 3: Reconcile with existing catalog
Skip this phase if there is no existing catalog — everything discovered is new.
For each item in the draft map, find the matching resource in the catalog inventory (match by ID, then by name, then by fuzzy match on name + type). Assign a status:
| Status |
Meaning |
unchanged |
Resource exists in catalog and matches what's in code. No user grilling needed. |
update |
Resource exists in catalog, but the code has drifted — new messages emitted, renamed fields, changed schemas, new sends/receives relationships. |
new |
Found in code, not in catalog. Candidate for a new resource. |
investigate |
Exists in catalog, not found in code. Possibly stale, possibly removed, possibly in a different repo. Never delete — only surface. |
For update items, capture what specifically drifted:
OrderService in catalog sends [OrderPlaced], code also sends OrderCancelled → drift: new send.
PaymentService schema field renamed amount_cents → amountCents → drift: schema change.
OrderSupportAgent in catalog has no tools, code defines orderLookup and zendeskNotes MCP tools → drift: new tools.
This categorization drives Phase 4 — you only grill on update, ambiguous new, and investigate items. unchanged resources are silent.
Phase 4: Tiered grilling
Grill only on structural decisions. Per-resource details (summary text, owner names, schema fields, badge styles) are not your concern — catalog-documentation-creator handles them.
For the full question bank with recommended-answer templates, see references/grilling.md. Read it now.
Walk the topics in this order. Dependencies flow downward — resolve earlier topics before later ones.
Topic 1: Domains & boundaries
Ask about domain groupings first, because service placement depends on it.
- If you detected clear domain candidates: present each with its recommended services and agents, then ask the user to confirm.
- If you detected none: propose "single domain for the whole codebase" and ask whether they want to split.
- For any ambiguous service or agent ("does
OrderSupportAgent belong to Orders or its own Support domain?"), grill it.
Topic 2: Service boundaries
- Confirm each service candidate. Present its evidence (path, entrypoint, Dockerfile).
- For ambiguous cases ("this module could be its own service or part of another"), grill with a recommended answer.
- Handle monorepo edge cases: is the shared
lib/ package a service? (Probably not — it's infrastructure.)
Topic 3: Agent boundaries
- Confirm each agent candidate. Present its evidence (LLM SDK usage, model configuration, tool registry, MCP tools, memory store, entrypoint).
- For ambiguous cases ("this service calls an LLM once; should it be a service with an LLM integration or a first-class agent?"), grill with a recommended answer.
- Capture model/provider and tool names as evidence, but avoid grilling on every prompt or low-level tool parameter.
Topic 4: Message classification
This is the most commonly-wrong call. Grill it hard.
For every message marked uncertain in discovery:
I found OrderReceived at src/orders/handlers.ts:18. It's consumed from a queue and there's no reply path, so I'd classify it as an event. Agree?
For messages with high-confidence classification, present them for quick bulk confirmation:
I identified these as events (based on past-tense naming + pub/sub pattern): OrderPlaced, OrderCancelled, PaymentProcessed. Any you'd reclassify?
Topic 5: Drift reconciliation (only if existing catalog)
For each update item:
Catalog says PaymentService sends [PaymentProcessed]. Code also emits PaymentRefunded at src/payments/refund.ts:24. Add PaymentRefunded to the service's sends? I'd say yes.
For each investigate item:
Catalog has LegacyPaymentConfirmed (event, v0.0.3). I could not find it in the code. It might live in another repo, or it might be removed. I'll flag it as investigate in the plan — the user can decide later. OK?
Do not propose deletions. Only surface.
What NOT to grill on
- Summary text for each resource
- Owner / team assignments (unless discovered from
CODEOWNERS and ambiguous)
- Prompt wording and low-level tool parameters for agents
- Schema field-level detail
- Badges, visual customizations
- Flow diagrams (that's
flow-wizard)
Those pass through to catalog-documentation-creator with sensible defaults.
Watch for interview fatigue
If the grilling is running long (say, more than ~15 questions):
- Summarize progress: "Here's what we've agreed so far — domains X, Y; services A, B, C; 12 messages classified."
- Offer to pause at the plan file: "We can stop here, write the plan, and pick up details later."
Phase 5: Produce the plan file
Write the plan to .catalog-plan.md. Default location: root of the code directory. Ask the user if they'd like it elsewhere.
Use this exact structure:
# 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)
- Services: OrderService, ShippingService
- Agents: OrderSupportAgent
- Rationale: both deal with the order lifecycle; confirmed with user
- **Payments** (status: unchanged)
- Services: PaymentService
## Services
### OrderService (status: new)
- Domain: Orders
- Path in code: /services/orders
- Receives: PlaceOrder (command)
- Sends: OrderPlaced (event), OrderCancelled (event)
- Channels: orders.commands, orders.events
- Containers: orders-db (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 (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`.
Status values (use exactly these): new, update, unchanged, investigate.
After writing, show the plan to the user and ask for explicit approval: "Here's the plan. Does this match what we agreed? Anything to add, change, or remove before we proceed?"
Loop on edits until the user approves.
Phase 6: Handoff
Once the plan is approved, ask:
"Generate the catalog now, or stop here with just the plan?"
If generate now:
- Invoke the
catalog-documentation-creator skill, passing the plan file path.
- Tell it to only create/update resources flagged
new or update. Skip unchanged. Report investigate items to the user as a list — do not auto-handle.
- If the user has no existing catalog,
catalog-documentation-creator will scaffold one first.
If stop here:
- Confirm the plan file location.
- Tell the user how to resume: "When you're ready, run
catalog-documentation-creator and point it at this plan file. It will generate the new and update resources."
After handoff
Let the user know:
- Where the plan was saved.
- (If generated) which resources were created/updated.
- Which
investigate items need manual review.
- That they can run
flow-wizard next if they want to document business flows across the catalog.
Quality checklist
Before finishing, verify:
- The plan file exists at the agreed path.
- Every domain, service, agent, message, channel, and container has a status:
new / update / unchanged / investigate.
- Every
update item lists what specifically drifted.
- Every
investigate item is flagged, not deleted.
- Message classifications (event / command / query) were either confirmed by the user or clearly recommended with evidence.
- Service-to-domain and agent-to-domain mapping is explicit for every service and agent.
- No per-resource grilling happened (summaries, owners, schemas — those are for
catalog-documentation-creator).
- If handing off,
catalog-documentation-creator has the plan path and instructions to skip unchanged.
1---2name: code-to-catalog3description: Turns a codebase into EventCatalog documentation through an evidence-based interview. Scans the code first, proposes an architectural model (domains, services, agents, messages, channels), grills the user on the structural decisions, produces a reviewable plan file, then hands off to catalog-documentation-creator. Use when user says "document my codebase in EventCatalog", "turn this repo into a catalog", "model my code as a catalog", "document my agents", "document my AI agents", "grill me on my architecture", "update my catalog from the code", "reconcile my catalog with my code", or "I don't know where to start documenting this codebase". Works for brand-new catalogs AND for updating existing catalogs that have drifted from the code.4license: MIT5---6
7# Code to Catalog
8
9Turn a codebase into EventCatalog documentation through a guided, evidence-based interview. Works for two situations:
10
111. **No catalog yet** — document an unfamiliar or undocumented codebase from scratch.
122. **Existing catalog** — reconcile the catalog with the current code (add new resources, flag drift, surface stale entries).
13
14This skill does not write catalog files itself. It produces a **plan file** (`.catalog-plan.md`) that captures the agreed architectural model, then hands off to the `catalog-documentation-creator` skill to generate the actual documentation.
15
16## How this skill works
17
18The skill runs in six phases. Follow them in order — later phases depend on earlier ones.
19
201. **Locate & inventory** — find the code directory and any existing catalog
212. **Discovery scan** — read the code, form a hypothesis
223. **Reconcile with existing catalog** — categorize findings as `new` / `update` / `unchanged` / `investigate`
234. **Tiered grilling** — interview the user on structural decisions only
245. **Produce the plan file** — write `.catalog-plan.md`, get approval
256. **Handoff** — ask whether to generate the catalog now or stop at the plan
26
27## Conversational style (applies throughout)
28
29- **One question at a time.** Never batch questions. The user answers, then move on.
30- **Always provide a recommended answer.** Every question includes what you think is true, with evidence (file path + line number). The user confirms, corrects, or overrides.
31- **Cite the code.** When you present a finding, point at the file where you saw it — e.g., `src/orders/events.ts:42`. The user should be able to verify without trusting you.
32- **Be honest about uncertainty.** If the code does not tell you whether something is an event or a command, say so. Do not guess silently.
33- **Surface conflicts, do not pick silently.** When catalog and code disagree, the user decides. Never overwrite without confirmation.
34- **Respect the user's time.** Grilling is tiered on purpose — structural decisions only. Do not grill on per-resource fields (summaries, owners, schemas).
35- **No catalog deletions.** Resources in the catalog that you cannot find in code are flagged `investigate` — never removed automatically.
36
37## Phase 1: Locate & inventory
38
39### Find the codebase
40
41Ask the user: **"Which code directory should I analyze?"**
42
43Verify the directory exists and looks like a code project (has a `package.json`, `pom.xml`, `go.mod`, `Cargo.toml`, `pyproject.toml`, source directories, etc.). If the directory is ambiguous (e.g., a monorepo), confirm the scope: the whole repo, or a specific subdirectory.
44
45### Find the catalog
46
47Ask the user: **"Do you already have an EventCatalog project, or do you want to start fresh?"**
48
49**If they already have one:**
50
51- Ask for the path. Verify it's an EventCatalog project by checking for `eventcatalog.config.js` or the standard directories (`services/`, `agents/`, `events/`, `commands/`, `queries/`, `domains/`, `channels/`, `flows/`).
52- Build an inventory of what already exists. If the EventCatalog MCP server is connected, use `getResources`, `getResource`, `findResourcesByOwner`. Otherwise read the filesystem directly and parse the frontmatter of each `index.md`/`index.mdx`.
53- Record for each resource: `id`, `name`, `version`, `type`, `summary`, and (for services and agents) `sends` / `receives` relationships.
54- Note the catalog's conventions: nested (`domains/X/services/Y/events/Z`) vs flat, PascalCase vs kebab-case IDs, existing owners, schema formats in use.
55
56**If they do not have a catalog:**
57
58- That's fine. Note that scaffolding will happen at handoff time through `catalog-documentation-creator` (which runs `npx @eventcatalog/create-eventcatalog@latest <name> --empty`).
59- Phase 3 (reconciliation) becomes a no-op — everything discovered will be `new`.
60
61## Phase 2: Discovery scan
62
63Read the codebase and form a hypothesis. Do **not** show the user your findings yet — you'll present them as questions in Phase 4, backed by evidence.
64
65For detailed detection heuristics per language/framework (Node.js, Python, Go, Java, .NET), see `references/discovery.md`. Read that file now if the codebase uses a stack you need guidance on.
66
67Detect:
68
69### Project structure
70
71- Monorepo vs single service (look for workspace configs: `pnpm-workspace.yaml`, `package.json` with `workspaces`, `nx.json`, `turbo.json`, `lerna.json`, multiple top-level service directories with their own manifests).
72- Language and framework per service or agent.
73- Build/deploy units (Dockerfiles, Helm charts, `serverless.yml`, `cdk` stacks, k8s manifests).
74
75### Service boundaries
76
77A service is an independently-deployable, independently-ownable unit. Signals:
78
79- Separate package with its own manifest
80- Separate Dockerfile / deployment config
81- Its own entrypoint (`main.ts`, `main.go`, `app.py`, etc.)
82- Consumed by others over a network boundary (HTTP, message bus)
83
84When in doubt, mark as a **candidate** and grill the user in Phase 4.
85
86### Agent boundaries
87
88An agent is an AI/LLM-powered runtime or worker that reasons, calls tools, or automates decisions. Signals:
89
90- Explicit names: `*Agent`, `*Assistant`, `*Copilot`, `*Worker` with LLM/tool orchestration
91- LLM SDK usage: OpenAI, Anthropic, Gemini, Vercel AI SDK, LangChain, LlamaIndex, Mastra, CrewAI, AutoGen
92- Tool registries or callable tools: MCP clients/servers, `tools`, `function_call`, `tool_choice`, `executeTool`
93- Agent frameworks: `Agent`, `createAgent`, `runAgent`, graph/workflow nodes using an LLM
94- Memory/state stores used by the agent: vector DBs, Redis, Postgres, Supabase, Pinecone, Qdrant, Chroma
95
96Do not classify a plain service as an agent just because it calls an LLM once. Treat it as an agent when the code owns a durable assistant/worker boundary, tool set, model policy, memory, or autonomous workflow.
97
98### Messages (events, commands, queries)
99
100Candidates come from:
101
102- **Naming patterns** — `*Created`, `*Placed`, `*Updated`, `*Deleted` (likely events); `Place*`, `Create*`, `Cancel*`, `Process*` (likely commands); `Get*`, `Find*`, `List*` (likely queries).
103- **Message bus clients** — Kafka (`kafkajs`, `confluent-kafka`, `sarama`), RabbitMQ (`amqplib`, `pika`), NATS, AWS SNS/SQS/EventBridge, GCP PubSub, Azure Service Bus.
104- **Schema files** — JSON Schema (`.schema.json`), Avro (`.avsc`), Protobuf (`.proto`). These are strong signals of a message contract.
105- **DTO / type definitions** — especially if they look like payloads (flat, data-only, named after a domain event).
106
107Classify each candidate as **event**, **command**, or **query** based on evidence:
108
109- Event: past tense, published to a topic/exchange, multiple consumers possible, no direct reply expected.
110- Command: imperative, sent to one specific handler, expects to be processed.
111- Query: read-only, expects a response.
112
113If evidence is ambiguous (common), mark it as **uncertain** and grill in Phase 4 — do not silently pick.
114
115### Channels
116
117Anywhere messages flow through named infrastructure:
118
119- Kafka topics (string literals passed to `producer.send({ topic: '...' })`)
120- RabbitMQ queues/exchanges
121- SNS topics, SQS queues
122- HTTP endpoints for query services (`GET /users/:id`)
123
124### Domains (candidates)
125
126Strong signals:
127
128- Top-level folder grouping (`src/orders/`, `src/payments/`, `src/shipping/`)
129- Bounded-context hints in READMEs, module docs
130- Package namespaces (`com.company.orders.*`)
131- Ownership files (`CODEOWNERS`, `.codeowners`)
132
133Do not guess domains with low confidence. If unclear, propose "single domain = whole codebase" and let the user split in Phase 4.
134
135### Containers
136
137Databases, caches, queues referenced in config, env vars, or client instantiation:
138
139- Postgres / MySQL / SQLite / Mongo / DynamoDB / Cassandra
140- Redis / Memcached
141- S3 buckets, GCS buckets
142
143### Output of Phase 2
144
145An internal draft map:
146
147```
148domains:
149 - name: <candidate>
150 confidence: high|medium|low
151 services: [...]
152 agents: [...]
153services:
154 - name: <candidate>
155 path: <dir>
156 sends: [...]
157 receives: [...]
158 channels: [...]
159 containers: [...]
160agents:
161 - name: <candidate>
162 path: <dir>
163 model: <provider/name/version if found>
164 tools: [...]
165 sends: [...]
166 receives: [...]
167 channels: [...]
168 containers: [...]
169 flows: [...]
170messages:
171 - name: <candidate>
172 classification: event|command|query|uncertain
173 evidence: <file:line>
174 producer: <service or agent>
175 consumer: <service, agent, or unknown>
176channels: [...]
177containers: [...]
178```
179
180Hold this map internally. You'll use it to drive Phase 3 and Phase 4.
181
182## Phase 3: Reconcile with existing catalog
183
184Skip this phase if there is no existing catalog — everything discovered is `new`.
185
186For each item in the draft map, find the matching resource in the catalog inventory (match by ID, then by name, then by fuzzy match on name + type). Assign a status:
187
188| Status | Meaning |
189|---|---|
190| `unchanged` | Resource exists in catalog and matches what's in code. No user grilling needed. |
191| `update` | Resource exists in catalog, but the code has drifted — new messages emitted, renamed fields, changed schemas, new sends/receives relationships. |
192| `new` | Found in code, not in catalog. Candidate for a new resource. |
193| `investigate` | Exists in catalog, not found in code. Possibly stale, possibly removed, possibly in a different repo. **Never delete — only surface.** |
194
195For `update` items, capture **what specifically drifted**:
196
197- `OrderService` in catalog sends `[OrderPlaced]`, code also sends `OrderCancelled` → drift: new send.
198- `PaymentService` schema field renamed `amount_cents` → `amountCents` → drift: schema change.
199- `OrderSupportAgent` in catalog has no tools, code defines `orderLookup` and `zendeskNotes` MCP tools → drift: new tools.
200
201This categorization drives Phase 4 — you only grill on `update`, ambiguous `new`, and `investigate` items. `unchanged` resources are silent.
202
203## Phase 4: Tiered grilling
204
205**Grill only on structural decisions.** Per-resource details (summary text, owner names, schema fields, badge styles) are not your concern — `catalog-documentation-creator` handles them.
206
207For the full question bank with recommended-answer templates, see `references/grilling.md`. Read it now.
208
209Walk the topics in this order. Dependencies flow downward — resolve earlier topics before later ones.
210
211### Topic 1: Domains & boundaries
212
213Ask about domain groupings first, because service placement depends on it.
214
215- If you detected clear domain candidates: present each with its recommended services and agents, then ask the user to confirm.
216- If you detected none: propose "single domain for the whole codebase" and ask whether they want to split.
217- For any ambiguous service or agent ("does `OrderSupportAgent` belong to `Orders` or its own `Support` domain?"), grill it.
218
219### Topic 2: Service boundaries
220
221- Confirm each service candidate. Present its evidence (path, entrypoint, Dockerfile).
222- For ambiguous cases ("this module could be its own service or part of another"), grill with a recommended answer.
223- Handle monorepo edge cases: is the shared `lib/` package a service? (Probably not — it's infrastructure.)
224
225### Topic 3: Agent boundaries
226
227- Confirm each agent candidate. Present its evidence (LLM SDK usage, model configuration, tool registry, MCP tools, memory store, entrypoint).
228- For ambiguous cases ("this service calls an LLM once; should it be a service with an LLM integration or a first-class agent?"), grill with a recommended answer.
229- Capture model/provider and tool names as evidence, but avoid grilling on every prompt or low-level tool parameter.
230
231### Topic 4: Message classification
232
233This is the most commonly-wrong call. Grill it hard.
234
235For every message marked `uncertain` in discovery:
236
237> I found `OrderReceived` at `src/orders/handlers.ts:18`. It's consumed from a queue and there's no reply path, so I'd classify it as an **event**. Agree?
238
239For messages with high-confidence classification, present them for quick bulk confirmation:
240
241> I identified these as events (based on past-tense naming + pub/sub pattern): `OrderPlaced`, `OrderCancelled`, `PaymentProcessed`. Any you'd reclassify?
242
243### Topic 5: Drift reconciliation *(only if existing catalog)*
244
245For each `update` item:
246
247> Catalog says `PaymentService` sends `[PaymentProcessed]`. Code also emits `PaymentRefunded` at `src/payments/refund.ts:24`. Add `PaymentRefunded` to the service's sends? I'd say yes.
248
249For each `investigate` item:
250
251> Catalog has `LegacyPaymentConfirmed` (event, v0.0.3). I could not find it in the code. It might live in another repo, or it might be removed. I'll flag it as `investigate` in the plan — the user can decide later. OK?
252
253Do not propose deletions. Only surface.
254
255### What NOT to grill on
256
257- Summary text for each resource
258- Owner / team assignments (unless discovered from `CODEOWNERS` and ambiguous)
259- Prompt wording and low-level tool parameters for agents
260- Schema field-level detail
261- Badges, visual customizations
262- Flow diagrams (that's `flow-wizard`)
263
264Those pass through to `catalog-documentation-creator` with sensible defaults.
265
266### Watch for interview fatigue
267
268If the grilling is running long (say, more than ~15 questions):
269
270- Summarize progress: "Here's what we've agreed so far — domains X, Y; services A, B, C; 12 messages classified."
271- Offer to pause at the plan file: "We can stop here, write the plan, and pick up details later."
272
273## Phase 5: Produce the plan file
274
275Write the plan to `.catalog-plan.md`. Default location: root of the code directory. Ask the user if they'd like it elsewhere.
276
277Use this exact structure:
278
279```markdown
280# Catalog Plan
281
282**Generated:** YYYY-MM-DD
283**Codebase:** /absolute/path/to/repo
284**Existing catalog:** /absolute/path/to/catalog (or "none — will be created")
285
286## Summary
287<1–2 paragraph narrative of what was found and the agreed architectural model>
288
289## Domains
290- **Orders** (status: new)
291 - Services: OrderService, ShippingService
292 - Agents: OrderSupportAgent
293 - Rationale: both deal with the order lifecycle; confirmed with user
294
295- **Payments** (status: unchanged)
296 - Services: PaymentService
297
298## Services
299### OrderService (status: new)
300- Domain: Orders
301- Path in code: /services/orders
302- Receives: PlaceOrder (command)
303- Sends: OrderPlaced (event), OrderCancelled (event)
304- Channels: orders.commands, orders.events
305- Containers: orders-db (postgres)
306
307### PaymentService (status: update)
308- Domain: Payments
309- Path in code: /services/payments
310- Drift: code emits new PaymentRefunded event not in catalog
311- Sends (after update): PaymentProcessed, PaymentRefunded
312
313## Agents
314### OrderSupportAgent (status: new)
315- Domain: Orders
316- Path in code: /agents/order-support
317- Model: OpenAI / gpt-4.1-mini
318- Tools: order-lookup (mcp), support-case-notes (mcp)
319- Receives: OrderConfirmed, OrderCancelled
320- Reads from: orders-db
321- Flows: PlaceOrderFlow
322
323### FraudReviewAgent (status: update)
324- Domain: Payments
325- Path in code: /agents/fraud-review
326- Drift: code added fraud-case-queue MCP tool not in catalog
327- Receives (after update): PaymentInitiated, RiskScoreCalculated, FraudDetected
328
329## Messages
330- **OrderPlaced** (event, status: new) — emitted by OrderService via orders.events
331- **OrderCancelled** (event, status: new) — emitted by OrderService via orders.events
332- **PlaceOrder** (command, status: new) — handled by OrderService
333- **PaymentRefunded** (event, status: new) — emitted by PaymentService
334- **LegacyPaymentConfirmed** (event, status: investigate) — in catalog, not found in code
335
336## Channels
337- orders.events (Kafka topic, status: new)
338- orders.commands (Kafka topic, status: new)
339
340## Containers
341- orders-db (postgres, status: new) — used by OrderService
342
343## Open decisions / rationale
344- Classified `CancelOrder` as a command (user confirmed — it expects a handler)
345- Kept Shipping as a sub-area of Orders rather than splitting (user preference)
346- Flagged `LegacyPaymentConfirmed` for manual review — may live in a different repo
347
348## Next step
349Run `catalog-documentation-creator` with this plan to generate resources marked `new` or `update`.
350```
351
352**Status values** (use exactly these): `new`, `update`, `unchanged`, `investigate`.
353
354After writing, show the plan to the user and ask for explicit approval: **"Here's the plan. Does this match what we agreed? Anything to add, change, or remove before we proceed?"**
355
356Loop on edits until the user approves.
357
358## Phase 6: Handoff
359
360Once the plan is approved, ask:
361
362> **"Generate the catalog now, or stop here with just the plan?"**
363
364**If generate now:**
365
366- Invoke the `catalog-documentation-creator` skill, passing the plan file path.
367- Tell it to only create/update resources flagged `new` or `update`. Skip `unchanged`. Report `investigate` items to the user as a list — do not auto-handle.
368- If the user has no existing catalog, `catalog-documentation-creator` will scaffold one first.
369
370**If stop here:**
371
372- Confirm the plan file location.
373- Tell the user how to resume: "When you're ready, run `catalog-documentation-creator` and point it at this plan file. It will generate the `new` and `update` resources."
374
375### After handoff
376
377Let the user know:
378
379- Where the plan was saved.
380- (If generated) which resources were created/updated.
381- Which `investigate` items need manual review.
382- That they can run `flow-wizard` next if they want to document business flows across the catalog.
383
384## Quality checklist
385
386Before finishing, verify:
387
3881. The plan file exists at the agreed path.
3892. Every domain, service, agent, message, channel, and container has a status: `new` / `update` / `unchanged` / `investigate`.
3903. Every `update` item lists what specifically drifted.
3914. Every `investigate` item is flagged, not deleted.
3925. Message classifications (event / command / query) were either confirmed by the user or clearly recommended with evidence.
3936. Service-to-domain and agent-to-domain mapping is explicit for every service and agent.
3947. No per-resource grilling happened (summaries, owners, schemas — those are for `catalog-documentation-creator`).
3958. If handing off, `catalog-documentation-creator` has the plan path and instructions to skip `unchanged`.