@eventmodelers/cli 1.0.37 → 1.0.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/package.json +1 -1
  2. package/shared/skills/learn-eventmodelers-api/SKILL.md +10 -3
  3. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-applying-conways-law/SKILL.md +3 -61
  4. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/SKILL.md +24 -93
  5. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/SKILL.md +2 -0
  6. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-core-rules/SKILL.md +182 -0
  7. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-automation-chains/SKILL.md +23 -7
  8. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/SKILL.md +50 -223
  9. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/references/examples.md +30 -120
  10. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/SKILL.md +3 -78
  11. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/SKILL.md +3 -50
  12. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/SKILL.md +3 -54
  13. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-interview-protocol/SKILL.md +31 -0
  14. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/SKILL.md +27 -67
  15. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/domain-patterns.md +15 -15
  16. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/patterns.md +44 -52
  17. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/SKILL.md +14 -15
  18. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-plotting-events/SKILL.md +4 -0
  19. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/SKILL.md +3 -15
  20. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/SKILL.md +3 -50
  21. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-translating-external-events/SKILL.md +4 -56
  22. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models/SKILL.md +58 -97
  23. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models-checklist/SKILL.md +72 -127
  24. package/stacks/modeling-kit/templates/.claude/skills/place-element/SKILL.md +15 -1
  25. package/stacks/modeling-kit/templates/.claude/skills/place-element/references/api-fallback.md +11 -1
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: eventmodeling-validating-event-models-checklist
3
- description: "Validate event-sourced CQRS models against 17 architectural checks across 7 phases. Identifies anti-patterns and confirms compliance with event sourcing principles. Use when reviewing event models for production readiness or after completing event modeling steps. Do not use for: reviewing incomplete or in-progress models (use eventmodeling-validating-event-models), or for elaborating new scenarios (use eventmodeling-elaborating-scenarios)."
3
+ description: "Validate an event model against 12 structural checks across 6 phases. Identifies notation anti-patterns and confirms the model is internally consistent. Use when reviewing an event model for readiness or after completing event modeling steps. Do not use for: reviewing incomplete or in-progress models (use eventmodeling-validating-event-models), or for elaborating new scenarios (use eventmodeling-elaborating-scenarios)."
4
4
  allowed-tools:
5
5
  - Write
6
6
  - Bash
@@ -10,25 +10,26 @@ allowed-tools:
10
10
 
11
11
  > **Before doing anything else**, invoke the `connect` skill — if not already connected — to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`. Do not proceed until it has completed. Consult `learn-eventmodelers-api` only if you need to look up a specific endpoint or field this file doesn't cover — don't load it eagerly.
12
12
 
13
+ This step applies the shared element rules in **`eventmodeling-core-rules`** — read it once per session if you haven't already; it defines what a COMMAND/EVENT/READMODEL/SCREEN/AUTOMATION is, how each is named, and the anti-patterns to reject, so this step doesn't restate them.
14
+
13
15
  Prefer `mcp__eventmodelers__*` tools when available (registered by the `connect` skill) — the curl blocks below are the fallback for sessions without MCP connected.
14
16
 
15
- **Purpose**: Validate any event-sourced CQRS event model against 17 architectural checks across 7 phases. Identifies anti-patterns and confirms compliance with event sourcing principles.
17
+ **Purpose**: Validate any event model against 12 structural checks across 6 phases. Identifies notation anti-patterns and confirms the model is internally consistent.
16
18
 
17
19
  **Applies To**: Any domain - e-commerce, banking, SaaS, marketplace, healthcare, etc.
18
20
 
19
21
  **When to Use**:
20
- - After completing Step 2 (Event Plot) of the 11-step event modeling workflow, as an early structural check
21
- - Alongside Step 9 (Validate), as the optional production-readiness pass before declaring model complete
22
- - When reviewing an existing event model for production readiness
23
- - When suspicious of architectural issues in event design
22
+ - After completing Step 2 (Event Plot) of the event modeling workflow, as an early structural check
23
+ - Alongside Step 9 (Validate), as an optional second pass before declaring the model complete
24
+ - When reviewing an existing event model
25
+ - When suspicious of structural issues in the model
24
26
 
25
27
  **What It Does**:
26
28
  1. Reads current board state (EVENT, COMMAND, READMODEL nodes) as input
27
- 2. Systematically applies 17 validation checks across 7 phases
28
- 2. Identifies violations of event sourcing principles (domain-agnostic)
29
- 3. Flags anti-patterns (calculations as events, non-entity streams, etc.)
29
+ 2. Systematically applies 12 validation checks across 6 phases
30
+ 3. Identifies notation anti-patterns (calculations modeled as events, events mixed into the wrong entity's timeline, etc.)
30
31
  4. Verifies read model/event distinction
31
- 5. Confirms stream independence and business rule enforcement
32
+ 5. Confirms every event and command traces cleanly
32
33
  6. Returns pass/fail verdict with evidence
33
34
 
34
35
  ---
@@ -53,52 +54,45 @@ Use the board nodes as the model input. After the checklist, use `handle-comment
53
54
 
