@eventmodelers/cli 1.0.80 → 1.0.84

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 (40) hide show
  1. package/cli.js +2 -2
  2. package/package.json +1 -1
  3. package/shared/skills/connect/SKILL.md +6 -4
  4. package/shared/skills/learn-eventmodelers-api/SKILL.md +24 -21
  5. package/shared/skills/request-feedback/SKILL.md +0 -2
  6. package/shared/skills/update-slice-status/SKILL.md +0 -2
  7. package/stacks/modeling-kit/templates/.claude/skills/attributes/SKILL.md +2 -2
  8. package/stacks/modeling-kit/templates/.claude/skills/attributes/references/api-fallback.md +1 -3
  9. package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/SKILL.md +19 -17
  10. package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/references/api-fallback.md +0 -2
  11. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/SKILL.md +0 -4
  12. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/references/api-fallback.md +0 -4
  13. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-automation-chains/SKILL.md +9 -8
  14. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-automation-chains/references/api-fallback.md +0 -1
  15. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/SKILL.md +9 -9
  16. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/references/api-fallback.md +0 -2
  17. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/SKILL.md +10 -9
  18. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/references/api-fallback.md +0 -2
  19. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/SKILL.md +14 -13
  20. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/references/api-fallback.md +4 -4
  21. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/SKILL.md +2 -2
  22. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/examples.md +2 -2
  23. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/SKILL.md +11 -11
  24. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/references/api-fallback.md +0 -2
  25. package/stacks/modeling-kit/templates/.claude/skills/examples/SKILL.md +1 -3
  26. package/stacks/modeling-kit/templates/.claude/skills/examples/references/api-fallback.md +1 -3
  27. package/stacks/modeling-kit/templates/.claude/skills/handle-comment/SKILL.md +2 -2
  28. package/stacks/modeling-kit/templates/.claude/skills/html-screen/SKILL.md +8 -8
  29. package/stacks/modeling-kit/templates/.claude/skills/html-screen/references/api-fallback.md +0 -1
  30. package/stacks/modeling-kit/templates/.claude/skills/place-element/SKILL.md +31 -26
  31. package/stacks/modeling-kit/templates/.claude/skills/place-element/references/api-fallback.md +5 -9
  32. package/stacks/modeling-kit/templates/.claude/skills/storyboard/SKILL.md +18 -15
  33. package/stacks/modeling-kit/templates/.claude/skills/storyboard/references/api-fallback.md +0 -1
  34. package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/SKILL.md +0 -1
  35. package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/references/api-fallback.md +0 -1
  36. package/stacks/modeling-kit/templates/.claude/skills/timeline/SKILL.md +4 -8
  37. package/stacks/modeling-kit/templates/.claude/skills/timeline/references/api-fallback.md +1 -7
  38. package/stacks/modeling-kit/templates/.claude/skills/wdyt/SKILL.md +19 -7
  39. package/stacks/modeling-kit/templates/kit/AGENTS.md +2 -1
  40. package/stacks/modeling-kit/templates/kit/CLAUDE.md +1 -1
@@ -110,7 +110,7 @@ For each returned node, check whether it has a valid cell assignment. A node wit
110
110
 
111
111
  **Prefer MCP:**
112
112
  ```
113
- mcp__eventmodelers__delete_node { "boardId": "$BOARD_ID", "nodeId": "<nodeId>" }
113
+ mcp__eventmodelers__delete_node { "boardId": "$BOARD_ID", "nodeIds": ["<nodeId>"] }
114
114
  ```
115
115
 
116
116
  **Fallback (no MCP):** see `references/api-fallback.md` — "No unplaced elements (0,0 nodes) — Delete an orphaned node".
@@ -135,18 +135,20 @@ Screens placed during Step 3 (Storyboarding) are provisional positions. Steps 4
135
135
  ### Column insertion
136
136
  Use `add_column` with `{"index": N}` to insert a column at a specific position (shifts existing columns right) — or, when the insertion point is "immediately before/after a node already on the board" rather than a numeric position you'd otherwise have to compute, pass `beforeNodeId`/`afterNodeId` instead and let the tool resolve the index itself. Do not use no position at all (append) when placing read models or view screens — always target the correct position.
137
137
 
138
- **Suppress auto-connect when inserting into an existing chain.** When you insert columns next to nodes that are *not* meant to connect to what you're about to place — e.g. slotting an output read model's column in beside an automation-chain column — the node placement's default auto-connect will wire the new node to whatever type-compatible node happens to sit in its own or the previous column (the "nearest event to the left"). That is the source of the recurring stray-edge cleanup. When the placement you're about to make should be wired only by your own explicit `set_connections` batch, pass `autoConnect: false` on the placing call (`submit_node_events`, `place_element`, `create_screen`/`create_screens`) and then wire every edge yourself. Keep the default (auto-connect on) for Steps 1/3/4 where same-column neighbors are exactly the intended wiring.
138
+ **Suppress auto-connect when inserting into an existing chain.** When you insert columns next to nodes that are *not* meant to connect to what you're about to place — e.g. slotting an output read model's column in beside an automation-chain column — the node placement's default auto-connect will wire the new node to whatever type-compatible node happens to sit in its own or the previous column (the "nearest event to the left"). That is the source of the recurring stray-edge cleanup. When the placement you're about to make should be wired only by your own explicit `set_connection` batch, pass `autoConnect: false` on the placing call (`submit_node_events`, `place_element`, `create_screen`) and then wire every edge yourself. Keep the default (auto-connect on) for Steps 1/3/4 where same-column neighbors are exactly the intended wiring.
139
139
 
140
- ### Prefer batch MCP tools over one-call-per-item loops
140
+ ### Every write tool takes an array — fill it
141
141
 
