@eventmodelers/cli 1.0.36 → 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 (71) hide show
  1. package/package.json +1 -1
  2. package/shared/skills/learn-eventmodelers-api/SKILL.md +22 -13
  3. package/stacks/modeling-kit/templates/.claude/skills/add-next-slice/SKILL.md +2 -23
  4. package/stacks/modeling-kit/templates/.claude/skills/add-next-slice/references/api-fallback.md +11 -0
  5. package/stacks/modeling-kit/templates/.claude/skills/analyze-existing-model/SKILL.md +6 -57
  6. package/stacks/modeling-kit/templates/.claude/skills/analyze-existing-model/references/api-fallback.md +68 -0
  7. package/stacks/modeling-kit/templates/.claude/skills/attributes/SKILL.md +4 -61
  8. package/stacks/modeling-kit/templates/.claude/skills/attributes/references/api-fallback.md +39 -0
  9. package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/SKILL.md +9 -53
  10. package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/references/api-fallback.md +63 -0
  11. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-applying-conways-law/SKILL.md +12 -380
  12. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-applying-conways-law/references/examples.md +329 -0
  13. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/SKILL.md +45 -290
  14. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/references/api-fallback.md +97 -0
  15. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/references/examples.md +35 -0
  16. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/SKILL.md +15 -410
  17. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/references/api-fallback.md +22 -0
  18. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/references/examples.md +397 -0
  19. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-core-rules/SKILL.md +182 -0
  20. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-automation-chains/SKILL.md +148 -0
  21. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-automation-chains/references/api-fallback.md +21 -0
  22. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/SKILL.md +48 -448
  23. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/references/examples.md +167 -0
  24. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/SKILL.md +31 -380
  25. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/references/api-fallback.md +31 -0
  26. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/references/examples.md +216 -0
  27. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/SKILL.md +33 -393
  28. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/references/api-fallback.md +79 -0
  29. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/references/examples.md +282 -0
  30. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/SKILL.md +54 -454
  31. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/references/api-fallback.md +67 -0
  32. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/references/examples.md +273 -0
  33. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-interview-protocol/SKILL.md +31 -0
  34. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/SKILL.md +37 -184
  35. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/domain-patterns.md +58 -99
  36. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/patterns.md +82 -163
  37. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/SKILL.md +86 -78
  38. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/references/api-fallback.md +51 -0
  39. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-plotting-events/SKILL.md +5 -5
  40. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-plotting-events/references/api-fallback.md +10 -0
  41. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/SKILL.md +22 -51
  42. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/api-fallback.md +41 -0
  43. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/examples.md +12 -9
  44. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/patterns.md +1 -10
  45. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/SKILL.md +29 -382
  46. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/references/api-fallback.md +77 -0
  47. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/references/examples.md +271 -0
  48. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-translating-external-events/SKILL.md +12 -349
  49. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-translating-external-events/references/examples.md +306 -0
  50. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models/SKILL.md +69 -107
  51. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models/references/api-fallback.md +14 -0
  52. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models-checklist/SKILL.md +75 -160
  53. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models-checklist/references/api-fallback.md +14 -0
  54. package/stacks/modeling-kit/templates/.claude/skills/examples/SKILL.md +3 -110
  55. package/stacks/modeling-kit/templates/.claude/skills/examples/references/api-fallback.md +118 -0
  56. package/stacks/modeling-kit/templates/.claude/skills/handle-comment/SKILL.md +5 -25
  57. package/stacks/modeling-kit/templates/.claude/skills/handle-comment/references/api-fallback.md +35 -0
  58. package/stacks/modeling-kit/templates/.claude/skills/html-screen/SKILL.md +9 -44
  59. package/stacks/modeling-kit/templates/.claude/skills/html-screen/references/api-fallback.md +51 -0
  60. package/stacks/modeling-kit/templates/.claude/skills/place-element/SKILL.md +34 -180
  61. package/stacks/modeling-kit/templates/.claude/skills/place-element/references/api-fallback.md +203 -0
  62. package/stacks/modeling-kit/templates/.claude/skills/storyboard/SKILL.md +14 -81
  63. package/stacks/modeling-kit/templates/.claude/skills/storyboard/references/api-fallback.md +74 -0
  64. package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/SKILL.md +4 -45
  65. package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/references/api-fallback.md +44 -0
  66. package/stacks/modeling-kit/templates/.claude/skills/timeline/SKILL.md +19 -88
  67. package/stacks/modeling-kit/templates/.claude/skills/timeline/references/api-fallback.md +91 -0
  68. package/stacks/modeling-kit/templates/.claude/skills/update-prompt-status/SKILL.md +1 -9
  69. package/stacks/modeling-kit/templates/.claude/skills/update-prompt-status/references/api-fallback.md +14 -0
  70. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-integrating-legacy-systems/SKILL.md +0 -674
  71. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/snapshotting.md +0 -204
