@eventmodelers/cli 1.0.28 → 1.0.30

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventmodelers/cli",
3
- "version": "1.0.28",
3
+ "version": "1.0.30",
4
4
  "description": "Eventmodelers CLI — real-time Claude agent + skills for Claude Code, for any stack (Node, Supabase, Axon, Cratis, or modeling-only)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -207,8 +207,8 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
207
207
  }]'
208
208
  ```
209
209
 
210
- **Stack timelines vertically so they do not overlap.**
211
- After creating each chapter, position it below the previous one. Use `y = index * 1200` (0-based creation order), `x = 0`. If existing chapters are already on the board, query their positions first and place the new chapter below the lowest one (`y = maxExistingY + 1200`). Pass this directly as `x`/`y` on `create_chapter` above, or reposition an existing chapter with:
210
+ **Stack timelines vertically so they do not overlap, and in general place new chapters close to existing ones they relate to.**
211
+ After creating each chapter, position it below the previous one. Use `y = index * 1200` (0-based creation order), `x = 0`. If existing chapters are already on the board, query their positions first. Prefer placing the new chapter directly below the existing chapter it is most closely related to (e.g. the same bounded context or an adjacent workflow), rather than mechanically appending below the lowest one — this keeps related chapters visually near each other on the canvas. Only fall back to `y = maxExistingY + 1200` when no related chapter exists yet. Pass this directly as `x`/`y` on `create_chapter` above, or reposition an existing chapter with:
212
212
 
213
213
  **Prefer MCP:**
214
214
  ```