142
- Several MCP tools have a batch form that does the exact same thing as calling their singular form once per item, with the same validation rules and (where order matters, e.g. wiring a READMODEL→AUTOMATION edge before the backward EVENT→READMODEL edge that depends on it) the same in-order guarantee just fewer round trips. Whenever a step's own instructions below show a single-item call and more than one item is being processed in the same pass, use the batch form instead:
142
+ Each write tool takes its items as an array, so handling several in one pass is one call rather than a loop. Entries are applied in order — which matters where a later one depends on an earlier one, e.g. wiring a READMODEL→AUTOMATION edge before the backward EVENT→READMODEL edge that needs it every entry reports its own outcome or error in `results`, and one failure does not stop the rest. Whenever a step's instructions below show a one-entry call and more than one item is being processed in the same pass, extend the array instead of repeating the call:
143
143
 
144
- - `set_connections` (not `set_connection` repeated) — wiring multiple edges
145
- - `auto_connect_nodes` (not `auto_connect_node` repeated) — auto-connecting multiple freshly-placed nodes
146
- - `create_slice_definitions` (not `create_slice_definition` repeated) — defining multiple slices
147
- - `create_screens` (not `create_screen` repeated) — creating multiple HTML screens whose content is already authored
148
- - `move_nodes` (not `move_node_in_timeline` repeated) moving multiple already-placed nodes within one timeline
149
- - `delete_nodes` / `delete_columns` (not `delete_node`/`delete_column` repeated) removing multiple nodes or columns, e.g. a corrective cleanup after a modeling mistake
144
+ - `set_connection`'s `connections` — wiring multiple edges
145
+ - `auto_connect_node`'s `nodeIds` — auto-connecting multiple freshly-placed nodes
146
+ - `create_slice_definition`'s `slices` — defining multiple slices
147
+ - `create_screen`'s `screens` — creating multiple screens
148
+ - `place_element`'s `elements` — laying out a whole slice or column run, each entry seeing the columns the previous one added
149
+ - `move_node_in_timeline`'s `moves` — moving multiple already-placed nodes within one timeline
150
+ - `delete_node`'s `nodeIds` / `delete_column`'s `columnIds` — removing multiple nodes or columns, e.g. a corrective cleanup after a modeling mistake
151
+ - `add_comment`'s `comments`, `create_drawing`'s `drawings`, `add_lane`'s `lanes` — same shape
150
152
  - `add_column`'s `count` param (not `add_column` repeated) — appending or inserting several columns at once; `beforeNodeId`/`afterNodeId` resolve the insertion point from an already-placed node instead of a computed index
151
153
  - `create_chapter`'s `columns` param — when the chapter's initial column count is already known, instead of creating the default 3 and appending more after
152
154
 
@@ -156,7 +158,7 @@ For a "what is on the board and how is it wired right now" check between steps
156
158
 
157
159
  **Structural validation is one call, not a scan.** `validate_model` (`{boardId, chapterId}`) runs the whole structural checklist server-side — unplaced nodes, backward arrows (todo-list exception applied), zero/multi-issuer commands, sourceless read models, two-screens-in-a-column, missing scenarios — and returns only `findings`. Use it for the mandatory post-step unplaced check and as the first move in Step 9, instead of per-type `get_nodes` loops and `get_node` `projection: "edges"` spot-checks.
158
160
 
159
- **Ask echo-heavy write tools for less.** `add_scenario`, `add_storyline`, `set_connections` and `submit_node_events` each accept `compact: true`, which drops the full-object echo from the response (returning `{specNodeId, added, count, isNewNode}`, a `{connected, existed, removed, notFound, failed, errors}` tally, or `{persisted: <count>}` respectively). Pass it whenever you're not going to read individual fields back off the response — which is almost always for a large `set_connections` batch or a bulk scenario post.
161
+ **Ask echo-heavy write tools for less.** `add_scenario`, `add_storyline`, `set_connection` and `submit_node_events` each accept `compact: true`, which drops the full-object echo from the response (returning `{specNodeId, added, count, isNewNode}`, a `{connected, existed, removed, notFound, failed, errors}` tally, or `{persisted: <count>}` respectively). Pass it whenever you're not going to read individual fields back off the response — which is almost always for a large `set_connection` batch or a bulk scenario post.
160
162
 
161
163
  ### Documenting decisions inline, at any step
162
164
 
@@ -416,7 +418,7 @@ Not delegated to a separate skill — performed directly by this orchestrating s
416
418
 
417
419
  **Prefer MCP:**
418
420
  ```
419
- mcp__eventmodelers__add_lane { "boardId": "$BOARD_ID", "timelineId": "$CHAPTER_ID", "type": "feedback", "label": "Notes" }
421
+ mcp__eventmodelers__add_lane { "boardId": "$BOARD_ID", "timelineId": "$CHAPTER_ID", "lanes": [{ "type": "feedback", "label": "Notes" }] }
420
422
  ```
421
423
 
422
424
  **Fallback (no MCP):** see `references/api-fallback.md` — "Step 11 — Document Reasoning — Add a feedback lane".
@@ -431,7 +433,6 @@ Not delegated to a separate skill — performed directly by this orchestrating s
431
433
  "boardId": "$BOARD_ID",
432
434
  "events": [{
433
435
  "id": "<event-uuid>", "eventType": "node:created", "nodeId": "<node-uuid>",
434
- "boardId": "$BOARD_ID", "timestamp": 1234567890,
435
436
  "chapterId": "$CHAPTER_ID", "cellId": "<feedbackLaneId>-<firstColumnId>",
436
437
  "meta": { "type": "MARKDOWN", "title": "Modeling Reasoning — <Chapter Name>", "description": "<full markdown body>" }
437
438
  }]
@@ -17,8 +17,8 @@ done
17
17
  curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
18
18
  -H "x-token: $TOKEN" -H "x-user-id: orchestrator" \
19
19
  -H "Content-Type: application/json" \
20
- -d '[{"id":"<uuid>","eventType":"node:changed","nodeId":"<nodeId>","boardId":"<BOARD_ID>",
21
- "timestamp":1234567890,"chapterId":"<chapterId>","cellId":"<rowId>-<colId>",
20
+ -d '[{"id":"<event-uuid>","eventType":"node:changed","nodeId":"<nodeId>",
21
+ "chapterId":"<chapterId>","cellId":"<rowId>-<colId>",
22
22
  "meta":{"type":"<TYPE>","title":"<title>"}}]'