@@ -7,7 +7,7 @@ description: Place a COMMAND, READMODEL, EVENT, SCREEN, AUTOMATION, or SCENARIO
7
7
 
8
8
  > **Before doing anything else**, invoke the `connect` skill — if not already connected — to resolve `TOKEN`, `BOARD_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.
9
9
 
10
- Prefer `mcp__eventmodelers__*` tools when available (registered by the `connect` skill) — the curl blocks below are the fallback for sessions without MCP connected.
10
+ Prefer `mcp__eventmodelers__*` tools when available (registered by the `connect` skill) — `references/api-fallback.md` has the curl fallback for every MCP call below, for sessions without MCP connected.
11
11
 
12
12
  Place a single element — COMMAND, READMODEL, EVENT, SCREEN, AUTOMATION, or SCENARIO spec node — onto an existing timeline on an eventmodelers board. Uses an existing column when a position is given; only creates a new column when appending.
13
13
  ---
@@ -50,7 +50,7 @@ mcp__eventmodelers__place_element {
50
50
  }
51
51
  ```
52
52
 
53
- 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. If `timelineId` is unknown, resolve it first via Step 2's MCP call. Go straight to Step 8 once it returns.
53
+ 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.
54
54
 
55
55
  **This does not cover**: `SCREEN`/`AUTOMATION`/`SCENARIO` (see their dedicated steps below), the `"after <title>"` position form, or an explicit `cellName` fast path (Step 1) — `place_element` has no way to express either. For those cases, or when MCP isn't connected, fall through to the manual steps below.
56
56
 
@@ -64,13 +64,7 @@ This tool finds or creates an empty cell in the correct lane and places the node
64
64
  mcp__eventmodelers__get_nodes { "boardId": "<BOARD_ID>", "type": "CHAPTER" }
65
65
  ```
66
66
 
67
- **Fallback (no MCP):**
68
-
69
- If `timelineId` is not provided, discover chapters on the board:
70
-
71
- ```bash
72
- curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?type=CHAPTER"
73
- ```
67
+ **Fallback (no MCP):** see `references/api-fallback.md` — "Step 2 — Discover chapters". If `timelineId` is not provided, this discovers chapters on the board.
74
68
 
75
69
  - **Exactly one chapter** → use it automatically, tell the user which one was selected.
76
70
  - **Multiple chapters** → list them by name/ID and ask the user which to target.
@@ -80,21 +74,17 @@ curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?type=CHAPTER"
80
74
 
81
75
  ## Step 3 — Fetch existing columns and resolve position
82
76
 
83
- Always fetch the chapter node first to get the current timeline state.
77
+ Always fetch the chapter node first to get the current timeline state — `projection: "cells"` returns just `{rows, columns, cells}`, not the whole chapter node.
84
78
 
85
79
  **Prefer MCP:**
86
80
 
87
81
  ```