54
55
  ## Validation Phases (Domain-Agnostic)
55
56
 
56
- ### Phase 1: Event Stream & Command Handler State Validation (4 checks)
57
- - Check 1.1: Each event belongs to exactly one stream
58
- - Check 1.2: Each command handler owns its own [CommandHandler]State class
59
- - Check 1.3: No hard dependencies between command handlers (orchestrated via events only)
60
- - Check 1.4: Each command is issued by exactly one thing — no COMMAND node has more than one inbound SCREEN/AUTOMATION edge
57
+ ### Phase 1: Event & Command Ownership Validation (2 checks)
58
+ - Check 1.1: Each event belongs to exactly one entity/timeline
59
+ - Check 1.2: Each command is issued by exactly one thing — no COMMAND node has more than one inbound SCREEN/AUTOMATION edge
61
60
 
62
- **Anti-pattern to catch**: Sharing state across handlers or treating state as persistent aggregate; a command wired from two issuers — auto-connect itself now guards against this (see `learn-eventmodelers-api` §3), so a double-issuer command found on the board is most likely a manual `set_connection` call or an edge left over from before that guard existed, not a fresh auto-connect artifact
61
+ **Anti-pattern to catch**: a command wired from two issuers — auto-connect itself now guards against this (see `learn-eventmodelers-api` §3), so a double-issuer command found on the board is most likely a manual `set_connection` call or an edge left over from before that guard existed, not a fresh auto-connect artifact
63
62
 
64
63
  ### Phase 2: Event Quality Validation (3 checks)
65
64
  - Check 2.1: Events represent domain facts, not calculations
66
65
  - Check 2.2: Event data is immutable after creation
67
66
  - Check 2.3: Event names use past tense (what actually happened)
68
67
 
69
- **Anti-pattern to catch**: Storing computed/aggregated data as events
68
+ **Anti-pattern to catch**: storing computed/aggregated data as an event
70
69
 
71
70
  ### Phase 3: Read Model vs Event Distinction (2 checks)
72
- - Check 3.1: Each read model is NOT an event stream
73
- - Check 3.2: Read model has natural query pattern
71
+ - Check 3.1: Each read model is NOT an event timeline
72
+ - Check 3.2: Read model has a natural query pattern
74
73
 
75
- **Anti-pattern to catch**: Confusing projections/calculations with domain facts
74
+ **Anti-pattern to catch**: confusing projections/calculations with domain facts
76
75
 
77
76
  ### Phase 4: Business Rules Validation (2 checks)
78
- - Check 4.1: Constraints enforced in command handler decision logic (encapsulated in [CommandHandler]State)
79
- - Check 4.2: Event preconditions are explicit (what state must exist before command is valid)
77
+ - Check 4.1: Every command's preconditions are documented explicitly
78
+ - Check 4.2: Event preconditions are explicit (what must already be true before a command is valid)
80
79
 
81
- **Anti-pattern to catch**: Business rules scattered across handlers or encoded in event stream structure
80
+ **Anti-pattern to catch**: business rules scattered across the model or left implicit ("obviously can't ship an unconfirmed order")
82
81
 
