npx skills add ...
npx skills add event-catalog/skills --skill code-to-catalog
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.
npx skills add event-catalog/skills --skill code-to-catalog
Turn a codebase into EventCatalog documentation through a guided, evidence-based interview. Works for two situations:
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.
The skill runs in six phases. Follow them in order — later phases depend on earlier ones.
new / update / unchanged / investigate.catalog-plan.md, get approvalsrc/orders/events.ts:42. The user should be able to verify without trusting you.investigate — never removed automatically.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.
Ask the user: "Do you already have an EventCatalog project, or do you want to start fresh?"
If they already have one:
eventcatalog.config.js or the standard directories (services/, agents/, events/, commands/, queries/, domains/, channels/, flows/).getResources, getResource, findResourcesByOwner. Otherwise read the filesystem directly and parse the frontmatter of each index.md/index.mdx.id, name, version, type, summary, and (for services and agents) sends / receives relationships.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:
catalog-documentation-creator (which runs npx @eventcatalog/create-eventcatalog@latest <name> --empty).new.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:
pnpm-workspace.yaml, package.json with workspaces, nx.json, turbo.json, lerna.json, multiple top-level service directories with their own manifests).serverless.yml, cdk stacks, k8s manifests).A service is an independently-deployable, independently-ownable unit. Signals:
main.ts, main.go, app.py, etc.)When in doubt, mark as a candidate and grill the user in Phase 4.
An agent is an AI/LLM-powered runtime or worker that reasons, calls tools, or automates decisions. Signals:
*Agent, *Assistant, *Copilot, *Worker with LLM/tool orchestrationtools, function_call, tool_choice, executeToolAgent, createAgent, runAgent, graph/workflow nodes using an LLMDo 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.
Candidates come from:
*Created, *Placed, *Updated, *Deleted (likely events); Place*, Create*, Cancel*, Process* (likely commands); Get*, Find*, List* (likely queries).kafkajs, confluent-kafka, sarama), RabbitMQ (amqplib, pika), NATS, AWS SNS/SQS/EventBridge, GCP PubSub, Azure Service Bus..schema.json), Avro (.avsc), Protobuf (.proto). These are strong signals of a message contract.Classify each candidate as event, command, or query based on evidence:
If evidence is ambiguous (common), mark it as uncertain and grill in Phase 4 — do not silently pick.
Anywhere messages flow through named infrastructure:
producer.send({ topic: '...' }))GET /users/:id)Strong signals:
src/orders/, src/payments/, src/shipping/)com.company.orders.*)CODEOWNERS, .codeowners)Do not guess domains with low confidence. If unclear, propose "single domain = whole codebase" and let the user split in Phase 4.
Databases, caches, queues referenced in config, env vars, or client instantiation:
An internal draft map:
Hold this map internally. You'll use it to drive Phase 3 and Phase 4.
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.
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.
Ask about domain groupings first, because service placement depends on it.
OrderSupportAgent belong to Orders or its own Support domain?"), grill it.lib/ package a service? (Probably not — it's infrastructure.)This is the most commonly-wrong call. Grill it hard.
For every message marked uncertain in discovery:
I found
OrderReceivedatsrc/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?
For each update item:
Catalog says
PaymentServicesends[PaymentProcessed]. Code also emitsPaymentRefundedatsrc/payments/refund.ts:24. AddPaymentRefundedto 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 asinvestigatein the plan — the user can decide later. OK?
Do not propose deletions. Only surface.
CODEOWNERS and ambiguous)flow-wizard)Those pass through to catalog-documentation-creator with sensible defaults.
If the grilling is running long (say, more than ~15 questions):
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:
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.
Once the plan is approved, ask:
"Generate the catalog now, or stop here with just the plan?"
If generate now:
catalog-documentation-creator skill, passing the plan file path.new or update. Skip unchanged. Report investigate items to the user as a list — do not auto-handle.catalog-documentation-creator will scaffold one first.If stop here:
catalog-documentation-creator and point it at this plan file. It will generate the new and update resources."Let the user know:
investigate items need manual review.flow-wizard next if they want to document business flows across the catalog.Before finishing, verify:
new / update / unchanged / investigate.update item lists what specifically drifted.investigate item is flagged, not deleted.catalog-documentation-creator).catalog-documentation-creator has the plan path and instructions to skip unchanged.# 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`.