88
- mcp__eventmodelers__get_node { "boardId": "<BOARD_ID>", "nodeId": "<TIMELINE_ID>" }
82
+ mcp__eventmodelers__get_node { "boardId": "<BOARD_ID>", "nodeId": "<TIMELINE_ID>", "projection": "cells" }
89
83
  ```
90
84
 
91
- **Fallback (no MCP):**
85
+ **Fallback (no MCP):** see `references/api-fallback.md` — "Step 3 — Fetch the chapter node".
92
86
 
93
- ```bash
94
- curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/$TIMELINE_ID"
95
- ```
96
-
97
- From `meta.timelineData`, read `columns` (ordered array of column objects with `id` and `index`) and `cells`.
87
+ Read `columns` (ordered array of column objects with `id` and `index`) and `cells` (from the result directly via MCP, or from `meta.timelineData` via the REST fallback).
98
88
 
99
89
  Then resolve `position`:
100
90
 
@@ -142,31 +132,7 @@ mcp__eventmodelers__add_scenario {
142
132
 
143
133
  Same rules apply (given=EVENTs only, when=at most one COMMAND or QUERY, then=EVENTs only or exactly one READMODEL, `expectError`+`errorDescription` for error cases). This auto-creates the spec node if the cell is empty, same as the curl endpoint.
144
134
 
145
- **Fallback (no MCP):**
146
-
147
- ```bash
148
- curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$TL/columns/$COL/scenarios" \
149
- -H "x-token: $TOKEN" -H "Content-Type: application/json" \
150
- -d '[
151
- {
152
- "id": "<scenario-uuid>",
153
- "title": "Happy path",
154
- "given": [{"id":"<eventNodeId>","title":"OrderPlaced","type":"EVENT"}],
155
- "when": [{"id":"<commandNodeId>","title":"PlaceOrder","type":"COMMAND"}],
156
- "then": [{"id":"<eventNodeId2>","title":"OrderConfirmed","type":"EVENT"}]
157
- },
158
- {
159
- "id": "<scenario-uuid>",
160
- "title": "Insufficient stock",
161
- "given": [{"id":"<eventNodeId>","title":"OrderPlaced","type":"EVENT"}],
162
- "when": [{"id":"<commandNodeId>","title":"PlaceOrder","type":"COMMAND"}],
163
- "then": [],
164
- "expectError": true,
165
- "errorDescription": "Stock below requested quantity"
166
- }
167
- ]'
168
- # → 201 { specNodeId, scenarios (all), added (count), isNewNode }
169
- ```
135
+ **Fallback (no MCP):** see `references/api-fallback.md` — "Step 4a — SCENARIO: append scenarios via the spec endpoint" for the full curl call and example payload.
170
136
 
171
137
  **Scenario object shapes:**
172
138
 
@@ -211,18 +177,7 @@ Only run this when position was omitted (append mode).
211
177
  mcp__eventmodelers__add_column { "boardId": "<BOARD_ID>", "timelineId": "<TIMELINE_ID>" }
212
178
  ```
213
179
 
214
- **Fallback (no MCP):**
215
-
216
- ```bash
217
- curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$TIMELINE_ID/columns" \
218
- -H "x-token: $TOKEN" \
219
- -H "x-board-id: $BOARD_ID" \
220
- -H "x-user-id: agent" \
221
- -H "Content-Type: application/json" \
222
- -d '{}'
223
- ```
224
-
225
- Response: `{ "columnId": "<uuid>", "index": <n>, "totalColumns": <n> }`
180
+ **Fallback (no MCP):** see `references/api-fallback.md` — "Step 5 — Create a column when appending".
226
181
 
227
182
  Save `columnId` from the response.
228
183
 
@@ -241,42 +196,45 @@ Cell IDs are always `<rowId>-<columnId>` — no cell array search needed.
241
196
 
242
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.
243
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
+
244
201
  **Check if the cell is already occupied.**