23
23
  ```
24
24
 
@@ -45,7 +45,7 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$CHAPTER_I
45
45
  curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
46
46
  -H "x-token: $TOKEN" -H "x-user-id: orchestrator" \
47
47
  -H "Content-Type: application/json" \
48
- -d '[{"id":"<event-uuid>","eventType":"node:created","nodeId":"<node-uuid>","boardId":"<BOARD_ID>",
49
- "timestamp":1234567890,"chapterId":"<CHAPTER_ID>","cellId":"<feedbackLaneId>-<firstColumnId>",
48
+ -d '[{"id":"<event-uuid>","eventType":"node:created","nodeId":"<node-uuid>",
49
+ "chapterId":"<CHAPTER_ID>","cellId":"<feedbackLaneId>-<firstColumnId>",
50
50
  "meta":{"type":"MARKDOWN","title":"Modeling Reasoning — <Chapter Name>","description":"<full markdown body>"}}]'
51
51
  ```
@@ -99,7 +99,7 @@ For every column from Step 2 that doesn't already have a matching slice, mark ea
99
99
 
100
100
  Prefer MCP:
101
101
  ```
102
- mcp__eventmodelers__create_slice_definitions { "boardId": "<BOARD_ID>", "timelineId": "<TL>", "slices": [
102
+ mcp__eventmodelers__create_slice_definition { "boardId": "<BOARD_ID>", "timelineId": "<TL>", "slices": [
103
103
  { "columnId": "<colId1>", "title": "PlaceOrder" },
104
104
  { "columnId": "<colId2>", "title": "OrderStatusView" }
105
105
  ] }
@@ -112,7 +112,7 @@ mcp__eventmodelers__create_slice_definitions { "boardId": "<BOARD_ID>", "timelin
112
112
  - READMODEL column → title = read model name (state-view slice)
113
113
  - AUTOMATION column → title = automation name, or the command it issues (automation slice)
114
114
 
115
- Use **`create_slice_definitions`/`slice-definitions`**, never `create_slice`/the plain **`slices`** endpoint here — `create_slice`/`slices` creates a brand-new column with its own swimlane/content nodes, which would duplicate the element already placed on the timeline. `create_slice_definitions`/`slice-definitions` only adds a `SLICE_BORDER` node to each column you already resolved in Step 2. `title` always comes from the request body — it is never derived automatically from the command/read model/automation node.
115
+ Use **`create_slice_definition`/`slice-definitions`**, never `create_slice`/the plain **`slices`** endpoint here — `create_slice`/`slices` creates a brand-new column with its own swimlane/content nodes, which would duplicate the element already placed on the timeline. `create_slice_definition`/`slice-definitions` only adds a `SLICE_BORDER` node to each column you already resolved in Step 2. `title` always comes from the request body — it is never derived automatically from the command/read model/automation node.
116
116
 
117
117
  **If Step 2 finds nothing to slice** (every COMMAND/READMODEL/AUTOMATION on the timeline already has a matching `SLICE_BORDER`), this skill's job is done — there is no existing element left to make explicit. Do not invent new model content here; that is out of scope for a skill whose whole design assumes the model is already complete. Invoke the `add-next-slice` skill instead — it owns deciding on and creating a genuinely new slice from scratch.
118
118
 
@@ -50,10 +50,10 @@ No slice depends on another slice directly — only on the events it produces.
50
50
 
51
51
  ## Creating These Slices via the API
52
52
 
53
- These elements already exist on the timeline (from `spec-info`) — use `create_slice_definitions`/`slice-definitions`, which only adds a `SLICE_BORDER` to each column's existing element. Never use `create_slice`/the plain `/slices` endpoint here: that endpoint creates a brand-new column with its own nodes, which would duplicate the element already on the board.
53
+ These elements already exist on the timeline (from `spec-info`) — use `create_slice_definition`/`slice-definitions`, which only adds a `SLICE_BORDER` to each column's existing element. Never use `create_slice`/the plain `/slices` endpoint here: that endpoint creates a brand-new column with its own nodes, which would duplicate the element already on the board.
54
54
 
55
55
  ```
56
- mcp__eventmodelers__create_slice_definitions { "boardId": "<BOARD_ID>", "timelineId": "<TL>", "slices": [
56
+ mcp__eventmodelers__create_slice_definition { "boardId": "<BOARD_ID>", "timelineId": "<TL>", "slices": [
57
57
  { "columnId": "<placeOrderColumnId>", "title": "PlaceOrder" },
58
58
  { "columnId": "<orderDetailViewColumnId>", "title": "OrderDetailView" },
59
59
  { "columnId": "<reserveInventoryOnPaymentColumnId>", "title": "ReserveInventoryOnPayment" }
@@ -122,7 +122,7 @@ After completing the screen analysis, use the `handle-comment` skill to post a c
122
122
 
123
123
  **Prefer MCP:**
124
124
  ```
125
- mcp__eventmodelers__add_lane { "boardId": "$BOARD_ID", "timelineId": "$CHAPTER_ID", "type": "actor", "label": "<Role Name>" }
125
+ mcp__eventmodelers__add_lane { "boardId": "$BOARD_ID", "timelineId": "$CHAPTER_ID", "lanes": [{ "type": "actor", "label": "<Role Name>" }] }
126
126
  ```
127
127
 
128
128
  **Fallback (no MCP):** see `references/api-fallback.md` — "Resolve One Actor Lane Per Human Role — Step 3: Create a new actor lane".
@@ -226,13 +226,15 @@ Every screen node requires rendered content. **HTML_SCREEN (via the `html-screen
226
226
  ```
227
227
  mcp__eventmodelers__create_screen {
228
228
  "boardId": "<BOARD_ID>",
229
- "contentType": "html",
230
- "nodeId": "<node-uuid>",
231
- "chapterId": "<CHAPTER_ID>",
232
- "cellId": "<actorRowId>-<columnId>",
233
- "pages": ["<div>...</div>"],
234
- "description": "<concise description of what this screen shows>",
235
- "fields": [ /* per "Mandatory Field Definitions" below — set in this same call */ ]
229
+ "screens": [{
230
+ "contentType": "html",
231
+ "nodeId": "<node-uuid>",
232
+ "chapterId": "<CHAPTER_ID>",
233
+ "cellId": "<actorRowId>-<columnId>",
234
+ "pages": ["<div>...</div>"],
235
+ "description": "<concise description of what this screen shows>",
236
+ "fields": [ /* per "Mandatory Field Definitions" below — set in this same call */ ]
237
+ }]
236
238
  }
237
239
  ```
238
240
 
@@ -240,7 +242,7 @@ mcp__eventmodelers__create_screen {
240
242
 
241
243
  The MCP `create_screen` call above already sets `meta.fields` (per "Mandatory Field Definitions" below) in the same call — no separate `node:changed` follow-up needed when using MCP.
242
244
 
243
- A storyboard screen is placed at a *provisional* position — Steps 4 and 5 wire it to its COMMAND / READMODEL once those exist, and may move it first. Pass `autoConnect: false` on `create_screen` / `create_screens` here so the placement doesn't pre-wire the screen to whatever happens to sit in the adjacent column; the real `SCREEN → COMMAND` and `READMODEL → SCREEN` edges are created deliberately in Steps 4 and 5. When creating several screens whose HTML is already authored, use `create_screens` (batch) with `autoConnect: false`.
245
+ A storyboard screen is placed at a *provisional* position — Steps 4 and 5 wire it to its COMMAND / READMODEL once those exist, and may move it first. Pass `autoConnect: false` on `create_screen` here so the placement doesn't pre-wire the screen to whatever happens to sit in the adjacent column; the real `SCREEN → COMMAND` and `READMODEL → SCREEN` edges are created deliberately in Steps 4 and 5. When creating several screens whose HTML is already authored, put them all in one `create_screen` call's `screens` array with `autoConnect: false`.
244
246
 
245
247
  Design the page(s) as real HTML/CSS, following the `html-screen` skill's guidance: write full-size markup (16px body text, generous padding — the canvas scales it down, don't shrink it yourself), one complete self-contained fragment per page (no `<html>`/`<head>`/`<body>` wrapper — the canvas adds those), no `<script>`/inline handlers (stripped server-side), and Bulma CSS classes (`title`, `button`, `is-primary`, `field`/`control`/`input`, etc. — remember heading size modifiers like `class="title is-1"`) since Bulma 0.9.4 is loaded by default. Every page MUST include real field labels matching the actual event/command fields this screen captures or displays, and at least one primary action (submit/confirm button) for command screens.
246
248
 
@@ -256,8 +258,6 @@ mcp__eventmodelers__submit_node_events {
256
258
  "id": "<event-uuid>",
257
259
  "eventType": "node:created",
258
260
  "nodeId": "<node-uuid>",
259
- "boardId": "<BOARD_ID>",
260
- "timestamp": 1234567890,
261
261
  "chapterId": "<CHAPTER_ID>",
262
262
  "cellId": "<actorRowId>-<columnId>",
263
263
  "meta": {"type": "SCREEN", "title": "<Screen Title>", "fields": [...]}
@@ -52,8 +52,6 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
52
52
  "id": "<event-uuid>",
53
53
  "eventType": "node:created",
54
54
  "nodeId": "<node-uuid>",
55
- "boardId": "<BOARD_ID>",
56
- "timestamp": 1234567890,
57
55
  "chapterId": "<CHAPTER_ID>",
58
56
  "cellId": "<actorRowId>-<columnId>",
59
57
  "meta": {"type": "SCREEN", "title": "<Screen Title>", "fields": [...]}
@@ -43,7 +43,7 @@ A run that opens each element with its own `get_node` to "read existing examples
43
43
 
44
44
  - `target` is a UUID → pass `nodeId`
45
45
  - `target` is a name → pass `name`
46
- - `target` is a cell name (e.g. `B3`) → pass `cellName` + `timelineId` (the chapter id — if multiple chapters exist on the board, resolve which one first using 2c-fallback's chapter lookup, or `mcp__eventmodelers__get_nodes { "boardId": "$BOARD_ID", "type": "CHAPTER" }`, and ask the user if ambiguous)
46
+ - `target` is a cell name (e.g. `B3`) → pass `cellName` + `timelineId` (the chapter id — if multiple chapters exist on the board, resolve which one first using 2c-fallback's chapter lookup, or `mcp__eventmodelers__get_nodes { "boardId": "$BOARD_ID", "type": "CHAPTER" }`, and ask the user if ambiguous). Only pass a cell name you were given or read back as a node's `cellName` (`get_board_outline`/`get_nodes`/`get_node` all report it) — if all you have is a node id or title, pass that instead rather than constructing an address.
47
47
 
48
48
  ```
49
49
  mcp__eventmodelers__add_field_examples { "boardId": "$BOARD_ID", "nodeId": "<target, if a UUID>" }
@@ -105,8 +105,6 @@ mcp__eventmodelers__submit_node_events {
105
105
  "id": "<uuid>",
106
106
  "eventType": "node:changed",
107
107
  "nodeId": "<TARGET_NODE.id>",
108
- "boardId": "$BOARD_ID",
109
- "timestamp": <epoch-ms>,
110
108
  "changedAttributes": ["meta.fields"],
111
109
  "meta": { "fields": "<updated-fields-array>" }
112
110
  }]
@@ -94,13 +94,11 @@ Build the payload with Python to avoid shell JSON-escaping issues, then POST it:
94
94
 
95
95
  ```bash
96
96
  python3 - <<EOF > /tmp/examples_payload.json
97
- import json, time, uuid
97
+ import json, uuid
98
98
  payload = [{
99
99
  "id": str(uuid.uuid4()),
100
100
  "eventType": "node:changed",
101
101
  "nodeId": "<TARGET_NODE.id>",
102
- "boardId": "<BOARD_ID>",
103
- "timestamp": int(time.time() * 1000),
104
102
  "changedAttributes": ["meta.fields"],
105
103
  "meta": {
106
104
  "fields": <updated-fields-array as Python list>
@@ -43,7 +43,7 @@ Route to the matching section below based on `action`.
43
43
  **Prefer MCP** — one call, `type` (`COMMENT`/`TASK`) passed straight through:
44
44
 
45
45
  ```
46
- mcp__eventmodelers__add_comment { "boardId": "$BOARD_ID", "nodeId": "$NODE_ID", "text": "<text>", "type": "<COMMENT|TASK>", "author": "<author>" }
46
+ mcp__eventmodelers__add_comment { "boardId": "$BOARD_ID", "comments": [{ "nodeId": "$NODE_ID", "text": "<text>", "type": "<COMMENT|TASK>", "author": "<author>" }] }
47
47
  ```
48
48
 
49
49
  **Fallback (no MCP):** see `references/api-fallback.md` — "Action: place".
@@ -58,7 +58,7 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/comments" \
58
58
  {"nodeId":"<id2>","text":"<text2>","type":"QUESTION","author":"wdyt"}]'
59
59
  ```
60
60
 
61
- Response: `201 {"results":[{"nodeId":"<id>","id":"<commentId>"}, …]}` in request order — an entry whose node doesn't exist reports `error` there without dropping the rest. Over MCP this is the `add_comments` tool.
61
+ Response: `201 {"results":[{"nodeId":"<id>","id":"<commentId>"}, …]}` in request order — an entry whose node doesn't exist reports `error` there without dropping the rest. Over MCP this is the `add_comment` tool's `comments` array.
62
62
 
63
63
  **Report:**
64
64
  ```
@@ -97,7 +97,6 @@ mcp__eventmodelers__submit_node_events {
97
97
  "boardId": "<BOARD_ID>",
98
98
  "events": [{
99
99
  "id": "<event-uuid>", "eventType": "node:changed", "nodeId": "<NODE_ID>",
100
- "boardId": "<BOARD_ID>", "timestamp": <NOW_MS>,
101
100
  "meta": {
102
101
  "type": "HTML_SCREEN",
103
102
  "title": "<Screen Title>",
@@ -136,12 +135,14 @@ mcp__eventmodelers__render_screen {
136
135
  ```
137
136
  mcp__eventmodelers__create_screen {
138
137
  "boardId": "<BOARD_ID>",
139
- "contentType": "html",
140
- "nodeId": "<generated-uuid>",
141
- "chapterId": "<CHAPTER_ID>",
142
- "cellName": "<CELL_NAME>",
143
- "pages": ["<div>...</div>"],
144
- "fields": [ /* optional — set meta.fields here too (see Step 5) instead of a separate call */ ]
138
+ "screens": [{
139
+ "contentType": "html",
140
+ "nodeId": "<generated-uuid>",
141
+ "chapterId": "<CHAPTER_ID>",
142
+ "cellName": "<CELL_NAME>",
143
+ "pages": ["<div>...</div>"],
144
+ "fields": [ /* optional — set meta.fields here too (see Step 5) instead of a separate call */ ]
145
+ }]
145
146
  }
146
147
  ```
147
148
 
@@ -174,7 +175,6 @@ mcp__eventmodelers__submit_node_events {
174
175
  "boardId": "<BOARD_ID>",
175
176
  "events": [{
176
177
  "id": "<event-uuid>", "eventType": "node:changed", "nodeId": "<NODE_ID>",
177
- "boardId": "<BOARD_ID>", "timestamp": <NOW_MS>,
178
178
  "changedAttributes": ["meta.fields"],
179
179
  "meta": { "type": "HTML_SCREEN", "fields": [
180
180
  {"name": "status", "type": "String", "example": "confirmed", "mapping": "ActiveReservationView.status", "cardinality": "Single"}
@@ -39,7 +39,6 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
39
39
  -H "Content-Type: application/json" \
40
40
  -d '[{
41
41
  "id": "<event-uuid>", "eventType": "node:changed", "nodeId": "<NODE_ID>",
42
- "boardId": "<BOARD_ID>", "timestamp": <NOW_MS>,
43
42
  "changedAttributes": ["meta.fields"],
44
43
  "meta": { "type": "HTML_SCREEN", "fields": [
45
44
  {"name": "status", "type": "String", "example": "confirmed", "mapping": "ActiveReservationView.status", "cardinality": "Single"}
@@ -44,14 +44,17 @@ Use `BOARD_ID` and `BASE_URL` from the `connect` skill. If a `boardId` argument
44
44
  mcp__eventmodelers__place_element {
45
45
  "boardId": "<BOARD_ID>",
46
46
  "timelineId": "<TIMELINE_ID>",
47
- "elementType": "<COMMAND|READMODEL|EVENT>",
48
- "title": "<title>",
49
- "columnIndex": <position, if given>,
50
- "fields": [{ "name": "orderId", "type": "String", "example": "ord-1" }]
47
+ "elements": [{
48
+ "elementType": "<COMMAND|READMODEL|EVENT>",
49
+ "title": "<title>",
50
+ "columnIndex": <position,
51
+ if given>,
52
+ "fields": [{ "name": "orderId", "type": "String", "example": "ord-1" }]
53
+ }]
51
54
  }
52
55
  ```
53
56
 
54
- Pass `fields` whenever the element's attributes are already known — they are written by this same call, so don't follow a placement with a `submit_node_events` just to set them. Placing **more than one** element is `place_elements` with an `elements` array (same per-entry options), applied in order so each entry sees the columns the previous one added — one call for a whole slice's or column run's worth instead of one per element.
57
+ Pass `fields` whenever the element's attributes are already known — they are written by this same call, so don't follow a placement with a `submit_node_events` just to set them. Placing **more than one** element is more entries in the same `elements` array, applied in order so each entry sees the columns the previous one added — one call for a whole slice's or column run's worth instead of one per element.
55
58
 
56
59
  This tool finds or creates an empty cell in the correct lane and places the node in one call — it collapses the "resolve timeline → fetch columns → determine lane → check occupancy → create node" sequence (Steps 2–3, 4, 6, 7b below) into a single round trip. A `columnIndex` past the timeline's current column count is handled automatically (columns are added to reach it) — no need to pre-check the column count or catch an out-of-range error yourself. If `timelineId` is unknown, resolve it first via Step 2's MCP call. Pass `compact: true` for a smaller `{nodeId, cellName, columnIndex}` response (plus `connectedCount` if auto-connect wired an edge) when you don't need the full `lane`/`elementType`/`title`/`autoConnected` detail back. Go straight to Step 8 once it returns.
57
60
 
@@ -274,13 +277,15 @@ mcp__eventmodelers__link_element { "boardId": "<BOARD_ID>", "nodeId": "<origin-n
274
277
  ```
275
278
  mcp__eventmodelers__create_screen {
276
279
  "boardId": "<BOARD_ID>",
277
- "contentType": "html",
278
- "nodeId": "<node-uuid>",
279
- "chapterId": "<TIMELINE_ID>",
280
- "cellId": "<CELL_ID>",
281
- "title": "<title>",
282
- "pages": ["<div>...</div>"],
283
- "description": "<title — what this screen shows>"
280
+ "screens": [{
281
+ "contentType": "html",
282
+ "nodeId": "<node-uuid>",
283
+ "chapterId": "<TIMELINE_ID>",
284
+ "cellId": "<CELL_ID>",
285
+ "title": "<title>",
286
+ "pages": ["<div>...</div>"],
287
+ "description": "<title — what this screen shows>"
288
+ }]
284
289
  }
285
290
  ```
286
291
 
@@ -293,13 +298,15 @@ mcp__eventmodelers__create_screen {
293
298
  ```
294
299
  mcp__eventmodelers__create_screen {
295
300
  "boardId": "<BOARD_ID>",
296
- "contentType": "sketch",
297
- "nodeId": "<node-uuid>",
298
- "chapterId": "<TIMELINE_ID>",
299
- "cellId": "<CELL_ID>",
300
- "title": "<title>",
301
- "elements": [...],
302
- "description": "<title — what this screen shows>"
301
+ "screens": [{
302
+ "contentType": "sketch",
303
+ "nodeId": "<node-uuid>",
304
+ "chapterId": "<TIMELINE_ID>",
305
+ "cellId": "<CELL_ID>",
306
+ "title": "<title>",
307
+ "elements": [...],
308
+ "description": "<title — what this screen shows>"
309
+ }]
303
310
  }
304
311
  ```
305
312
 
@@ -321,10 +328,9 @@ This step applies to `SCREEN` (view/output conflict case), `AUTOMATION`, `SCENAR
321
328
  mcp__eventmodelers__submit_node_events {
322
329
  "boardId": "<BOARD_ID>",
323
330
  "events": [{
331
+ "id": "<event-uuid>",
324
332
  "eventType": "node:created",
325
333
  "nodeId": "<node-uuid>",
326
- "boardId": "<BOARD_ID>",
327
- "timestamp": <Date.now()>,
328
334
  "chapterId": "<TIMELINE_ID>",
329
335
  "cellId": "<CELL_ID>",
330
336
  "meta": { "type": "<ELEMENT_TYPE>", "title": "<title>" },
@@ -343,10 +349,9 @@ mcp__eventmodelers__submit_node_events {
343
349
  mcp__eventmodelers__submit_node_events {
344
350
  "boardId": "<BOARD_ID>",
345
351
  "events": [{
352
+ "id": "<event-uuid>",
346
353
  "eventType": "node:created",
347
354
  "nodeId": "<node-uuid>",
348
- "boardId": "<BOARD_ID>",
349
- "timestamp": <Date.now()>,
350
355
  "chapterId": "<TIMELINE_ID>",
351
356
  "cellName": "<CELL_NAME>",
352
357
  "meta": { "type": "<ELEMENT_TYPE>", "title": "<title>" },
@@ -357,7 +362,7 @@ mcp__eventmodelers__submit_node_events {
357
362
 
358
363
  **Fallback (no MCP):** see `references/api-fallback.md` — "Step 7b — Create any other node type (fast path, `cellName`)".
359
364
 
360
- Response: `{ "hashes": { "<event-uuid>": "<hash>" } }`
365
+ Response: `{ "hashes": { "<event-id>": "<hash>" } }` — keyed by the `id` you sent on each event, which is how you match a hash back to the event that produced it.
361
366
 
362
367
  > **`node:created` with `cellId`/`cellName` IS the placement** — do NOT also call the `drop` endpoint afterwards. The `drop` endpoint adds a second cell reference without removing the first, causing the node to appear in two columns simultaneously. Use `node:created` with `cellId` or `cellName` for all initial placements.
363
368
 
@@ -380,7 +385,7 @@ Count inbound edges where `target === COMMAND_NODE_ID` and the source node is ty
380
385
  - **2 or more** → keep the edge whose source sits in the COMMAND's own column (the deliberate, same-slice issuer) and remove every other one:
381
386
 
382
387
  ```
383
- mcp__eventmodelers__set_connection { "boardId": "<BOARD_ID>", "source": "<extra-issuer-node-id>", "target": "<COMMAND_NODE_ID>", "action": "remove" }
388
+ mcp__eventmodelers__set_connection { "boardId": "<BOARD_ID>", "connections": [{ "source": "<extra-issuer-node-id>", "target": "<COMMAND_NODE_ID>", "action": "remove" }] }
384
389
  ```
385
390
 
386
391
  If it's not clear which edge is the deliberate one (e.g. neither source sits in the COMMAND's own column), do not guess — leave both edges and post a comment on the COMMAND node via `handle-comment` instead, describing the ambiguity.
@@ -411,4 +416,4 @@ Timeline: <timelineId>
411
416
 
412
417
  ## Example — place an EVENT via curl
413
418
 
414
- A full worked example (add column → fetch chapter → create node) placing an EVENT called "Order Placed" at the end of a timeline lives in `references/api-fallback.md`'s "Full worked example" section. With MCP connected, the same result is one call: `mcp__eventmodelers__place_element { "boardId": "<BOARD_ID>", "timelineId": "<TIMELINE_ID>", "elementType": "EVENT", "title": "Order Placed" }` (see "Prefer MCP" above).
419
+ A full worked example (add column → fetch chapter → create node) placing an EVENT called "Order Placed" at the end of a timeline lives in `references/api-fallback.md`'s "Full worked example" section. With MCP connected, the same result is one call: `mcp__eventmodelers__place_element { "boardId": "<BOARD_ID>", "timelineId": "<TIMELINE_ID>", "elements": [{ "elementType": "EVENT", "title": "Order Placed" }] }` (see "Prefer MCP" above).
@@ -124,10 +124,9 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
124
124
  -H "x-user-id: agent" \
125
125
  -H "Content-Type: application/json" \
126
126
  -d '[{
127
+ "id": "<event-uuid>",
127
128
  "eventType": "node:created",
128
129
  "nodeId": "<node-uuid>",
129
- "boardId": "<BOARD_ID>",
130
- "timestamp": <Date.now()>,
131
130
  "chapterId": "<TIMELINE_ID>",
132
131
  "cellId": "<CELL_ID>",
133
132
  "meta": {
@@ -148,10 +147,9 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
148
147
  -H "x-user-id: agent" \
149
148
  -H "Content-Type: application/json" \
150
149
  -d '[{
150
+ "id": "<event-uuid>",
151
151
  "eventType": "node:created",
152
152
  "nodeId": "<node-uuid>",
153
- "boardId": "<BOARD_ID>",
154
- "timestamp": <Date.now()>,
155
153
  "chapterId": "<TIMELINE_ID>",
156
154
  "cellName": "<CELL_NAME>",
157
155
  "meta": {
@@ -162,11 +160,11 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
162
160
  }]'
163
161
  ```
164
162
 
165
- Response: `{ "hashes": { "<event-uuid>": "<hash>" } }`
163
+ Response: `{ "hashes": { "<event-id>": "<hash>" } }` — keyed by the `id` you sent on each event, which is how you match a hash back to the event that produced it.
166
164
 
167
165
  ## Full worked example — place an EVENT via curl, start to finish
168
166
 
169
- With MCP connected, the same result is one call: `mcp__eventmodelers__place_element { "boardId": "<BOARD_ID>", "timelineId": "<TIMELINE_ID>", "elementType": "EVENT", "title": "Order Placed" }`.
167
+ With MCP connected, the same result is one call: `mcp__eventmodelers__place_element { "boardId": "<BOARD_ID>", "timelineId": "<TIMELINE_ID>", "elements": [{ "elementType": "EVENT", "title": "Order Placed" }] }`.
170
168
 
171
169
  Placing an EVENT called "Order Placed" at the end of a timeline, over curl:
172
170
 
@@ -188,8 +186,6 @@ curl -s -X POST "http://localhost:3000/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/
188
186
  "id": "<event-uuid>",
189
187
  "eventType": "node:created",
190
188
  "nodeId": "<node-uuid>",
191
- "boardId": "<BOARD_ID>",
192
- "timestamp": 1714900000000,
193
189
  "chapterId": "<TIMELINE_ID>",
194
190
  "cellId": "<CELL_ID>",
195
191
  "meta": { "type": "EVENT", "title": "Order Placed" },
@@ -197,4 +193,4 @@ curl -s -X POST "http://localhost:3000/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/
197
193
  }]'
198
194
  ```
199
195
 
200
- Replace `<TIMELINE_ID>`, `<BOARD_ID>`, `<CELL_ID>`, `<event-uuid>`, and `<node-uuid>` with real UUIDs. Use `Date.now()` or a current unix-ms timestamp for `timestamp`.
196
+ Replace `<TIMELINE_ID>`, `<BOARD_ID>`, `<CELL_ID>`, `<event-uuid>` and `<node-uuid>` with real values you mint two uuids here: the node's and the event's own `id`, which is required. `boardId`/`timestamp` are omitted on purpose: the server derives both from the request and ignores them if sent.
@@ -179,13 +179,15 @@ Build the payload, then send a single call that creates the screen node, places
179
179
  ```
180
180
  mcp__eventmodelers__create_screen {
181
181
  "boardId": "<BOARD_ID>",
182
- "contentType": "html",
183
- "nodeId": "<SCREEN_NODE_ID>",
184
- "chapterId": "<CHAPTER_ID>",
185
- "cellId": "<actorCellId>",
186
- "title": "<screenTitle>",
187
- "pages": ["<div>...</div>"],
188
- "description": "<screenTitle — what this screen shows>"
182
+ "screens": [{
183
+ "contentType": "html",
184
+ "nodeId": "<SCREEN_NODE_ID>",
185
+ "chapterId": "<CHAPTER_ID>",
186
+ "cellId": "<actorCellId>",
187
+ "title": "<screenTitle>",
188
+ "pages": ["<div>...</div>"],
189
+ "description": "<screenTitle — what this screen shows>"
190
+ }]
189
191
  }
190
192
  ```
191
193
 
@@ -198,13 +200,15 @@ mcp__eventmodelers__create_screen {
198
200
  ```
199
201
  mcp__eventmodelers__create_screen {
200
202
  "boardId": "<BOARD_ID>",
201
- "contentType": "sketch",
202
- "nodeId": "<SCREEN_NODE_ID>",
203
- "chapterId": "<CHAPTER_ID>",
204
- "cellId": "<actorCellId>",
205
- "title": "<screenTitle>",
206
- "elements": [...],
207
- "description": "<screenTitle — what this screen shows>"
203
+ "screens": [{
204
+ "contentType": "sketch",
205
+ "nodeId": "<SCREEN_NODE_ID>",
206
+ "chapterId": "<CHAPTER_ID>",
207
+ "cellId": "<actorCellId>",
208
+ "title": "<screenTitle>",
209
+ "elements": [...],
210
+ "description": "<screenTitle — what this screen shows>"
211
+ }]
208
212
  }
209
213
  ```
210
214
 
@@ -224,7 +228,6 @@ mcp__eventmodelers__submit_node_events {
224
228
  "boardId": "<BOARD_ID>",
225
229
  "events": [{
226
230
  "id": "<event-uuid>", "eventType": "node:changed", "nodeId": "<SCREEN_NODE_ID>",
227
- "boardId": "<BOARD_ID>", "timestamp": <NOW_MS>,
228
231
  "changedAttributes": ["meta.fields"],
229
232
  "meta": { "type": "HTML_SCREEN", "fields": [ /* planned fields */ ] }
230
233
  }]
@@ -67,7 +67,6 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
67
67
  -H "Content-Type: application/json" \
68
68
  -d '[{
69
69
  "id": "<event-uuid>", "eventType": "node:changed", "nodeId": "<SCREEN_NODE_ID>",
70
- "boardId": "<BOARD_ID>", "timestamp": <NOW_MS>,
71
70
  "changedAttributes": ["meta.fields"],
72
71
  "meta": { "type": "HTML_SCREEN", "fields": [ /* planned fields */ ] }
73
72
  }]'
@@ -122,7 +122,6 @@ mcp__eventmodelers__submit_node_events {
122
122
  "boardId": "<BOARD_ID>",
123
123
  "events": [{
124
124
  "id": "<event-uuid>", "eventType": "node:changed", "nodeId": "<NODE_ID>",
125
- "boardId": "<BOARD_ID>", "timestamp": <NOW_MS>,
126
125
  "changedAttributes": ["meta.fields"],
127
126
  "meta": { "type": "SCREEN", "fields": [
128
127
  {"name": "status", "type": "String", "example": "confirmed", "mapping": "ActiveReservationView.status", "cardinality": "Single"}
@@ -33,7 +33,6 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
33
33
  -H "Content-Type: application/json" \
34
34
  -d '[{
35
35
  "id": "<event-uuid>", "eventType": "node:changed", "nodeId": "<NODE_ID>",
36
- "boardId": "<BOARD_ID>", "timestamp": <NOW_MS>,
37
36
  "changedAttributes": ["meta.fields"],
38
37
  "meta": { "type": "SCREEN", "fields": [
39
38
  {"name": "status", "type": "String", "example": "confirmed", "mapping": "ActiveReservationView.status", "cardinality": "Single"}
@@ -191,7 +191,7 @@ emptyColumns = [columnId, ...] // in column order, ready to reuse
191
191
 
192
192
  **Prefer MCP:**
193
193
  ```
194
- mcp__eventmodelers__delete_column { "boardId": "<BOARD_ID>", "timelineId": "<CHAPTER_ID>", "columnId": "<columnId>" }
194
+ mcp__eventmodelers__delete_column { "boardId": "<BOARD_ID>", "timelineId": "<CHAPTER_ID>", "columnIds": ["<columnId>"] }
195
195
  ```
196
196
 
197
197
  **Fallback (no MCP):** see `references/api-fallback.md` — "Delete a column".
@@ -246,8 +246,6 @@ mcp__eventmodelers__submit_node_events {
246
246
  "id": "<event-uuid>",
247
247
  "eventType": "node:created",
248
248
  "nodeId": "<node-uuid>",
249
- "boardId": "<BOARD_ID>",
250
- "timestamp": <Date.now()>,
251
249
  "chapterId": "<CHAPTER_ID>",
252
250
  "cellId": "<CELL_ID>",
253
251
  "meta": { "type": "EVENT", "title": "<EventName>" },
@@ -262,7 +260,7 @@ mcp__eventmodelers__submit_node_events {
262
260
 
263
261
  **Prefer MCP:** this whole "find/create a column, compute the cell, place the node" sequence collapses into one call:
264
262
  ```
265
- mcp__eventmodelers__place_element { "boardId": "<BOARD_ID>", "timelineId": "<CHAPTER_ID>", "elementType": "EVENT", "title": "<EventName>", "columnIndex": <index> }
263
+ mcp__eventmodelers__place_element { "boardId": "<BOARD_ID>", "timelineId": "<CHAPTER_ID>", "elements": [{ "elementType": "EVENT", "title": "<EventName>", "columnIndex": <index> }] }
266
264
  ```
267
265
  Extract `nodeId` and `columnId` directly from the tool result.
268
266
 
@@ -302,8 +300,6 @@ mcp__eventmodelers__submit_node_events {
302
300
  "id": "<new-uuid>",
303
301
  "eventType": "node:changed",
304
302
  "nodeId": "<eventNodeId>",
305
- "boardId": "<BOARD_ID>",
306
- "timestamp": <Date.now()>,
307
303
  "changedAttributes": ["meta.title"],
308
304
  "meta": { "type": "EVENT", "title": "<NewTitle>" },
309
305
  "node": { "id": "<eventNodeId>", "data": {} }
@@ -323,7 +319,7 @@ Two steps — delete the node, then delete the column:
323
319
 
324
320
  **Prefer MCP:**
325
321
  ```
326
- mcp__eventmodelers__delete_node { "boardId": "<BOARD_ID>", "nodeId": "<eventNodeId>" }
322
+ mcp__eventmodelers__delete_node { "boardId": "<BOARD_ID>", "nodeIds": ["<eventNodeId>"] }
327
323
  ```
328
324
 
329
325
  **Fallback (no MCP):** see `references/api-fallback.md` — "Delete an event node".
@@ -332,7 +328,7 @@ mcp__eventmodelers__delete_node { "boardId": "<BOARD_ID>", "nodeId": "<eventNode
332
328
 
333
329
  **Prefer MCP:**
334
330
  ```
335
- mcp__eventmodelers__delete_column { "boardId": "<BOARD_ID>", "timelineId": "<CHAPTER_ID>", "columnId": "<columnId>" }
331
+ mcp__eventmodelers__delete_column { "boardId": "<BOARD_ID>", "timelineId": "<CHAPTER_ID>", "columnIds": ["<columnId>"] }
336
332
  ```
337
333
 
338
334
  **Fallback (no MCP):** see `references/api-fallback.md` — "Delete a column".