83
82
  ### Phase 5: Data Traceability (1 check)
84
83
  - Check 5.1: Input → Event → Read Model traceability is complete
85
84
 
86
- **Anti-pattern to catch**: Command inputs that disappear or read model fields without source
87
-
88
- ### Phase 6: Event Flow Validation (1 check)
89
- - Check 6.1: No impossible event sequences (state machine is sound)
90
-
91
- **Anti-pattern to catch**: Events that can occur in invalid state combinations
85
+ **Anti-pattern to catch**: command inputs that disappear, or read model fields without a source
92
86
 
93
- ### Phase 7: Stream Independence (1 check)
94
- - Check 7.1: Each stream can be versioned/restored independently
87
+ ### Phase 6: Event Flow Validation (2 checks)
88
+ - Check 6.1: No impossible event sequences (the slice-transition flow is sound)
89
+ - Check 6.2: No event belongs to more than one entity's timeline — an event that seems to span two entities usually means a naming or boundary mistake, not a shared fact
95
90
 
96
- **Anti-pattern to catch**: Hard dependencies between streams
91
+ **Anti-pattern to catch**: events that can occur in invalid combinations; a "shared" event quietly coupling two entities together
97
92
 
98
- ### Final Questions (3 checks)
99
- - Question 1: Could an architect unfamiliar with this domain understand the model in 15 minutes?
100
- - Question 2: Could you change your core algorithm/calculation without changing event history?
101
- - Question 3: Could this be implemented in your target technology stack (e.g., TypeScript + PostgreSQL)?
93
+ ### Final Questions (2 checks)
94
+ - Question 1: Could a modeler unfamiliar with this domain understand the model in 15 minutes?
95
+ - Question 2: Could the business rule/calculation behind a read model change without rewriting event history?
102
96
 
103
97
  ---
104
98
 
@@ -108,7 +102,7 @@ The skill returns a validation report with:
108
102
 
109
103
  ### For Each Check
110
104
  ```
111
- Check 1.2: Stream Root is Business Entity, Not Calculation
105
+ Check 1.2: Command Issued by Exactly One Thing
112
106
  Status: PASS
113
107
  Evidence: [Specific examples from your model]
114
108
  ```
@@ -116,7 +110,7 @@ Evidence: [Specific examples from your model]
116
110
  ### Anti-Patterns Identified (if any)
117
111
  ```
118
112
  CRITICAL: [Anti-pattern description]
119
- Problem: [Why it violates event sourcing]
113
+ Problem: [Why it violates event modeling principles]
120
114
  Violates: [Which checks fail]
121
115
  Fix: [Recommended action]
122
116
  ```
@@ -124,7 +118,6 @@ Fix: [Recommended action]
124
118
  ### Final Verdict
125
119
  ```
126
120
  Status: PASS (or PASS WITH WARNINGS or FAIL)
127
- Implementation Ready: YES (or NO - fix issues first)
128
121
  Confidence: [percentage]
129
122
  ```
130
123
 