245
202
 
246
- **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):
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.
247
204
 
248
- **Fallback (no MCP):**
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`:
249
206
 
250
207
  ```bash
251
- curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?cellId=$CELL_ID"
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"
252
213
  ```
253
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.
216
+
217
+ **Fallback (no MCP):** see `references/api-fallback.md` — "Step 6 — Check cell occupancy".
218
+
254
219
  **If the cell is occupied**, the behaviour depends on the element type being placed:
255
220
 
256
221
  | Element type | Occupant type in same cell | Action |
257
222
  |---|---|---|
258
- | `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. |
259
- | `SCREEN` (view/output screen) | any | Same as READMODEL insert immediately after. |
223
+ | `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. This row covers positioning the read model relative to its **source EVENT's** column. If instead you're placing the read model to share a column with an **already-placed view SCREEN** it feeds (`eventmodeling-identifying-outputs`'s Step 5g scenario) and that column is unavailable, do the opposite: insert the new column immediately **before** the screen — the screen's own position must never move to resolve this. |
224
+ | `SCREEN` (view/output screen) | any | Insert immediately after (this is placing a brand-new screen, not repositioning one relative to an existing read model). |
260
225
  | `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. |
261
226
  | Any | Same element type | Stop and tell the user — true conflict, no safe default. |
262
227
  | Any | Different type but not a known pairing | Stop and tell the user. |
263
228
 
264
- **Insert immediately after** means: create the new column with `index = currentColumnIndex + 1`, not by appending to the end. This keeps the read model visually adjacent to the event that drives it.
229
+ **Insert immediately after** means: create the new column right after the current one, not by appending to the end. This keeps the read model visually adjacent to the event that drives it.
265
230
 
266
- **Prefer MCP:**
231
+ **Prefer MCP** — pass `afterNodeId` set to the occupying node's id (found in Step 6's cell-occupancy check) and let the tool resolve the index itself, instead of computing `currentColumnIndex + 1` by hand:
267
232
 
268
233
  ```
269
- mcp__eventmodelers__add_column { "boardId": "<BOARD_ID>", "timelineId": "<TIMELINE_ID>", "index": <currentColumnIndex + 1> }
234
+ mcp__eventmodelers__add_column { "boardId": "<BOARD_ID>", "timelineId": "<TIMELINE_ID>", "afterNodeId": "<occupyingNodeId>" }
270
235
  ```
271
236
 
272
- **Fallback (no MCP):**
273
-
274
- ```bash
275
- curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$TIMELINE_ID/columns" \
276
- -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: agent" \
277
- -H "Content-Type: application/json" \
278
- -d '{"index": <currentColumnIndex + 1>}'
279
- ```
237
+ **Fallback (no MCP):** see `references/api-fallback.md` — "Step 6 — Insert a column at a specific index" (no relative-insertion equivalent over REST; the index is computed by hand).
280
238
 
281
239
  If no matching row is found, stop and report the error — the timeline may be missing the required lane type.
282
240
 
@@ -292,7 +250,7 @@ Instead, create a **linked copy**: place the new node normally (Step 7, same tit
292
250
  mcp__eventmodelers__link_element { "boardId": "<BOARD_ID>", "nodeId": "<origin-node-id>", "targetNodeId": "<newly-placed-node-id>" }
293
251
  ```
294
252
 
295
- (REST fallback: `POST .../nodes/:nodeId/link` with `{ "targetNodeId": "<newly-placed-node-id>" }` see `learn-eventmodelers-api` §3.) This replaces the new node's meta with a full copy of the origin's, sets `meta.linkedTo`, and only works for COMMAND/EVENT/READMODEL. Once linked, wire the local copy to its neighbors with normal same-timeline `set_connection`/auto-connect calls. `eventmodeling-checking-completeness` treats any `linkedTo`-marked node it finds as this intentional pattern, never a duplicate to flag.
253
+ (REST fallback: see `references/api-fallback.md` "Step 6a — Link a node to an origin on a different timeline".) This replaces the new node's meta with a full copy of the origin's, sets `meta.linkedTo`, and only works for COMMAND/EVENT/READMODEL. Once linked, wire the local copy to its neighbors with normal same-timeline `set_connection`/auto-connect calls. `eventmodeling-checking-completeness` treats any `linkedTo`-marked node it finds as this intentional pattern, never a duplicate to flag.
296
254
 
297
255
  ---
298
256
 
@@ -318,20 +276,7 @@ mcp__eventmodelers__create_screen {
318
276
  }
319
277
  ```
320
278
 
321
- **Fallback (no MCP):**
322
-
323
- ```bash
324
- curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/html-screen-nodes/<node-uuid>" \
325
- -H "x-token: $TOKEN" \
326
- -H "x-board-id: $BOARD_ID" \
327
- -H "x-user-id: agent" \
328
- -H "Content-Type: application/json" \
329
- -d '{
330
- "chapterId": "<TIMELINE_ID>",
331
- "cellId": "<CELL_ID>",
332
- "pages": ["<div>...</div>"]
333
- }'
334
- ```
279
+ **Fallback (no MCP):** see `references/api-fallback.md` — "Step 7a — SCREEN: create and render (HTML path)".
335
280
 
336
281
  **Sketch path (explicit request only) — `contentType: "sketch"`, plain SCREEN node:** only use this when the user explicitly asked for a "sketch"/"wireframe"/"low-fidelity mockup". Design the sketch elements first (same grid language as `storyboard-screen`):
337
282
 
@@ -349,21 +294,7 @@ mcp__eventmodelers__create_screen {
349
294
  }
350
295
  ```
351
296
 
352
- **Fallback (no MCP):**
353
-
354
- ```bash
355
- curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/image-nodes/<node-uuid>/sketch" \
356
- -H "x-token: $TOKEN" \
357
- -H "x-board-id: $BOARD_ID" \
358
- -H "x-user-id: agent" \
359
- -H "Content-Type: application/json" \
360
- -d '{
361
- "chapterId": "<TIMELINE_ID>",
362
- "cellId": "<CELL_ID>",
363
- "description": {"elements": [...]},
364
- "semanticDescription": "<title — what this screen shows>"
365
- }'
366
- ```
297
+ **Fallback (no MCP):** see `references/api-fallback.md` — "Step 7a — SCREEN: create and render (sketch path, explicit request only)".
367
298
 
368
299
  Pass whichever cell reference you already resolved — `CELL_ID` from Step 6, or `CELL_NAME` from Step 1's fast path (either path accepts `cellId` or `cellName`). Expect success (MCP: `created: true`; curl: `204`). On failure, read the validation error, fix the payload, and retry once. Then skip the rest of Step 7 and go to Step 8.
369
300
 
@@ -393,28 +324,7 @@ mcp__eventmodelers__submit_node_events {
393
324
  }
394
325
  ```
395
326
 
396
- **Fallback (no MCP):**
397
-
398
- ```bash
399
- curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
400
- -H "x-token: $TOKEN" \
401
- -H "x-board-id: $BOARD_ID" \
402
- -H "x-user-id: agent" \
403
- -H "Content-Type: application/json" \
404
- -d '[{
405
- "eventType": "node:created",
406
- "nodeId": "<node-uuid>",
407
- "boardId": "<BOARD_ID>",
408
- "timestamp": <Date.now()>,
409
- "chapterId": "<TIMELINE_ID>",
410
- "cellId": "<CELL_ID>",
411
- "meta": {
412
- "type": "<ELEMENT_TYPE>",
413
- "title": "<title>"
414
- },
415
- "node": { "data": { "title": "<title>" } }
416
- }]'
417
- ```
327
+ **Fallback (no MCP):** see `references/api-fallback.md` — "Step 7b — Create any other node type (normal path, `cellId`)".
418
328
 
419
329
  **Fast path** (`cellName` given directly, e.g. `"A2"` — see the Step 1 shortcut) — pass `cellName` instead of `cellId` and let the backend resolve it; nothing else in the payload changes:
420
330
 
@@ -436,28 +346,7 @@ mcp__eventmodelers__submit_node_events {
436
346
  }
437
347
  ```
438
348
 
439
- **Fallback (no MCP):**
440
-
441
- ```bash
442
- curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
443
- -H "x-token: $TOKEN" \
444
- -H "x-board-id: $BOARD_ID" \
445
- -H "x-user-id: agent" \
446
- -H "Content-Type: application/json" \
447
- -d '[{
448
- "eventType": "node:created",
449
- "nodeId": "<node-uuid>",
450
- "boardId": "<BOARD_ID>",
451
- "timestamp": <Date.now()>,
452
- "chapterId": "<TIMELINE_ID>",
453
- "cellName": "<CELL_NAME>",
454
- "meta": {
455
- "type": "<ELEMENT_TYPE>",
456
- "title": "<title>"
457
- },
458
- "node": { "data": { "title": "<title>" } }
459
- }]'
460
- ```
349
+ **Fallback (no MCP):** see `references/api-fallback.md` — "Step 7b — Create any other node type (fast path, `cellName`)".
461
350
 
462
351
  Response: `{ "hashes": { "<event-uuid>": "<hash>" } }`
463
352
 
@@ -513,39 +402,4 @@ Timeline: <timelineId>
513
402
 
514
403
  ## Example — place an EVENT via curl
515
404
 
516
- **This whole example is the curl fallback.** 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).
517
-
518
- Full working example placing an EVENT called "Order Placed" at the end of a timeline:
519
-
520
- ```bash
521
- # 1. Add a column (append at end)
522
- curl -s -X POST "http://localhost:3000/api/org/<ORG_ID>/boards/<BOARD_ID>/timelines/<TIMELINE_ID>/columns" \
523
- -H "Content-Type: application/json" \
524
- -d '{}'
525
-
526
- # 2. Fetch chapter to find the target lane cell for the new column
527
- curl -s -H "x-user-id: place-element-skill" \
528
- "http://localhost:3000/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/<TIMELINE_ID>"
529
-
530
- # 3. Create the EVENT node
531
-
532
- Do not skip the User-ID.
533
-
534
-
535
- curl -s -X POST "http://localhost:3000/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/events" \
536
- -H "Content-Type: application/json" \
537
- -H "x-user-id: place-element-skill" \
538
- -d '[{
539
- "id": "<event-uuid>",
540
- "eventType": "node:created",
541
- "nodeId": "<node-uuid>",
542
- "boardId": "<BOARD_ID>",
543
- "timestamp": 1714900000000,
544
- "chapterId": "<TIMELINE_ID>",
545
- "cellId": "<CELL_ID>",
546
- "meta": { "type": "EVENT", "title": "Order Placed" },
547
- "node": { "id": "<node-uuid>", "data": { "title": "Order Placed" } }
548
- }]'
549
- ```
550
-
551
- 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`.
405
+ 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).
@@ -0,0 +1,203 @@
1
+ # Place Element — curl Fallback Calls
2
+
3
+ Only needed when MCP is not connected. Every call below has an MCP equivalent in the main SKILL.md — always prefer that.
4
+
5
+ ## Step 2 — Discover chapters
6
+
7
+ ```bash
8
+ curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?type=CHAPTER"
9
+ ```
10
+
11
+ ## Step 3 — Fetch the chapter node (columns + cells)
12
+
13
+ ```bash
14
+ curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/$TIMELINE_ID"
15
+ ```
16
+
17
+ ## Step 4a — SCENARIO: append scenarios via the spec endpoint
18
+
19
+ ```bash
20
+ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$TL/columns/$COL/scenarios" \
21
+ -H "x-token: $TOKEN" -H "Content-Type: application/json" \
22
+ -d '[
23
+ {
24
+ "id": "<scenario-uuid>",
25
+ "title": "Happy path",
26
+ "given": [{"id":"<eventNodeId>","title":"OrderPlaced","type":"EVENT"}],
27
+ "when": [{"id":"<commandNodeId>","title":"PlaceOrder","type":"COMMAND"}],
28
+ "then": [{"id":"<eventNodeId2>","title":"OrderConfirmed","type":"EVENT"}]
29
+ },
30
+ {
31
+ "id": "<scenario-uuid>",
32
+ "title": "Insufficient stock",
33
+ "given": [{"id":"<eventNodeId>","title":"OrderPlaced","type":"EVENT"}],
34
+ "when": [{"id":"<commandNodeId>","title":"PlaceOrder","type":"COMMAND"}],
35
+ "then": [],
36
+ "expectError": true,
37
+ "errorDescription": "Stock below requested quantity"
38
+ }
39
+ ]'
40
+ # → 201 { specNodeId, scenarios (all), added (count), isNewNode }
41
+ ```
42
+
43
+ ## Step 5 — Create a column when appending
44
+
45
+ ```bash
46
+ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$TIMELINE_ID/columns" \
47
+ -H "x-token: $TOKEN" \
48
+ -H "x-board-id: $BOARD_ID" \
49
+ -H "x-user-id: agent" \
50
+ -H "Content-Type: application/json" \
51
+ -d '{}'
52
+ ```
53
+
54
+ Response: `{ "columnId": "<uuid>", "index": <n>, "totalColumns": <n> }`
55
+
56
+ ## Step 6 — Check cell occupancy
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
+
60
+ ```bash
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"
68
+ ```
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
+
72
+ ## Step 6 — Insert a column at a specific index (conflict resolution)
73
+
74
+ No relative-insertion equivalent over REST (unlike MCP's `afterNodeId`) — compute the index by hand:
75
+
76
+ ```bash
77
+ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$TIMELINE_ID/columns" \
78
+ -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: agent" \
79
+ -H "Content-Type: application/json" \
80
+ -d '{"index": <currentColumnIndex + 1>}'
81
+ ```
82
+
83
+ ## Step 6a — Link a node to an origin on a different timeline
84
+
85
+ `POST .../nodes/:nodeId/link` with `{ "targetNodeId": "<newly-placed-node-id>" }` — see `learn-eventmodelers-api` §3.
86
+
87
+ ## Step 7a — SCREEN: create and render (HTML path)
88
+
89
+ ```bash
90
+ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/html-screen-nodes/<node-uuid>" \
91
+ -H "x-token: $TOKEN" \
92
+ -H "x-board-id: $BOARD_ID" \
93
+ -H "x-user-id: agent" \
94
+ -H "Content-Type: application/json" \
95
+ -d '{
96
+ "chapterId": "<TIMELINE_ID>",
97
+ "cellId": "<CELL_ID>",
98
+ "pages": ["<div>...</div>"]
99
+ }'
100
+ ```
101
+
102
+ ## Step 7a — SCREEN: create and render (sketch path, explicit request only)
103
+
104
+ ```bash
105
+ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/image-nodes/<node-uuid>/sketch" \
106
+ -H "x-token: $TOKEN" \
107
+ -H "x-board-id: $BOARD_ID" \
108
+ -H "x-user-id: agent" \
109
+ -H "Content-Type: application/json" \
110
+ -d '{
111
+ "chapterId": "<TIMELINE_ID>",
112
+ "cellId": "<CELL_ID>",
113
+ "description": {"elements": [...]},
114
+ "semanticDescription": "<title — what this screen shows>"
115
+ }'
116
+ ```
117
+
118
+ ## Step 7b — Create any other node type (normal path, `cellId`)
119
+
120
+ Include `x-token`, `x-board-id`, and `x-user-id: agent` on every call to `/nodes/events`.
121
+
122
+ ```bash
123
+ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
124
+ -H "x-token: $TOKEN" \
125
+ -H "x-board-id: $BOARD_ID" \
126
+ -H "x-user-id: agent" \
127
+ -H "Content-Type: application/json" \
128
+ -d '[{
129
+ "eventType": "node:created",
130
+ "nodeId": "<node-uuid>",
131
+ "boardId": "<BOARD_ID>",
132
+ "timestamp": <Date.now()>,
133
+ "chapterId": "<TIMELINE_ID>",
134
+ "cellId": "<CELL_ID>",
135
+ "meta": {
136
+ "type": "<ELEMENT_TYPE>",
137
+ "title": "<title>"
138
+ },
139
+ "node": { "data": { "title": "<title>" } }
140
+ }]'
141
+ ```
142
+
143
+ ## Step 7b — Create any other node type (fast path, `cellName`)
144
+
145
+ Same as above, but `cellName` replaces `cellId` — nothing else in the payload changes:
146
+
147
+ ```bash
148
+ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
149
+ -H "x-token: $TOKEN" \
150
+ -H "x-board-id: $BOARD_ID" \
151
+ -H "x-user-id: agent" \
152
+ -H "Content-Type: application/json" \
153
+ -d '[{
154
+ "eventType": "node:created",
155
+ "nodeId": "<node-uuid>",
156
+ "boardId": "<BOARD_ID>",
157
+ "timestamp": <Date.now()>,
158
+ "chapterId": "<TIMELINE_ID>",
159
+ "cellName": "<CELL_NAME>",
160
+ "meta": {
161
+ "type": "<ELEMENT_TYPE>",
162
+ "title": "<title>"
163
+ },
164
+ "node": { "data": { "title": "<title>" } }
165
+ }]'
166
+ ```
167
+
168
+ Response: `{ "hashes": { "<event-uuid>": "<hash>" } }`
169
+
170
+ ## Full worked example — place an EVENT via curl, start to finish
171
+
172
+ With MCP connected, the same result is one call: `mcp__eventmodelers__place_element { "boardId": "<BOARD_ID>", "timelineId": "<TIMELINE_ID>", "elementType": "EVENT", "title": "Order Placed" }`.
173
+
174
+ Placing an EVENT called "Order Placed" at the end of a timeline, over curl:
175
+
176
+ ```bash
177
+ # 1. Add a column (append at end)
178
+ curl -s -X POST "http://localhost:3000/api/org/<ORG_ID>/boards/<BOARD_ID>/timelines/<TIMELINE_ID>/columns" \
179
+ -H "Content-Type: application/json" \
180
+ -d '{}'
181
+
182
+ # 2. Fetch chapter to find the target lane cell for the new column
183
+ curl -s -H "x-user-id: place-element-skill" \
184
+ "http://localhost:3000/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/<TIMELINE_ID>"
185
+
186
+ # 3. Create the EVENT node — do not skip the x-user-id header
187
+ curl -s -X POST "http://localhost:3000/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/events" \
188
+ -H "Content-Type: application/json" \
189
+ -H "x-user-id: place-element-skill" \
190
+ -d '[{
191
+ "id": "<event-uuid>",
192
+ "eventType": "node:created",
193
+ "nodeId": "<node-uuid>",
194
+ "boardId": "<BOARD_ID>",
195
+ "timestamp": 1714900000000,
196
+ "chapterId": "<TIMELINE_ID>",
197
+ "cellId": "<CELL_ID>",
198
+ "meta": { "type": "EVENT", "title": "Order Placed" },
199
+ "node": { "id": "<node-uuid>", "data": { "title": "Order Placed" } }
200
+ }]'
201
+ ```
202
+
203
+ 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`.