@eventmodelers/cli 0.0.39 → 1.0.1
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/README.md +116 -69
- package/cli.js +98 -32
- package/package.json +4 -2
- package/shared/build-kit/lib/adapters/pocketbase-realtime-adapter.js +29 -0
- package/shared/build-kit/lib/adapters/realtime-adapter.js +27 -0
- package/shared/build-kit/lib/adapters/supabase-realtime-adapter.js +24 -0
- package/shared/build-kit/lib/ralph.js +30 -31
- package/shared/build-kit/package.json +3 -1
- package/shared/build-kit/ralph-claude.js +63 -5
- package/shared/skills/connect/SKILL.md +54 -5
- package/shared/skills/learn-eventmodelers-api/SKILL.md +88 -3
- package/shared/skills/load-slice/SKILL.md +16 -0
- package/shared/skills/update-slice-status/SKILL.md +15 -5
- package/stacks/modeling-kit/templates/.claude/skills/add-next-slice/SKILL.md +86 -0
- package/stacks/modeling-kit/templates/.claude/skills/analyze-existing-model/SKILL.md +29 -1
- package/stacks/modeling-kit/templates/.claude/skills/attributes/SKILL.md +47 -5
- package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/SKILL.md +73 -59
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-applying-conways-law/SKILL.md +1 -1
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/SKILL.md +100 -14
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/SKILL.md +22 -2
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/SKILL.md +1 -1
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/SKILL.md +30 -4
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/SKILL.md +72 -12
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/SKILL.md +66 -9
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-integrating-legacy-systems/SKILL.md +1 -1
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/SKILL.md +29 -5
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-plotting-events/SKILL.md +9 -1
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/SKILL.md +37 -3
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/SKILL.md +114 -27
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-translating-external-events/SKILL.md +1 -1
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models/SKILL.md +15 -3
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models-checklist/SKILL.md +13 -2
- package/stacks/modeling-kit/templates/.claude/skills/examples/SKILL.md +45 -7
- package/stacks/modeling-kit/templates/.claude/skills/handle-comment/SKILL.md +28 -1
- package/stacks/modeling-kit/templates/.claude/skills/html-screen/SKILL.md +45 -19
- package/stacks/modeling-kit/templates/.claude/skills/place-element/SKILL.md +172 -6
- package/stacks/modeling-kit/templates/.claude/skills/storyboard/SKILL.md +104 -25
- package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/SKILL.md +31 -17
- package/stacks/modeling-kit/templates/.claude/skills/timeline/SKILL.md +111 -12
- package/stacks/modeling-kit/templates/.claude/skills/update-prompt-status/SKILL.md +10 -1
- package/stacks/modeling-kit/templates/.claude/skills/wdyt/SKILL.md +24 -5
- package/stacks/modeling-kit/templates/kit/CLAUDE.md +12 -4
- package/stacks/node/templates/.claude/skills/build-state-view/SKILL.md +13 -7
- package/stacks/supabase/templates/.claude/skills/build-state-view/SKILL.md +13 -7
|
@@ -5,7 +5,9 @@ description: Add a new attribute or rename an existing attribute across a chain
|
|
|
5
5
|
|
|
6
6
|
# Attributes
|
|
7
7
|
|
|
8
|
-
> **Before doing anything else**, invoke the `connect` skill to resolve `TOKEN`, `BOARD_ID`, and `BASE_URL`. Do not proceed until the connect skill has completed.
|
|
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 the connect skill has completed.
|
|
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.
|
|
9
11
|
|
|
10
12
|
You are propagating an attribute change (add or rename) across a chain of elements on an eventmodelers board. You start at the target cell, apply the change, then walk backwards through inbound dependencies until you reach the source cell, applying the change to every element along the way.
|
|
11
13
|
|
|
@@ -25,7 +27,22 @@ If any of these were already provided in `$ARGUMENTS`, skip asking for them.
|
|
|
25
27
|
|
|
26
28
|
---
|
|
27
29
|
|
|
28
|
-
## Step 2 — Resolve
|
|
30
|
+
## Step 2 — Resolve the chain
|
|
31
|
+
|
|
32
|
+
**Prefer MCP:** `get_attribute_chain` resolves every node between the source and target cells (inclusive), ordered target→source, each with its full `fields[]` — this collapses the manual cell-resolution and inbound-edge walk below into one call. You still need `TIMELINE_ID` (the chapter to search): if multiple chapters exist on the board, resolve which one first (see 2a fallback below, or `mcp__eventmodelers__get_nodes { "boardId": "$BOARD_ID", "type": "CHAPTER" }`) and ask the user if ambiguous.
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
mcp__eventmodelers__get_attribute_chain {
|
|
36
|
+
"boardId": "$BOARD_ID",
|
|
37
|
+
"timelineId": "$CHAPTER_ID",
|
|
38
|
+
"targetCellName": "<target cell, e.g. B2>",
|
|
39
|
+
"sourceCellName": "<source cell, e.g. A2>"
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The result gives you the ordered chain directly — save it as the chain used in Step 4, and skip the manual walk in 2a–3c below. Continue with the fallback only if MCP isn't connected.
|
|
44
|
+
|
|
45
|
+
### Fallback (no MCP) — resolve both cells to nodes
|
|
29
46
|
|
|
30
47
|
For each cell (target and source), resolve it to a node using the same cell-resolution strategy as the `examples` skill. Always fetch fresh:
|
|
31
48
|
|
|
@@ -49,7 +66,7 @@ Decode the cell name:
|
|
|
49
66
|
s- Find the matching column in `columns` and row in `rows`.
|
|
50
67
|
- Compute: **`CELL_ID = row.id + "-" + column.id`** (cell IDs are always `<rowId>-<columnId>`).
|
|
51
68
|
|
|
52
|
-
3. Always fetch the cell live:
|
|
69
|
+
3. Always fetch the cell live. No MCP equivalent: `get_nodes` only filters by `type`, not `cellId` — the alternative is `get_node` on the CHAPTER node, reading `meta.timelineData.cells` (a sparse array; an absent cell id means the cell is empty), but that reuses the same chapter fetch from step 2 rather than guaranteeing the freshest live state, so this curl call has no direct MCP replacement:
|
|
53
70
|
```bash
|
|
54
71
|
curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?cellId=$CELL_ID" \
|
|
55
72
|
-H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: attributes-skill"
|
|
@@ -61,7 +78,7 @@ Save as `TARGET_NODE` and `SOURCE_NODE`.
|
|
|
61
78
|
|
|
62
79
|
---
|
|
63
80
|
|
|
64
|
-
|
|
81
|
+
### Fallback (no MCP) — build the dependency chain
|
|
65
82
|
|
|
66
83
|
Walk backwards from `TARGET_NODE` to `SOURCE_NODE` by following inbound edges. Build an ordered list: `[TARGET_NODE, …intermediate nodes…, SOURCE_NODE]`.
|
|
67
84
|
|
|
@@ -71,6 +88,13 @@ Each node may have an `edges` array:
|
|
|
71
88
|
edges: [{ id, source, target, sourceHandle, targetHandle }]
|
|
72
89
|
```
|
|
73
90
|
An **inbound** edge is one where `edge.target === currentNode.id`. For each inbound edge, fetch the source node:
|
|
91
|
+
|
|
92
|
+
**Prefer MCP:**
|
|
93
|
+
```
|
|
94
|
+
mcp__eventmodelers__get_node { "boardId": "$BOARD_ID", "nodeId": "$EDGE_SOURCE_ID" }
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Fallback (no MCP):**
|
|
74
98
|
```bash
|
|
75
99
|
curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/$EDGE_SOURCE_ID" \
|
|
76
100
|
-H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: attributes-skill"
|
|
@@ -123,7 +147,25 @@ For each node:
|
|
|
123
147
|
- Find the field where `name === oldName` (case-insensitive). If not found in this node, skip it (log it).
|
|
124
148
|
- Update only the `name` property to `newName`. Leave all other field properties unchanged.
|
|
125
149
|
|
|
126
|
-
Build the updated `fields` array and send a `node:changed` event
|
|
150
|
+
Build the updated `fields` array and send a `node:changed` event.
|
|
151
|
+
|
|
152
|
+
**Prefer MCP** — same event body, passed as a tool arg instead of `-d`:
|
|
153
|
+
```
|
|
154
|
+
mcp__eventmodelers__submit_node_events {
|
|
155
|
+
"boardId": "$BOARD_ID",
|
|
156
|
+
"events": [{
|
|
157
|
+
"id": "<uuid>",
|
|
158
|
+
"eventType": "node:changed",
|
|
159
|
+
"nodeId": "<NODE_ID>",
|
|
160
|
+
"boardId": "$BOARD_ID",
|
|
161
|
+
"timestamp": <epoch-ms>,
|
|
162
|
+
"changedAttributes": ["meta.fields"],
|
|
163
|
+
"meta": { "fields": "<updated_fields_array>" }
|
|
164
|
+
}]
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Fallback (no MCP)** — build the payload with Python to avoid JSON escaping issues, then POST it:
|
|
127
169
|
|
|
128
170
|
```bash
|
|
129
171
|
python3 - <<EOF > /tmp/attributes_payload.json
|
|
@@ -49,7 +49,9 @@ Do NOT invoke `connect`. Do NOT proceed to Step 1.
|
|
|
49
49
|
|
|
50
50
|
## Step 1 — Connect
|
|
51
51
|
|
|
52
|
-
Invoke the `connect` skill to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`. Do not proceed until all four are available.
|
|
52
|
+
Invoke the `connect` skill — if not already connected — to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`. Do not proceed until all four are available.
|
|
53
|
+
|
|
54
|
+
> Prefer `mcp__eventmodelers__*` tools when available (registered by the `connect` skill) — the curl blocks below (Steps 5–7, the eventmodelers board-API calls) are the fallback for sessions without MCP connected. This is unrelated to the browser automation MCP checked in Step 0, which stays as-is.
|
|
53
55
|
|
|
54
56
|
---
|
|
55
57
|
|
|
@@ -201,8 +203,14 @@ Discovered N screens across M flows:
|
|
|
201
203
|
|
|
202
204
|
**If `chapterId` was provided** — use it as the single `CHAPTER_ID` for all screens. Skip this step.
|
|
203
205
|
|
|
204
|
-
**Otherwise** — for each flow, create one chapter
|
|
206
|
+
**Otherwise** — for each flow, create one chapter.
|
|
207
|
+
|
|
208
|
+
**Prefer MCP:**
|
|
209
|
+
```
|
|
210
|
+
mcp__eventmodelers__create_chapter { "boardId": "<BOARD_ID>", "x": 0, "y": 0 }
|
|
211
|
+
```
|
|
205
212
|
|
|
213
|
+
**Fallback (no MCP):**
|
|
206
214
|
```bash
|
|
207
215
|
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/chapters" \
|
|
208
216
|
-H "x-token: $TOKEN" \
|
|
@@ -212,8 +220,26 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/chapters" \
|
|
|
212
220
|
|
|
213
221
|
Extract `id` → `CHAPTER_ID` for this flow.
|
|
214
222
|
|
|
215
|
-
Update the chapter title to the flow name using `node:changed
|
|
223
|
+
Update the chapter title to the flow name using `node:changed`.
|
|
216
224
|
|
|
225
|
+
**Prefer MCP:**
|
|
226
|
+
```
|
|
227
|
+
mcp__eventmodelers__submit_node_events {
|
|
228
|
+
"boardId": "<BOARD_ID>",
|
|
229
|
+
"events": [{
|
|
230
|
+
"id": "<uuid>",
|
|
231
|
+
"eventType": "node:changed",
|
|
232
|
+
"nodeId": "<CHAPTER_ID>",
|
|
233
|
+
"boardId": "<BOARD_ID>",
|
|
234
|
+
"timestamp": <NOW_MS>,
|
|
235
|
+
"changedAttributes": ["meta.title"],
|
|
236
|
+
"meta": { "type": "CHAPTER", "title": "<flow name>" },
|
|
237
|
+
"node": { "id": "<CHAPTER_ID>", "data": {} }
|
|
238
|
+
}]
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**Fallback (no MCP):**
|
|
217
243
|
```bash
|
|
218
244
|
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
|
|
219
245
|
-H "x-token: $TOKEN" \
|
|
@@ -238,18 +264,24 @@ Save `CHAPTER_ID` against each flow.
|
|
|
238
264
|
|
|
239
265
|
## Step 6 — Fetch chapter grid and build column queue
|
|
240
266
|
|
|
241
|
-
For each chapter, fetch its current grid state
|
|
267
|
+
For each chapter, fetch its current grid state.
|
|
268
|
+
|
|
269
|
+
**Prefer MCP:**
|
|
270
|
+
```
|
|
271
|
+
mcp__eventmodelers__get_node { "boardId": "<BOARD_ID>", "nodeId": "<CHAPTER_ID>" }
|
|
272
|
+
```
|
|
242
273
|
|
|
274
|
+
**Fallback (no MCP):**
|
|
243
275
|
```bash
|
|
244
276
|
curl -s -H "x-token: $TOKEN" \
|
|
245
277
|
"$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/$CHAPTER_ID"
|
|
246
278
|
```
|
|
247
279
|
|
|
248
280
|
From `meta.timelineData`:
|
|
249
|
-
- `rows` — find the row with `type === "actor"` → save its `id` as `actorRowId`
|
|
250
|
-
- `columns` — ordered list; build an empty-column queue
|
|
281
|
+
- `rows` — find the row with `type === "actor"` → save its `id` as `actorRowId` and its 0-based position in `rows` as `actorRowIndex`
|
|
282
|
+
- `columns` — ordered list; build an empty-column queue, remembering each entry's 0-based position in `columns` as its `columnIndex`
|
|
251
283
|
|
|
252
|
-
**Cell ID convention**: `<rowId>-<columnId>` — always computed directly, never looked up.
|
|
284
|
+
**Cell ID convention**: `<rowId>-<columnId>` — always computed directly, never looked up. **Cell name convention** (spreadsheet-style, needed for the MCP tool in Step 7b): `<columnLetter><rowNumber>`, where `columnLetter` is `columnIndex` converted to spreadsheet letters (0→A, 1→B, …25→Z, 26→AA, …) and `rowNumber` is `actorRowIndex + 1`.
|
|
253
285
|
|
|
254
286
|
---
|
|
255
287
|
|
|
@@ -261,10 +293,17 @@ For each screen:
|
|
|
261
293
|
|
|
262
294
|
### 7a — Acquire a column slot
|
|
263
295
|
|
|
264
|
-
**If the empty-column queue is non-empty** — pop the first entry → `columnId`. Compute `CELL_ID = actorRowId + "-" + columnId
|
|
296
|
+
**If the empty-column queue is non-empty** — pop the first entry → `columnId` and its remembered `columnIndex`. Compute `CELL_ID = actorRowId + "-" + columnId` and `CELL_NAME` per the convention above.
|
|
297
|
+
|
|
298
|
+
**If the empty-column queue is empty** — create a new column.
|
|
265
299
|
|
|
266
|
-
**
|
|
300
|
+
**Prefer MCP:**
|
|
301
|
+
```
|
|
302
|
+
mcp__eventmodelers__add_column { "boardId": "<BOARD_ID>", "timelineId": "<CHAPTER_ID>" }
|
|
303
|
+
```
|
|
304
|
+
The result's `index` field is the new column's `columnIndex` (use it directly for `CELL_NAME` — no need to recompute from the full column list).
|
|
267
305
|
|
|
306
|
+
**Fallback (no MCP):**
|
|
268
307
|
```bash
|
|
269
308
|
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$CHAPTER_ID/columns" \
|
|
270
309
|
-H "x-token: $TOKEN" \
|
|
@@ -273,70 +312,46 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$CHAPTER_I
|
|
|
273
312
|
-H "Content-Type: application/json" \
|
|
274
313
|
-d '{}'
|
|
275
314
|
```
|
|
315
|
+
Response includes `{ columnId, index, totalColumns }` — `index` is the new `columnIndex`.
|
|
276
316
|
|
|
277
|
-
Extract `columnId`. Compute `CELL_ID = actorRowId + "-" + columnId
|
|
317
|
+
Extract `columnId`. Compute `CELL_ID = actorRowId + "-" + columnId` and `CELL_NAME` per the convention above.
|
|
278
318
|
|
|
279
|
-
### 7b —
|
|
319
|
+
### 7b — Create the SCREEN node with its screenshot, atomically
|
|
280
320
|
|
|
281
|
-
Generate
|
|
321
|
+
Generate a UUID for `SCREEN_NODE_ID`:
|
|
282
322
|
|
|
283
323
|
```bash
|
|
284
324
|
python3 -c "import uuid; print(uuid.uuid4())"
|
|
285
325
|
```
|
|
286
326
|
|
|
287
|
-
|
|
327
|
+
This step must create the node and attach the real screenshot in a single call — never split into "upload image" then "create node" (or vice versa), which leaves a window where the node exists with no image or an image with no node.
|
|
288
328
|
|
|
289
|
-
|
|
290
|
-
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/images/$SCREEN_NODE_ID" \
|
|
291
|
-
-H "x-token: $TOKEN" \
|
|
292
|
-
-F "file=@<screen.filepath>"
|
|
329
|
+
**Prefer MCP:**
|
|
293
330
|
```
|
|
294
|
-
|
|
295
|
-
>
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
|
|
305
|
-
-H "x-token: $TOKEN" \
|
|
306
|
-
-H "x-board-id: $BOARD_ID" \
|
|
307
|
-
-H "x-user-id: discover-storyboard" \
|
|
308
|
-
-H "Content-Type: application/json" \
|
|
309
|
-
-d '[{
|
|
310
|
-
"id": "<EVT_ID>",
|
|
311
|
-
"eventType": "node:created",
|
|
312
|
-
"nodeId": "<SCREEN_NODE_ID>",
|
|
313
|
-
"boardId": "<BOARD_ID>",
|
|
314
|
-
"timestamp": <NOW_MS>,
|
|
315
|
-
"chapterId": "<CHAPTER_ID>",
|
|
316
|
-
"cellId": "<CELL_ID>",
|
|
317
|
-
"meta": {
|
|
318
|
-
"type": "SCREEN",
|
|
319
|
-
"title": "<screen.title>",
|
|
320
|
-
"description": "<screen.description — 'Shows X. Arrived via: Y. Actions: user can do A, user can do B.'>"
|
|
321
|
-
},
|
|
322
|
-
"node": { "id": "<SCREEN_NODE_ID>", "data": {} }
|
|
323
|
-
}]'
|
|
331
|
+
mcp__eventmodelers__create_screen {
|
|
332
|
+
"boardId": "<BOARD_ID>",
|
|
333
|
+
"contentType": "image",
|
|
334
|
+
"nodeId": "<SCREEN_NODE_ID>",
|
|
335
|
+
"chapterId": "<CHAPTER_ID>",
|
|
336
|
+
"cellName": "<CELL_NAME>",
|
|
337
|
+
"imageBase64": "<base64-encoded contents of screen.filepath, no data: URI prefix>",
|
|
338
|
+
"mimeType": "image/png",
|
|
339
|
+
"description": "<screen.description — 'Shows X. Arrived via: Y. Actions: user can do A, user can do B.'>"
|
|
340
|
+
}
|
|
324
341
|
```
|
|
325
342
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
### 7d — Verify the screen
|
|
329
|
-
|
|
330
|
-
Confirm the node and its uploaded screenshot both actually exist:
|
|
331
|
-
|
|
343
|
+
**Fallback (no MCP)** — the same atomic operation via the `image-nodes` endpoint (not the plain `images/:id` endpoint, which only updates an existing node's image and does not place it):
|
|
332
344
|
```bash
|
|
333
|
-
curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/
|
|
334
|
-
-H "x-token: $TOKEN"
|
|
345
|
+
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/image-nodes/$SCREEN_NODE_ID" \
|
|
346
|
+
-H "x-token: $TOKEN" \
|
|
347
|
+
-F "file=@<screen.filepath>" \
|
|
348
|
+
-F "chapterId=$CHAPTER_ID" \
|
|
349
|
+
-F "cellName=$CELL_NAME"
|
|
335
350
|
```
|
|
336
351
|
|
|
337
|
-
|
|
352
|
+
Response: `204` on success. Log failures in the final report but continue to the next screen — do not stop the entire run.
|
|
338
353
|
|
|
339
|
-
###
|
|
354
|
+
### 7d — Report per-screen progress
|
|
340
355
|
|
|
341
356
|
After each screen: print one line, e.g.:
|
|
342
357
|
```
|
|
@@ -355,8 +370,7 @@ Discover Storyboard complete.
|
|
|
355
370
|
Flows created (N total):
|
|
356
371
|
• "Login & Authentication" — chapter <id> — 3 screens
|
|
357
372
|
• "Product Browsing" — chapter <id> — 5 screens
|
|
358
|
-
|
|
359
|
-
Screens uploaded: N of M (list any failures, including screens that failed 7d verification)
|
|
373
|
+
Screens uploaded: N of M (list any failures)
|
|
360
374
|
|
|
361
375
|
Next steps:
|
|
362
376
|
- Open the board to review the storyboard timelines
|
package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-applying-conways-law/SKILL.md
CHANGED
|
@@ -9,7 +9,7 @@ allowed-tools:
|
|
|
9
9
|
|
|
10
10
|
# Applying Conway's Law
|
|
11
11
|
|
|
12
|
-
> **Before doing anything else**, invoke the `connect` skill to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`.
|
|
12
|
+
> **Before doing anything else**, invoke the `connect` skill — if not already connected — to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`. Do not proceed until it has completed. Consult `learn-eventmodelers-api` only if you need to look up a specific endpoint or field this file doesn't cover — don't load it eagerly.
|
|
13
13
|
|
|
14
14
|
## Interview Phase (Optional)
|
|
15
15
|
|
package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/SKILL.md
CHANGED
|
@@ -9,7 +9,9 @@ allowed-tools:
|
|
|
9
9
|
|
|
10
10
|
# Brainstorming Events
|
|
11
11
|
|
|
12
|
-
> **Before doing anything else**, invoke the `connect` skill to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`.
|
|
12
|
+
> **Before doing anything else**, invoke the `connect` skill — if not already connected — to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`. Do not proceed until it has completed. Consult `learn-eventmodelers-api` only if you need to look up a specific endpoint or field this file doesn't cover — don't load it eagerly.
|
|
13
|
+
|
|
14
|
+
Prefer `mcp__eventmodelers__*` tools when available (registered by the `connect` skill) — the curl blocks below are the fallback for sessions without MCP connected.
|
|
13
15
|
|
|
14
16
|
## Interview Phase (Optional)
|
|
15
17
|
|
|
@@ -118,6 +120,12 @@ This section feeds into subsequent steps (plotting, storyboarding, etc.)
|
|
|
118
120
|
|
|
119
121
|
Before brainstorming, check for EVENT nodes already on the board to avoid duplicating events from a previous session:
|
|
120
122
|
|
|
123
|
+
**Prefer MCP:**
|
|
124
|
+
```
|
|
125
|
+
mcp__eventmodelers__get_nodes { "boardId": "<BOARD_ID>", "type": "EVENT" }
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Fallback (no MCP):**
|
|
121
129
|
```bash
|
|
122
130
|
curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
123
131
|
"$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?type=EVENT"
|
|
@@ -125,6 +133,12 @@ curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
|
125
133
|
|
|
126
134
|
If events already exist, treat them as the starting list and focus on discovering what might be missing. Also check for existing chapters (timelines) so you can reuse them:
|
|
127
135
|
|
|
136
|
+
**Prefer MCP:**
|
|
137
|
+
```
|
|
138
|
+
mcp__eventmodelers__get_nodes { "boardId": "<BOARD_ID>", "type": "CHAPTER" }
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Fallback (no MCP):**
|
|
128
142
|
```bash
|
|
129
143
|
curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
130
144
|
"$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?type=CHAPTER"
|
|
@@ -147,7 +161,13 @@ If all events belong to a single flow, one timeline is correct — do not split
|
|
|
147
161
|
|
|
148
162
|
For each group, create a chapter on the board **before placing any events**. Reuse an existing chapter if one already matches the workflow name.
|
|
149
163
|
|
|
150
|
-
**
|
|
164
|
+
**Prefer MCP — create a chapter:**
|
|
165
|
+
```
|
|
166
|
+
mcp__eventmodelers__create_chapter { "boardId": "<BOARD_ID>", "x": 0, "y": 1200 }
|
|
167
|
+
```
|
|
168
|
+
(`x`/`y` are optional — see the vertical-stacking note below. Response includes the new `timelineId`.)
|
|
169
|
+
|
|
170
|
+
**Fallback (no MCP) — create a chapter:**
|
|
151
171
|
```bash
|
|
152
172
|
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/chapters" \
|
|
153
173
|
-H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
@@ -156,6 +176,23 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/chapters" \
|
|
|
156
176
|
```
|
|
157
177
|
|
|
158
178
|
**Immediately set its title** (use the workflow / bounded-context name):
|
|
179
|
+
|
|
180
|
+
**Prefer MCP:**
|
|
181
|
+
```
|
|
182
|
+
mcp__eventmodelers__submit_node_events {
|
|
183
|
+
"boardId": "<BOARD_ID>",
|
|
184
|
+
"events": [{
|
|
185
|
+
"id": "<uuid>",
|
|
186
|
+
"eventType": "node:changed",
|
|
187
|
+
"nodeId": "<chapterId>",
|
|
188
|
+
"boardId": "<BOARD_ID>",
|
|
189
|
+
"timestamp": 1234567890,
|
|
190
|
+
"meta": {"type": "CHAPTER", "title": "Reservation & Lending"}
|
|
191
|
+
}]
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Fallback (no MCP):**
|
|
159
196
|
```bash
|
|
160
197
|
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
|
|
161
198
|
-H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
@@ -171,8 +208,14 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
|
|
|
171
208
|
```
|
|
172
209
|
|
|
173
210
|
**Stack timelines vertically so they do not overlap.**
|
|
174
|
-
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`):
|
|
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:
|
|
175
212
|
|
|
213
|
+
**Prefer MCP:**
|
|
214
|
+
```
|
|
215
|
+
mcp__eventmodelers__move_timeline_position { "boardId": "<BOARD_ID>", "timelineId": "<TL>", "x": 0, "y": 1200 }
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**Fallback (no MCP):**
|
|
176
219
|
```bash
|
|
177
220
|
curl -s -X PUT "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$TL/position" \
|
|
178
221
|
-H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
@@ -197,11 +240,11 @@ Fields use this structure inside `meta`:
|
|
|
197
240
|
"type": "EVENT",
|
|
198
241
|
"title": "OrderPlaced",
|
|
199
242
|
"fields": [
|
|
200
|
-
{"name": "orderId", "type": "String",
|
|
201
|
-
{"name": "customerId", "type": "String",
|
|
202
|
-
{"name": "total", "type": "
|
|
203
|
-
{"name": "status", "type": "String",
|
|
204
|
-
{"name": "placedAt", "type": "
|
|
243
|
+
{"name": "orderId", "type": "String", "example": "order-abc123"},
|
|
244
|
+
{"name": "customerId", "type": "String", "example": "cust-456"},
|
|
245
|
+
{"name": "total", "type": "Decimal", "example": "149.99"},
|
|
246
|
+
{"name": "status", "type": "String", "example": "Draft"},
|
|
247
|
+
{"name": "placedAt", "type": "DateTime", "example": "2026-05-29T10:00:00Z"}
|
|
205
248
|
]
|
|
206
249
|
}
|
|
207
250
|
```
|
|
@@ -225,6 +268,13 @@ When a chapter is available, place each event directly into it. **Include `cellI
|
|
|
225
268
|
For each event:
|
|
226
269
|
|
|
227
270
|
**Step A — Create a column** (append at end of the chapter):
|
|
271
|
+
|
|
272
|
+
**Prefer MCP:**
|
|
273
|
+
```
|
|
274
|
+
mcp__eventmodelers__add_column { "boardId": "<BOARD_ID>", "timelineId": "<CHAPTER_ID>" }
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**Fallback (no MCP):**
|
|
228
278
|
```bash
|
|
229
279
|
curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$CHAPTER_ID/columns" \
|
|
230
280
|
-H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: brainstorming-events" \
|
|
@@ -233,6 +283,13 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$CHAPTER_I
|
|
|
233
283
|
```
|
|
234
284
|
|
|
235
285
|
**Step B — Fetch the chapter to find the swimlane row ID** (only needed once per chapter):
|
|
286
|
+
|
|
287
|
+
**Prefer MCP:**
|
|
288
|
+
```
|
|
289
|
+
mcp__eventmodelers__get_node { "boardId": "<BOARD_ID>", "nodeId": "<CHAPTER_ID>" }
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
**Fallback (no MCP):**
|
|
236
293
|
```bash
|
|
237
294
|
curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
238
295
|
"$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/$CHAPTER_ID"
|
|
@@ -241,7 +298,36 @@ curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
|
241
298
|
|
|
242
299
|
**Step C — Compute:** `cellId = swimlaneRow.id + "-" + columnId`
|
|
243
300
|
|
|
244
|
-
**Step D — Create the event with `cellId
|
|
301
|
+
**Step D — Create the event with `cellId`.**
|
|
302
|
+
|
|
303
|
+
**Prefer MCP** — pass the same shape to `submit_node_events` (`events` is a tool arg, not a `-d` body):
|
|
304
|
+
```
|
|
305
|
+
mcp__eventmodelers__submit_node_events {
|
|
306
|
+
"boardId": "<BOARD_ID>",
|
|
307
|
+
"events": [{
|
|
308
|
+
"id": "<event-uuid>",
|
|
309
|
+
"eventType": "node:created",
|
|
310
|
+
"nodeId": "<node-uuid>",
|
|
311
|
+
"boardId": "<BOARD_ID>",
|
|
312
|
+
"timestamp": 1234567890,
|
|
313
|
+
"chapterId": "<chapterId>",
|
|
314
|
+
"cellId": "<swimlaneRowId>-<columnId>",
|
|
315
|
+
"meta": {
|
|
316
|
+
"type": "EVENT",
|
|
317
|
+
"title": "BookReserved",
|
|
318
|
+
"fields": [
|
|
319
|
+
{"name": "reservationId", "type": "String", "example": "res-789"},
|
|
320
|
+
{"name": "copyId", "type": "String", "example": "copy-42"},
|
|
321
|
+
{"name": "memberId", "type": "String", "example": "mbr-101"},
|
|
322
|
+
{"name": "expiresAt", "type": "DateTime", "example": "2026-06-01T00:00:00Z"},
|
|
323
|
+
{"name": "reservedAt", "type": "DateTime", "example": "2026-05-29T10:00:00Z"}
|
|
324
|
+
]
|
|
325
|
+
}
|
|
326
|
+
}]
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**Fallback (no MCP) — same body via `POST .../nodes/events`:**
|
|
245
331
|
```json
|
|
246
332
|
[{
|
|
247
333
|
"id": "<event-uuid>",
|
|
@@ -255,11 +341,11 @@ curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
|
255
341
|
"type": "EVENT",
|
|
256
342
|
"title": "BookReserved",
|
|
257
343
|
"fields": [
|
|
258
|
-
{"name": "reservationId", "type": "String",
|
|
259
|
-
{"name": "copyId", "type": "String",
|
|
260
|
-
{"name": "memberId", "type": "String",
|
|
261
|
-
{"name": "expiresAt", "type": "
|
|
262
|
-
{"name": "reservedAt", "type": "
|
|
344
|
+
{"name": "reservationId", "type": "String", "example": "res-789"},
|
|
345
|
+
{"name": "copyId", "type": "String", "example": "copy-42"},
|
|
346
|
+
{"name": "memberId", "type": "String", "example": "mbr-101"},
|
|
347
|
+
{"name": "expiresAt", "type": "DateTime", "example": "2026-06-01T00:00:00Z"},
|
|
348
|
+
{"name": "reservedAt", "type": "DateTime", "example": "2026-05-29T10:00:00Z"}
|
|
263
349
|
]
|
|
264
350
|
}
|
|
265
351
|
}]
|
package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/SKILL.md
CHANGED
|
@@ -8,12 +8,22 @@ allowed-tools:
|
|
|
8
8
|
|
|
9
9
|
# Checking Completeness
|
|
10
10
|
|
|
11
|
-
> **Before doing anything else**, invoke the `connect` skill to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`.
|
|
11
|
+
> **Before doing anything else**, invoke the `connect` skill — if not already connected — to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`. Do not proceed until it has completed. Consult `learn-eventmodelers-api` only if you need to look up a specific endpoint or field this file doesn't cover — don't load it eagerly.
|
|
12
|
+
|
|
13
|
+
Prefer `mcp__eventmodelers__*` tools when available (registered by the `connect` skill) — the curl blocks below are the fallback for sessions without MCP connected.
|
|
12
14
|
|
|
13
15
|
## Board Context
|
|
14
16
|
|
|
15
17
|
Before starting, read the current board state to drive the analysis from what is actually on the board rather than relying solely on conversation context:
|
|
16
18
|
|
|
19
|
+
**Prefer MCP:**
|
|
20
|
+
```
|
|
21
|
+
mcp__eventmodelers__get_nodes { "boardId": "<BOARD_ID>", "type": "EVENT" }
|
|
22
|
+
mcp__eventmodelers__get_nodes { "boardId": "<BOARD_ID>", "type": "COMMAND" }
|
|
23
|
+
mcp__eventmodelers__get_nodes { "boardId": "<BOARD_ID>", "type": "READMODEL" }
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Fallback (no MCP):**
|
|
17
27
|
```bash
|
|
18
28
|
# All nodes (events, commands, read models, screens)
|
|
19
29
|
curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
@@ -152,6 +162,16 @@ Status: All fields sourced
|
|
|
152
162
|
|
|
153
163
|
Every column that holds a COMMAND or READMODEL node must have a slice defined (a SLICE_BORDER node on that column) — otherwise it can never be built as a feature. Skip columns whose COMMAND/READMODEL node has `data.linkedTo` set: it's a linked copy (see Board Context above), and only the original's column needs a slice.
|
|
154
164
|
|
|
165
|
+
**Prefer MCP** — `list_slices` is lighter than filtering all nodes, and also returns each slice's status:
|
|
166
|
+
```
|
|
167
|
+
mcp__eventmodelers__list_slices { "boardId": "<BOARD_ID>" }
|
|
168
|
+
```
|
|
169
|
+
Or, to get the full SLICE_BORDER nodes (with `columnId`) the same way as the curl fallback:
|
|
170
|
+
```
|
|
171
|
+
mcp__eventmodelers__get_nodes { "boardId": "<BOARD_ID>", "type": "SLICE_BORDER" }
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Fallback (no MCP):**
|
|
155
175
|
```bash
|
|
156
176
|
curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
157
177
|
"$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?type=SLICE_BORDER"
|
|
@@ -435,7 +455,7 @@ Present as:
|
|
|
435
455
|
### Issues Found
|
|
436
456
|
1. Estimated delivery date missing
|
|
437
457
|
- Fix: Add to OrderShipped event
|
|
438
|
-
- Type:
|
|
458
|
+
- Type: DateTime (ISO 8601)
|
|
439
459
|
- Source: Calculated from carrier API
|
|
440
460
|
- Status: Will add in next iteration
|
|
441
461
|
|
package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/SKILL.md
CHANGED
|
@@ -9,7 +9,7 @@ allowed-tools:
|
|
|
9
9
|
|
|
10
10
|
# Designing Event Models
|
|
11
11
|
|
|
12
|
-
> **Before doing anything else**, invoke the `connect` skill to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`.
|
|
12
|
+
> **Before doing anything else**, invoke the `connect` skill — if not already connected — to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`. Do not proceed until it has completed. Consult `learn-eventmodelers-api` only if you need to look up a specific endpoint or field this file doesn't cover — don't load it eagerly.
|
|
13
13
|
|
|
14
14
|
## Interview Phase (Optional)
|
|
15
15
|
|
package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/SKILL.md
CHANGED
|
@@ -9,7 +9,9 @@ allowed-tools:
|
|
|
9
9
|
|
|
10
10
|
# Elaborating Scenarios
|
|
11
11
|
|
|
12
|
-
> **Before doing anything else**, invoke the `connect` skill to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`.
|
|
12
|
+
> **Before doing anything else**, invoke the `connect` skill — if not already connected — to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`. Do not proceed until it has completed. Consult `learn-eventmodelers-api` only if you need to look up a specific endpoint or field this file doesn't cover — don't load it eagerly.
|
|
13
|
+
|
|
14
|
+
Prefer `mcp__eventmodelers__*` tools when available (registered by the `connect` skill) — the curl blocks below are the fallback for sessions without MCP connected.
|
|
13
15
|
|
|
14
16
|
## Interview Phase (Optional)
|
|
15
17
|
|
|
@@ -571,8 +573,14 @@ After designing all scenarios, post them to the board using the timeline/column
|
|
|
571
573
|
|
|
572
574
|
### Step 1 — Identify the target timeline and column
|
|
573
575
|
|
|
574
|
-
Fetch all CHAPTER nodes to find the timeline
|
|
576
|
+
Fetch all CHAPTER nodes to find the timeline.
|
|
577
|
+
|
|
578
|
+
**Prefer MCP:**
|
|
579
|
+
```
|
|
580
|
+
mcp__eventmodelers__get_nodes { "boardId": "<BOARD_ID>", "type": "CHAPTER" }
|
|
581
|
+
```
|
|
575
582
|
|
|
583
|
+
**Fallback (no MCP):**
|
|
576
584
|
```bash
|
|
577
585
|
curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?type=CHAPTER" \
|
|
578
586
|
-H "x-token: $TOKEN"
|
|
@@ -584,8 +592,14 @@ For each command or view being specified, find its column: fetch the chapter nod
|
|
|
584
592
|
|
|
585
593
|
### Step 2 — Load valid step elements
|
|
586
594
|
|
|
587
|
-
For each target timeline, call spec-info to discover the node IDs that may appear in given/when/then
|
|
595
|
+
For each target timeline, call spec-info to discover the node IDs that may appear in given/when/then.
|
|
588
596
|
|
|
597
|
+
**Prefer MCP:**
|
|
598
|
+
```
|
|
599
|
+
mcp__eventmodelers__get_spec_info { "boardId": "<BOARD_ID>", "timelineId": "<TL>" }
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
**Fallback (no MCP):**
|
|
589
603
|
```bash
|
|
590
604
|
curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$TL/spec-info" \
|
|
591
605
|
-H "x-token: $TOKEN"
|
|
@@ -602,8 +616,20 @@ See `learn-eventmodelers-api` for the full step item format, scenario object sha
|
|
|
602
616
|
|
|
603
617
|
### Step 4 — Post all scenarios for a column in one call
|
|
604
618
|
|
|
605
|
-
Group all scenarios for the same column and
|
|
619
|
+
Group all scenarios for the same column and post them as an array. The SCENARIO spec node is created automatically — no pre-creation needed.
|
|
620
|
+
|
|
621
|
+
**Prefer MCP:**
|
|
622
|
+
```
|
|
623
|
+
mcp__eventmodelers__add_scenario {
|
|
624
|
+
"boardId": "<BOARD_ID>",
|
|
625
|
+
"timelineId": "<TL>",
|
|
626
|
+
"columnId": "<COL>",
|
|
627
|
+
"scenarios": [...scenario objects, same shape as below...]
|
|
628
|
+
}
|
|
629
|
+
```
|
|
630
|
+
`given`/`when`/`then` are arrays of `{id, title?, type?, ...}` objects — **not** bare nodeId strings (this differs from the raw REST body shown in the fallback below). The examples in Steps 4b/4c/§Rejection already use this object shape; pass them straight through as the `scenarios` array. For a state-view scenario whose `when` needs to represent a query rather than a COMMAND, `when` may hold a single inline object that is **not** a board node: `{"id": "<generated-uuid>", "type": "QUERY", "title": "...", "fields": [{"name": "...", "example": "..."}]}`. Same server-side rules apply either way (see below).
|
|
606
631
|
|
|
632
|
+
**Fallback (no MCP):**
|
|
607
633
|
```bash
|
|
608
634
|
curl -s -X POST \
|
|
609
635
|
"$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$TL/columns/$COL/scenarios" \
|