@@ -353,6 +353,8 @@ mcp__eventmodelers__submit_node_events {
353
353
 
354
354
  > **Never call `drop` after using `cellId` in `node:created`.** The drop endpoint adds a second cell reference without removing the first. `node:created + cellId` is the only placement step needed.
355
355
 
356
+ > **One EVENT per column (hard rule).** A column is a single moment in the timeline — never place two EVENT nodes in the same column, even when they sit in different swimlane rows (e.g. two systems under Conway's Law). Step A above always appends a fresh column per event, which already satisfies this; if you ever reuse an existing column instead of appending, first confirm no swimlane row in that column already holds an EVENT. **Don't resolve this by checkerboarding across swimlanes** — see "Swimlane Rules (Mandatory)" below: this chapter's own swimlane carries the continuous story; the other swimlane only ever gets an isolated single-column handover, then the story resumes back in this swimlane.
357
+
356
358
  ### Mode B — Free-form brainstorming (no chapter yet)
357
359
 
358
360
  When chapters have not been created yet, events may be created without `chapterId` or `cellId`. They appear as free-floating sticky notes on the canvas. This is valid during open discovery.
@@ -366,18 +368,16 @@ An event left without a chapter and cell reference will never appear in any time
366
368
 
367
369
  ## Swimlane Rules (Mandatory)
368
370
 
369
- Do not create unnecessary swimlanes. Before adding a lane, check whether an existing lane already covers the element's type. If yes, place the element in that lane.
370
-
371
- **Only create a new swimlane when:**
372
- - A new actor is introduced that has no existing lane, **or**
373
- - An explicit business rule requires a distinct lane
371
+ **Use swimlanes sparingly — a swimlane exists for exactly one purpose: marking where integration with another system happens. Nothing else justifies one.** Not a different actor, not a different role, not visual grouping, not "an explicit business rule" in the abstract. Every chapter starts with, and in the common case keeps, a single default swimlane holding all of this bounded context's own domain events. Before adding a lane, check whether an existing lane already covers the element's type. If yes, place the element in that lane.
374
372
 
375
- **Never** add a swimlane just to group things visually or because a second role appearsuse the existing lane if the type matches.
373
+ **The only valid reason to create a second `swimlane`-type lane: another system's own events cross into this chapter as integration triggers for a translation automation** (see `eventmodeling-identifying-outputs` Step 5b). Label it for that system and place its trigger events there never fold them into this chapter's own event swimlane (they are not this bounded context's domain facts) and never treat them as an informal "signal" with no EVENT node at all. An external EVENT may only ever open the *translation* automation's todo list — never the todo list of the automation that does the actual domain work; that automation is triggered solely by the internal event the translation automation produces (Step 5b covers the full two-automation chain).
376
374
 
377
- **Exception: a second `swimlane`-type lane for another system's own events.** When an external/other-team system's events cross into this chapter as integration triggers for an automation (see `eventmodeling-identifying-outputs` Step 5b), add a second swimlane lane labeled for that system and place its trigger events there — never fold them into this chapter's own event swimlane (they are not this bounded context's domain facts) and never treat them as an informal "signal" with no EVENT node at all.
375
+ **Never** add a swimlane for any other reason not a new actor, not a new role, not visual grouping. Human roles get their own **actor** lane during Step 3 (Storyboarding) a different row type entirely — never a new swimlane here.
378
376
 
379
377
  **When two swimlanes exist side by side, tell a continuous story from this chapter's own swimlane as much as possible — don't checkerboard between them.** Having a second swimlane for an external system does not mean every other column should alternate between "our event" and "their event." Keep a run of consecutive columns in this chapter's own swimlane while the domain process is unfolding, and only place an event in the external swimlane where a real cross-system trigger occurs (the external system reacting to, or producing, an event that actually drives the next step of this chapter's process). If two adjacent columns each have an event in a different swimlane but neither one triggers or is triggered by the other, that's a sign the events were placed for visual symmetry rather than because the story actually crossed system boundaries there — revisit the plotting instead.
380
378
 
379
+ **An event in the other swimlane is a handover, not a relocation.** It marks a single moment where control passes to the other system — it does not mean the narrative now belongs to that swimlane for a run of columns. Immediately after the handover column, the story resumes in *this* chapter's own swimlane (the next column back in this swimlane), not in the other one. The other swimlane should typically show isolated, single-column events at each genuine handover point, never a multi-column stretch of its own — a long run of consecutive events in the external swimlane is a sign the events belong in a chapter of their own, not this one's.
380
+
381
381
  ---
382
382
 
383
383
  ## Workshop Facilitation Guide
@@ -504,7 +504,7 @@ Present as a Role Catalog:
504
504
  ```
505
505
 
506
506
  This catalog feeds directly into:
507
- - **Step 3 (Storyboarding)**: One swimlane per human role
507
+ - **Step 3 (Storyboarding)**: One actor lane per human role (not a swimlane — see Swimlane Rules above)
508
508
  - **Step 4 (Inputs)**: Every command attributed to a specific role/actor
509
509
  - **Step 7 (Scenarios)**: Scenarios reference roles by name
510
510
  - **Step 8 (Completeness)**: Verify every role has at least one command path
@@ -674,5 +674,5 @@ Include error and boundary conditions:
674
674
  - [ ] No overlapping event semantics — two events don't mean the same thing
675
675
  - [ ] Every event is placed into a **named chapter** — no event left in an untitled or default timeline
676
676
  - [ ] **Multiple chapters are stacked vertically** (y offset of 1200 per chapter) — no two chapters overlap on the canvas
677
- - [ ] No unnecessary swimlanes created — existing lanes reused when the type matches; new lanes added only for new actors or explicit business rules
678
- - [ ] **When a second (external-system) swimlane exists, events follow one continuous story from this chapter's own swimlane as much as possible** — no mechanical alternation between the two swimlanes column-to-column; the external swimlane is only used where a genuine cross-system trigger occurs
677
+ - [ ] No unnecessary swimlanes created — a swimlane exists only to mark integration with another system; never added for a new actor, a new role, or visual grouping
678
+ - [ ] **When a second (external-system) swimlane exists, events follow one continuous story from this chapter's own swimlane throughout** — the external swimlane only ever holds isolated single-column handovers, never a run of its own, and the story resumes in this chapter's swimlane immediately after each one
@@ -405,12 +405,18 @@ After this step is done, **every SCREEN and every AUTOMATION on the board must b
405
405
  - `NotificationSent` (the event this automation's own resulting command produces) **closes** that row (removes it — the list only ever shows outstanding work).
406
406
  - The automation (`Send Welcome Notification`) reads `NotificationsToSend`, and for every open row issues `SendNotification`.
407
407
 
408
- Even an automation that looks like a "pure signal relay" (e.g. translating an external system's trigger straight into a local command with no visible decision) still has a todo list — model it anyway: it documents that the automation is idempotent/complete once its own event fires, and keeps every automation consistent with the same `READMODEL → AUTOMATION → COMMAND → EVENT` pattern instead of silently exempting some as "too simple to need one." This applies without exception even when the automation's trigger comes from another team's system (Step 6 territory) whose upstream decision logic is out of scope for this model.
408
+ Even an automation that looks like a "pure signal relay" still has a todo list — model it anyway: it documents that the automation is idempotent/complete once its own event fires, and keeps every automation consistent with the same `READMODEL → AUTOMATION → COMMAND → EVENT` pattern instead of silently exempting some as "too simple to need one."
409
409
 
410
- **There is no such thing as an invisible or informal "signal" — a trigger is always a real EVENT node, placed in a second swimlane when it belongs to another system.** Do not model an externally-triggered automation's todo list as "opened and closed by the same event" — that conflates the external trigger with this chapter's own resulting fact and produces a todo list that is never meaningfully open. Instead:
411
- 1. Add a second `swimlane`-type lane to the chapter (`add_lane` with `type: "swimlane"`, labeled for the external system, e.g. "Reservation & Pickup System (external)") — a chapter can have more than one lane of the same type, and this lane holds that other system's own events as this chapter sees them, distinct from this chapter's own swimlane.
412
- 2. Place one EVENT per integration trigger point in that second swimlane, in the **same column** as the AUTOMATION/COMMAND/EVENT triplet it feeds (e.g. `ReservationRequested` in the same column as the `ReserveCopy` automation/command/`CopyReserved` event). This event represents that other system's own domain fact arriving at the boundary it is a real, first-class EVENT, not a comment or a placeholder.
413
- 3. Wire the todo list the standard way: the external EVENT (second swimlane) **opens** the row, this chapter's own resulting EVENT (first swimlane, the same event the automation's command produces) **closes** it — the typical, expected shape for this kind of automation, matching the general open/close pattern above exactly. `EVENT → READMODEL` connections from both swimlanes are unaffected by which swimlane the event sits in.
410
+ **There is no such thing as an invisible or informal "signal" — a trigger is always a real EVENT node, placed in a second swimlane when it belongs to another system.**
411
+
412
+ **An automation can only ever be directly triggered by an internal event — never by another system's event.** A "trigger" arriving from a second swimlane is not itself the thing that drives your domain's work; it first has to be *translated* into an internal event. Do not model this as one automation whose todo list is opened by the external EVENT and that also does the real work (e.g. an automation reading a todo list opened by `ReservationRequested` from another system's swimlane and directly issuing `ReserveCopy`) that lets an external system trigger domain work with no translation step, which this model doesn't allow. When an integration trigger comes from another team's system (Step 6 territory), model it as **two chained automations**, never one:
413
+
414
+ 1. **Translation automation** — its only job is converting the external fact into an internal one; the upstream decision logic on the other system's side is out of scope. Its todo list is opened by the external EVENT (second swimlane) and closed by the internal EVENT its own command produces — this is the one and only place an external EVENT is allowed to open a todo list.
415
+ - Second swimlane: place one EVENT per integration trigger point there, in the **same column** as this translation automation's AUTOMATION/COMMAND/EVENT triplet (e.g. `ReservationRequested` in the same column as a `Record Reservation Request` automation/command/`ReservationRequestReceived` event). This event represents that other system's own domain fact arriving at the boundary — it is a real, first-class EVENT, not a comment or a placeholder.
416
+ - Its command and resulting event carry no business decision of their own — they exist to produce the internal event the next automation needs, nothing more.
417
+ 2. **Worker automation** — the one that does the actual work (the domain reaction the process is really about, e.g. `ReserveCopy`). Its todo list is opened **only** by the internal EVENT the translation automation produced (this chapter's own swimlane) — never by the external EVENT directly — and closed by whatever event marks that work done.
418
+
419
+ Wire the todo lists the standard way for each automation separately: for the translation automation, the external EVENT (second swimlane) **opens** the row and its own resulting internal EVENT **closes** it; for the worker automation, that same internal EVENT **opens** its row and its own resulting EVENT **closes** it. `EVENT → READMODEL` connections from both swimlanes are unaffected by which swimlane the event sits in.
414
420
 
415
421
  **Fields**: a todo-list read model's fields describe the pending item — the identity it's about (e.g. `customerId`) plus enough context to act on it (e.g. `email`, `notificationType`). Do not add a `status` field to mark items done — a todo list's "open" state is *membership in the list itself* (the row exists at all), not a status flag on a row that never leaves. If the same underlying data is also useful with an explicit status column for a different consumer, that is a different read model, not this one.
416
422
 
@@ -771,6 +777,7 @@ Identify UI needs without event sources:
771
777
  - [ ] **Typical pattern applied**: most screens follow `READ MODEL → SCREEN → COMMAND → EVENT`
772
778
  - [ ] **Every SCREEN from storyboarding is connected to at least one read model** (via `READMODEL → SCREEN`); only blank creation forms may be exempt — verified via the mandatory per-node pass above, not assumed
773
779
  - [ ] **Every AUTOMATION from storyboarding is connected to at least one todo-list read model** (via `READMODEL → AUTOMATION`, Step 5b) — no exemption for automations, unlike screens; even a simple relay automation gets one
780
+ - [ ] **No automation's todo list is opened directly by another system's (second-swimlane) EVENT unless that automation is itself the translation automation** (Step 5b) — an automation doing the actual domain work is only ever opened by an internal event; a second-swimlane EVENT feeding straight into a work automation's todo list is a missing translation automation
774
781
  - [ ] **No read model is placed without a connected SCREEN or AUTOMATION consumer**
775
782
  - [ ] **No read model spans more than one component** — a screen with N distinct components gets N read models and N highlighted screen copies (same screen name, one component crisp per copy), not one screen-wide read model
776
783
  - [ ] **Every multi-component screen was broken apart in Step 5c** — each copy keeps the original screen's name, differs only in which component is marked/highlighted
@@ -129,7 +129,9 @@ Work within the chosen timeline only. For each event in the final chronological
129
129
  | `boardId` | `BOARD_ID` |
130
130
  | `timelineId` | the chapter this event belongs to |
131
131
 
132
- Reuse existing empty columns, do not blindly create new ones.
132
+ Reuse existing empty columns, do not blindly create new ones. "Empty" means no EVENT anywhere in that column — **never place two EVENT nodes in the same column, even across different swimlanes**; each column is a single moment in the timeline. If the column already holds an EVENT in another swimlane, place this one in a new column instead (see `place-element`'s one-EVENT-per-column rule).
133
+
134
+ **Do not resolve that conflict by checkerboarding.** When a chapter has more than one swimlane (e.g. a second system's events, see `eventmodeling-brainstorming-events`'s Swimlane Rules), the chapter's own swimlane carries the continuous story throughout — do not alternate "our event, their event, our event, their event" column by column just because each needs its own column, and do not give the other swimlane a multi-column run of its own either. An event in the other swimlane is a single-column handover: it marks one moment where control passes to the other system, and the very next column returns to this chapter's own swimlane to continue the story. Two swimlanes trading events every column with no genuine trigger behind each handover is a sign of forcing visual symmetry rather than following the actual causal order — re-sequence instead. If the other swimlane ends up needing a long run of its own consecutive events, that's a sign those events belong in a chapter of their own, not this one.
133
135
 
134
136
  Process events in order, one at a time. Do not skip any event.
135
137
 
@@ -237,6 +237,8 @@ Using the `timelineData` already fetched in Step 3 (re-fetch if a column was jus
237
237
 
238
238
  Cell IDs are always `<rowId>-<columnId>` — no cell array search needed.
239
239
 
240
+ **One EVENT per column (hard rule).** A column represents a single moment in the timeline. When `elementType` is `EVENT`, an occupied column means occupied *at all* — even if the existing EVENT sits in a different swimlane row (e.g. a different system under Conway's Law). Never place two EVENT nodes in the same column just because they're in different swimlanes. Before treating the column as available, check `cells` for **every** row whose `type === "swimlane"`, not only `targetRow` — if any of those cells already holds an EVENT node, treat the column as occupied and insert a new column immediately after (see the table below), not the target column itself.
241
+
240
242
  **Check if the cell is already occupied.**
241
243
 
242
244
  **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 `meta.timelineData.cells` you already fetched in Step 3 via `get_node` 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):
@@ -253,6 +255,7 @@ curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?cellId=$CELL_ID"
253
255
  |---|---|---|
254
256
  | `READMODEL` | `COMMAND` (state-change slice already owns this column) | Insert a **new column immediately after** the current column (not at the end) and use that new column as the target. |
255
257
  | `SCREEN` (view/output screen) | any | Same as READMODEL — insert immediately after. |
258
+ | `EVENT` | `EVENT` in **any other swimlane row of the same column** | Insert a new column immediately after — an EVENT never shares a column with another EVENT, even across different swimlanes. |
256
259
  | Any | Same element type | Stop and tell the user — true conflict, no safe default. |
257
260
  | Any | Different type but not a known pairing | Stop and tell the user. |
258
261