@@ -145,100 +138,65 @@ CalculationPerformed {
145
138
  - ReadModel: MetricView (recalculated from events)
146
139
  ```
147
140
 
148
- **Why**: Calculations change multiple times as source data changes. Events are immutable.
141
+ **Why**: Calculations change as source data changes. Events are immutable.
149
142
 
150
- ### 2. Shared vs Handler-Owned State
143
+ ### 2. Command With Multiple Issuers
151
144
 
152
- The DDD-aggregate anti-pattern one shared state class used by every handler versus the correct pattern of one minimal, handler-owned state class per command. See `eventmodeling-designing-event-models`'s "Core Architectural Rule" for the full worked example (`OrderAggregate` vs. per-command state).
153
-
154
- **Why**: Each handler is a micro-slice. Separate state classes maintain isolation, enable parallel teams, prevent merge conflicts.
155
-
156
- ### 3. Circular Dependencies
157
- ```
158
- ANTI-PATTERN:
159
- StreamA → EventA → affects
160
- StreamB → EventB → affects
161
- StreamA (circular!)
162
-
163
- CORRECT:
164
- StreamA → EventA → Event Bus
165
- StreamB → EventB → Event Bus
166
- ReadModels ← consume (one-way only)
167
- No feedback loops
168
- ```
145
+ A command is never issued by more than one thing a COMMAND with 2+ inbound SCREEN/AUTOMATION edges hides which actor is actually responsible. See `place-element`'s Step 7c for the full check-and-fix mechanics (which edge to keep, how to remove the rest).
169
146
 
170
- **Why**: Circular dependencies make the system hard to reason about and test.
147
+ **Why**: Each command represents one specific trigger's decision to act collapsing two triggers onto one command node usually means either a naming/slice-boundary mistake or a stray manual/pre-existing edge (auto-connect itself now guards against fresh occurrences — see `learn-eventmodelers-api` §3).
171
148
 
172
- ### 4. Persistent State vs Ephemeral State
149
+ ### 3. An Event Shared Across Entities
173
150
  ```
174
151
  ANTI-PATTERN:
175
- Treat [CommandHandler]State as persistent entity
176
- - Save SubmitReviewState to database after command
177
- - Load it again next time
178
- - Result: Duplicates event sourcing, loses audit trail
152
+ EntityA EventA also placed on EntityB's timeline
179
153
 
180
154
  CORRECT:
181
- Reconstruct [CommandHandler]State on-demand
182
- - Load events from stream
183
- - Replay via evolve() to rebuild state
184
- - Process command, emit outcome events
185
- - Discard state (it's ephemeral, not persisted)
155
+ EntityA EventA (on EntityA's timeline only)
156
+ EntityB reacts to EventA via a read model/automation, it doesn't own it
186
157
  ```
187
158
 
188
- **Why**: State is derived from events, never stored. Events are source of truth. This enables consistent replay, audit trails, and time-travel debugging.
189
-
190
- ### 5. Command With Multiple Issuers
191
-
192
- A command is never issued by more than one thing — a COMMAND with 2+ inbound SCREEN/AUTOMATION edges hides which actor is actually responsible. See `place-element`'s Step 7c for the full check-and-fix mechanics (which edge to keep, how to remove the rest).
193
-
194
- **Why**: Each command represents one specific trigger's decision to act — collapsing two triggers onto one command node usually means either a naming/slice-boundary mistake or a stray manual/pre-existing edge (auto-connect itself now guards against fresh occurrences — see `learn-eventmodelers-api` §3).
159
+ **Why**: An event belongs to the story of exactly one entity. If a second entity needs to react to it, that's a read model or automation reading it — not the same event living on two timelines.
195
160
 
196
161
  ---
197
162
 
198
163
  ## Questions to Ask During Validation
199
164
 
200
- **For each event stream**:
201
- 1. "Do all events in this stream share the same identity (streamId)?"
202
- 2. "Could these events occur in any order, or is sequence important?"
203
- 3. "Is every event in this stream an immutable fact that actually happened?"
165
+ **For each entity's timeline**:
166
+ 1. "Do all events on this timeline belong to the same entity?"
167
+ 2. "Could these events occur in any order, or does sequence matter?"
168
+ 3. "Is every event on this timeline an immutable fact that actually happened?"
204
169
 
205
- **For each command handler**:
206
- 1. "Does this handler own its own [CommandHandler]State class?"
207
- 2. "Is the state ephemeral (reconstructed per command, not persisted)?"
208
- 3. "Can I trace the state reconstruction: events → evolve() → decision?"
170
+ **For each command**:
171
+ 1. "Are its preconditions written down, not just assumed?"
172
+ 2. "Does it produce an event, or document why it's rejected?"
209
173
 
210
174
  **For each read model**:
211
175
  1. "Is this calculated from events via a projection?"
212
176
  2. "Does it answer a specific query need?"
213
- 3. "Could its data change due to new events or state changes?"
214
-
215
- **For system architecture**:
216
- 1. "Does each command handler operate independently (communicate via events only)?"
217
- 2. "Could I run two handlers' code in parallel without merge conflicts?"
218
- 3. "Are the only shared artifacts the event definitions?"
177
+ 3. "Could its data change due to new events?"
219
178
 
220
179
  ---
221
180
 
222
181
  ## Success Criteria
223
182
 
224
183
  **Model is validated when**:
225
- - All 17 checks pass (or have documented workarounds)
184
+ - All 12 checks pass (or have documented workarounds)
226
185
  - No critical anti-patterns identified
227
- - All 3 final questions answer YES
228
- - Event sourcing principles clearly upheld
229
- - Ready to proceed to code generation
186
+ - Both final questions answer YES
187
+ - Event modeling principles are clearly upheld
230
188
 
231
189
  **Model needs fixes when**:
232
190
  - Any check fails with clear evidence
233
191
  - Anti-patterns identified with specific violations
234
- - Final questions have NO answers
192
+ - A final question has a NO answer
235
193
  - Fixes are straightforward and targeted
236
194
 
237
195
  **Model should be redesigned when**:
238
196
  - Multiple phases fail
239
- - Architectural assumptions are fundamentally flawed
197
+ - Structural assumptions are fundamentally flawed
240
198
  - Anti-patterns are systemic and pervasive
241
- - Would require rewriting core event structure
199
+ - Would require rewriting the core event timeline
242
200
 
243
201
  ---
244
202
 
@@ -248,25 +206,13 @@ A command is never issued by more than one thing — a COMMAND with 2+ inbound S
248
206
  When you see something like "CalculationDone" or "ReviewRatingUpdated":
249
207
  - Ask: "Is this immutable and caused by a user/system action?"
250
208
  - If NO → It's a read model, not an event
251
- - Fix: Remove from events, create read model projection instead
252
-
253
- ### Pattern: Shared vs Isolated State
254
- When you see "ReviewAggregate" used by multiple handlers:
255
- - Ask: "Could SubmitReviewHandler and ApproveReviewHandler work on separate files?"
256
- - If NO → State classes aren't properly isolated
257
- - Fix: Create SubmitReviewState and ApproveReviewState, each handler owns one
258
-
259
- ### Pattern: Persistent vs Ephemeral State
260
- When state is saved to database after a command:
261
- - Ask: "Is this state only needed during command processing?"
262
- - If YES → It's ephemeral, reconstruct from events instead
263
- - Fix: Load events, replay via evolve(), process command, discard state
209
+ - Fix: Remove from events, create a read model projection instead
264
210
 
265
211
  ### Pattern: Data That Doesn't Trace
266
212
  When a read model field appears without source:
267
213
  - Ask: "Where did this come from?"
268
- - If no event source → Add event or remove field
269
- - If sourced from calculation → Verify it's in projection, not event
214
+ - If no event source → Add the event or remove the field
215
+ - If sourced from a calculation → Verify it's in the read model, not the event
270
216
 
271
217
  ---
272
218
 
@@ -285,19 +231,19 @@ Step 3-8: Storyboard, Inputs, Outputs, Conway's Law, Scenarios, Completeness
285
231
 
286
232
  Step 9: Validate (eventmodeling-validating-event-models)
287
233
 
288
- → RUN eventmodeling-validating-event-models-checklist again (production-readiness pass)
234
+ → RUN eventmodeling-validating-event-models-checklist again (final structural pass)
289
235
 
290
- PASS → Step 10: Slice, Step 11: Document Reasoning → Code generation
236
+ PASS → Step 10: Slice, Step 11: Document Reasoning
291
237
  FAIL → Fix identified issues
292
238
  ```
293
239
 
294
- Running the checklist after Step 2 prevents wasting time on later steps if core events are flawed.
240
+ Running the checklist after Step 2 prevents wasting time on later steps if the core events are flawed.
295
241
 
296
242
  ---
297
243
 
298
244
  ## Checklist Questions by Domain
299
245
 
300
- The skill applies the same 17 checks regardless of domain. Here's how to think about it in different contexts:
246
+ The skill applies the same 12 checks regardless of domain. Here's how to think about it in different contexts:
301
247
 
302
248
  **E-commerce domain**:
303
249
  - Events: OrderCreated, OrderConfirmed, PaymentAuthorized, OrderShipped
@@ -321,26 +267,26 @@ The principle is the same across all domains: **immutable facts as events, calcu
321
267
 
322
268
  ## Tips for Best Results
323
269
 
324
- 1. **Be specific**: List actual event names, command handler names, and state classes from your model
325
- 2. **Reference your documentation**: Link to or quote from your step 1-7 documents and micro-slice plans
326
- 3. **Provide context**: Explain what your domain is and how handlers will be parallelized
327
- 4. **Ask follow-ups**: If a check flags an issue, ask "How do I fix this specifically?" or "Can this handler be isolated?"
328
- 5. **Iterate**: Run again after making fixes to confirm all checks pass and handlers are properly isolated
270
+ 1. **Be specific**: List actual event and command names from your model
271
+ 2. **Reference your documentation**: Link to or quote from your step 1-7 documents
272
+ 3. **Provide context**: Explain what your domain is
273
+ 4. **Ask follow-ups**: If a check flags an issue, ask "How do I fix this specifically?"
274
+ 5. **Iterate**: Run again after making fixes to confirm all checks pass
329
275
 
330
276
  ## Quality Checklist
331
277
 
332
- - [ ] All 17 checks evaluated — no check skipped without documented justification
333
- - [ ] Every FAIL result includes the specific event, handler, or stream that violated the check
278
+ - [ ] All 12 checks evaluated — no check skipped without documented justification
279
+ - [ ] Every FAIL result includes the specific event, command, or entity that violated the check
334
280
  - [ ] Anti-patterns identified by name with the exact model element that triggered the flag
335
281
  - [ ] Final verdict is one of: PASS / PASS WITH WARNINGS / FAIL — no ambiguous outcomes
336
- - [ ] All 3 final architectural questions answered YES before declaring model ready for implementation
282
+ - [ ] Both final questions answered YES before declaring the model ready
337
283
  - [ ] Any FAIL result has a recommended fix, not just a problem statement
338
284
 
339
285
  ---
340
286
 
341
287
  ## Related Skills
342
288
 
343
- - **eventmodeling-orchestrating-event-modeling**: Main skill coordinating the 11-step event modeling process
289
+ - **eventmodeling-orchestrating-event-modeling**: Main skill coordinating the full event modeling process
344
290
  - **eventmodeling-brainstorming-events**: Extract events from requirements (Step 1)
345
291
  - **eventmodeling-plotting-events**: Sequence events chronologically (Step 2)
346
292
  - **eventmodeling-designing-event-models**: Design your complete event model
@@ -350,6 +296,5 @@ The principle is the same across all domains: **immutable facts as events, calcu
350
296
 
351
297
  ## Validation Checklist Reference
352
298
 
353
- The 17-point checklist is defined in the **Validation Phases** section above.
299
+ The 12-point checklist is defined in the **Validation Phases** section above.
354
300
  Each check includes the anti-pattern to catch and questions to ask when evaluating your model.
355
-
@@ -196,9 +196,23 @@ Cell IDs are always `<rowId>-<columnId>` — no cell array search needed.
196
196
 
197
197
  **Same swimlane for events emitted by the same command.** When one command emits more than one event, each event still gets its own column (per the hard rule above), but all of them belong in the *same* swimlane row, placed in adjacent columns immediately after the command. Do not scatter a command's sibling events across different swimlane rows — one command producing multiple events is one system doing multiple things in sequence, not several systems reacting independently.
198
198
 
199
+ **One COMMAND / READMODEL / SCREEN / AUTOMATION per column — server-enforced, not just a heuristic.** Unlike the EVENT rule above (which this skill has to check for itself), the server itself rejects a second `COMMAND`, `READMODEL`, `SCREEN`/`HTML_SCREEN`, or `AUTOMATION` landing in a column that already has one of that type — across *every* row of the relevant lane (`interaction` for COMMAND/READMODEL, `actor` for SCREEN/AUTOMATION), not only the exact target cell. A board can have several separate `interaction` or `actor` rows, so the target cell itself can be empty and the placement will still fail with a `ValidationError` ("Column already has a … node … — only one … is allowed per column"). Treat that rejection exactly like a same-cell conflict in the table below — insert a new column rather than retrying the same one.
200
+
199
201
  **Check if the cell is already occupied.**
200
202
 
201
- **No direct MCP equivalent**: `get_nodes` only filters by `type`, not `cellId` — there is no MCP tool that filters nodes by cell. Instead, use the `cells` array you already fetched in Step 3 via `get_node` (`projection: "cells"`) on the chapter/timeline node: `cells` is a sparse array, so a `nodeId` absent from the entry for `CELL_ID` means the cell is empty. Only fall back to the curl call below if you haven't already loaded `timelineData` (e.g. MCP wasn't used in Step 3 either):
203
+ **Fastest path**: use the `cells` array you already fetched in Step 3 via `get_node` (`projection: "cells"`) on the chapter/timeline node `cells` is a sparse array, so a `nodeId` absent from the entry for `CELL_ID` means the cell is empty. Also scan it for the column-wide conflict from the rule above: any entry with `colId === columnId` and `nodeType === elementType` (for COMMAND/READMODEL/SCREEN/AUTOMATION) means the column is occupied even though `CELL_ID` itself is free. This avoids an extra round-trip, but can be stale if a column was just created in Step 5 — re-fetch first in that case.
204
+
205
+ **No direct MCP equivalent** for querying by cell/column: `get_nodes` only filters by `type`. The REST API does support it directly though — `GET /nodes` takes `cellId` **or** `colId`, both requiring `timelineId`:
206
+
207
+ ```bash
208
+ # Same-cell occupancy — returns [] if empty, or [nodeRecord] if occupied
209
+ curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?cellId=$CELL_ID&timelineId=$TIMELINE_ID"
210
+
211
+ # Column-wide occupancy (any row) — optionally add &type=READMODEL to narrow to one element type
212
+ curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?colId=$COLUMN_ID&timelineId=$TIMELINE_ID"
213
+ ```
214
+
215
+ Use this REST call (see the curl fallback below) when you don't already have fresh `timelineData` loaded, instead of re-fetching the whole chapter node just to check occupancy.
202
216
 
203
217
  **Fallback (no MCP):** see `references/api-fallback.md` — "Step 6 — Check cell occupancy".
204
218
 
@@ -55,10 +55,20 @@ Response: `{ "columnId": "<uuid>", "index": <n>, "totalColumns": <n> }`
55
55
 
56
56
  ## Step 6 — Check cell occupancy
57
57
 
58
+ `GET /nodes` takes `cellId` **or** `colId`, both requiring `timelineId` — no need to re-fetch and parse the whole chapter node just for this:
59
+
58
60
  ```bash
59
- curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?cellId=$CELL_ID"
61
+ # Same-cell occupancy — [] if empty, [nodeRecord] if occupied
62
+ curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?cellId=$CELL_ID&timelineId=$TIMELINE_ID"
63
+
64
+ # Same-column occupancy, across every row of the timeline — add &type=<elementType> to narrow
65
+ # (the server enforces one COMMAND/READMODEL/SCREEN/HTML_SCREEN/AUTOMATION per column even when
66
+ # the target cell itself is empty — see SKILL.md)
67
+ curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?colId=$COLUMN_ID&timelineId=$TIMELINE_ID"
60
68
  ```
61
69
 
70
+ If you already have fresh `timelineData` loaded from Step 3, reading its `cells` array directly (sparse — an entry only exists once something has been placed there) avoids the extra round-trip; use the calls above otherwise, or when `timelineData` might be stale (e.g. a column was just created).
71
+
62
72
  ## Step 6 — Insert a column at a specific index (conflict resolution)
63
73
 
64
74
  No relative-insertion equivalent over REST (unlike MCP's `afterNodeId`) — compute the index by hand: