@eventmodelers/cli 1.0.80 → 1.0.81
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/cli.js +2 -2
- package/package.json +1 -1
- package/shared/skills/connect/SKILL.md +6 -4
- package/shared/skills/learn-eventmodelers-api/SKILL.md +11 -10
- package/shared/skills/request-feedback/SKILL.md +0 -2
- package/shared/skills/update-slice-status/SKILL.md +0 -2
- package/stacks/modeling-kit/templates/.claude/skills/attributes/SKILL.md +2 -2
- package/stacks/modeling-kit/templates/.claude/skills/attributes/references/api-fallback.md +1 -3
- package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/SKILL.md +0 -2
- package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/references/api-fallback.md +0 -2
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/SKILL.md +0 -4
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/references/api-fallback.md +0 -4
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-automation-chains/SKILL.md +0 -1
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-automation-chains/references/api-fallback.md +0 -1
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/SKILL.md +0 -2
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/references/api-fallback.md +0 -2
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/SKILL.md +0 -1
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/references/api-fallback.md +0 -2
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/SKILL.md +0 -1
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/references/api-fallback.md +4 -4
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/SKILL.md +0 -2
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/references/api-fallback.md +0 -2
- package/stacks/modeling-kit/templates/.claude/skills/examples/SKILL.md +1 -3
- package/stacks/modeling-kit/templates/.claude/skills/examples/references/api-fallback.md +1 -3
- package/stacks/modeling-kit/templates/.claude/skills/html-screen/SKILL.md +0 -2
- package/stacks/modeling-kit/templates/.claude/skills/html-screen/references/api-fallback.md +0 -1
- package/stacks/modeling-kit/templates/.claude/skills/place-element/SKILL.md +3 -5
- package/stacks/modeling-kit/templates/.claude/skills/place-element/references/api-fallback.md +4 -8
- package/stacks/modeling-kit/templates/.claude/skills/storyboard/SKILL.md +0 -1
- package/stacks/modeling-kit/templates/.claude/skills/storyboard/references/api-fallback.md +0 -1
- package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/SKILL.md +0 -1
- package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/references/api-fallback.md +0 -1
- package/stacks/modeling-kit/templates/.claude/skills/timeline/SKILL.md +0 -4
- package/stacks/modeling-kit/templates/.claude/skills/timeline/references/api-fallback.md +1 -7
- package/stacks/modeling-kit/templates/kit/AGENTS.md +2 -1
- package/stacks/modeling-kit/templates/kit/CLAUDE.md +1 -1
package/cli.js
CHANGED
|
@@ -3595,11 +3595,11 @@ program
|
|
|
3595
3595
|
...agentHeaders(cfg),
|
|
3596
3596
|
},
|
|
3597
3597
|
body: JSON.stringify([{
|
|
3598
|
+
// The event id is the caller's and required; boardId/timestamp are the server's —
|
|
3599
|
+
// it derives both from the request and ignores anything sent here.
|
|
3598
3600
|
id: randomUUID(),
|
|
3599
3601
|
eventType: 'node:changed',
|
|
3600
3602
|
nodeId: slice.id,
|
|
3601
|
-
boardId: cfg.boardId,
|
|
3602
|
-
timestamp: Date.now(),
|
|
3603
3603
|
changedAttributes: ['sliceStatus'],
|
|
3604
3604
|
meta: { sliceStatus: newStatus },
|
|
3605
3605
|
}]),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eventmodelers/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.81",
|
|
4
4
|
"description": "Eventmodelers CLI — real-time Claude agent + skills for Claude Code, for any stack (Node, Supabase, Axon, OpenCQRS, UmaDB, Kurrent, or modeling-only)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -283,15 +283,17 @@ The same discipline applies to writes: `submit_node_events` takes `events[]`, so
|
|
|
283
283
|
|
|
284
284
|
Where per-node calls genuinely can't be avoided, issue them together in one message so they run concurrently rather than in sequence.
|
|
285
285
|
|
|
286
|
-
### Ids
|
|
286
|
+
### Ids
|
|
287
287
|
|
|
288
|
-
Elements you create carry client-side ids
|
|
288
|
+
Elements you create carry client-side ids — one `nodeId` per new node — and **every event carries its own `id`**, a fresh uuid per event, never the node's. Mint them **once per turn, in a single call**, and take from that pool as you assemble the event array:
|
|
289
289
|
|
|
290
290
|
```bash
|
|
291
|
-
for i in $(seq
|
|
291
|
+
for i in $(seq 8); do uuidgen; done
|
|
292
292
|
```
|
|
293
293
|
|
|
294
|
-
Nothing in that depends on anything you're about to read, so splitting it across
|
|
294
|
+
Nothing in that depends on anything you're about to read, so splitting it across several shells is round trips bought for nothing.
|
|
295
|
+
|
|
296
|
+
The event `id` is **required** — an event without one is rejected as an invalid shape. It is what keys the returned `hashes` map, and what makes a resubmit idempotent: the same event sent twice under the same id writes one board event, not two. An event's `boardId` and `timestamp`, by contrast, are **not** yours to send — the server takes the board from the call and stamps the time itself, and ignores both if you send them.
|
|
295
297
|
|
|
296
298
|
---
|
|
297
299
|
|
|
@@ -20,12 +20,12 @@ Server name: `eventmodelers`. Every tool takes `boardId` explicitly; none need `
|
|
|
20
20
|
| Tool | Args | Purpose | REST equivalent |
|
|
21
21
|
|---|---|---|---|
|
|
22
22
|
| `list_boards` | — | List boards for the org | §1 `GET /api/boards` (org-scoped) |
|
|
23
|
-
| `get_nodes` | `boardId`, `type?`, `name?`, `chapterId?`, `nodeIds?`, `projection?` (`"line"`) | List nodes, optionally by type and/or a partial case-insensitive title match. `chapterId` scopes to one timeline — prefer this over an unscoped board-wide call whenever the step is working within one chapter (the common case); `nodeIds` fetches a known, scattered subset in one call (e.g. re-verifying exactly the nodes just touched by a batch write) instead of a full `type` refetch; `projection: "line"` maps each match to `{id, type, title}` only | §3 `GET .../nodes` |
|
|
24
|
-
| `get_node` | `boardId`, `nodeId`, `projection?` (`"cells"` \| `"edges"`) | Get one node. `projection: "cells"` (CHAPTER nodes only) returns just `{rows, columns, cells}` instead of the full `timelineData` — use whenever only the grid/occupancy is needed, not the whole chapter; `projection: "edges"` returns just that node's inbound/outbound connections instead of `findNodeById`'s full record. Both are opt-in — omitting `projection` is the unchanged full response | §3 `GET .../nodes/:nodeId` |
|
|
23
|
+
| `get_nodes` | `boardId`, `type?`, `name?`, `chapterId?`, `nodeIds?`, `projection?` (`"line"`) | List nodes, optionally by type and/or a partial case-insensitive title match. `chapterId` scopes to one timeline — prefer this over an unscoped board-wide call whenever the step is working within one chapter (the common case); `nodeIds` fetches a known, scattered subset in one call (e.g. re-verifying exactly the nodes just touched by a batch write) instead of a full `type` refetch; `projection: "line"` maps each match to `{id, type, title}` only. Every node carries `cellName`, its cell address in the chapter it is placed in (absent when unplaced) — read the cell names the cell-addressed tools need from here, never derive or invent one | §3 `GET .../nodes` |
|
|
24
|
+
| `get_node` | `boardId`, `nodeId`, `projection?` (`"cells"` \| `"edges"`) | Get one node — the full response carries `cellName`, its cell address in the chapter it is placed in. `projection: "cells"` (CHAPTER nodes only) returns just `{rows, columns, cells}` instead of the full `timelineData` — use whenever only the grid/occupancy is needed, not the whole chapter; `projection: "edges"` returns just that node's inbound/outbound connections instead of `findNodeById`'s full record. Both are opt-in — omitting `projection` is the unchanged full response | §3 `GET .../nodes/:nodeId` |
|
|
25
25
|
| `get_node_comments` | `boardId`, `nodeId` | List comments on a node | §1 `GET .../nodes/:nodeId/comments` |
|
|
26
26
|
| `get_board_events` | `boardId` | All board events, in sequence | §1 `GET .../events` |
|
|
27
27
|
| `search_board_events` | `boardId`, `name` | Search events by node name | §1 `GET .../events/search` |
|
|
28
|
-
| `submit_node_events` | `boardId`, `events[]`, `autoConnect?`, `compact?` | Create/update nodes (raw `NodeChangeEvent`/edge events). Every event property is described on the tool's own `events[]` schema — read that rather than this skill when all you need is the event shape. `autoConnect: false` places freshly-created nodes without wiring them to their own/previous-column neighbors (avoids a stray nearest-left edge); `compact: true` returns `{persisted: <count>}` instead of the per-node hash map | §3 `POST .../nodes/events` |
|
|
28
|
+
| `submit_node_events` | `boardId`, `events[]`, `autoConnect?`, `compact?` | Create/update nodes (raw `NodeChangeEvent`/edge events). Every event property is described on the tool's own `events[]` schema — read that rather than this skill when all you need is the event shape. An event needs its own `id` (required — a fresh uuid per event, never the node id) and its `eventType`, plus the keys of its kind (`nodeId`/`meta`/`node`, or `edgeId`/`source`/`target`). The `id` keys the returned `hashes` map and makes a resubmit idempotent — the same event sent twice under one id writes a single board event. Don't send `boardId` or `timestamp` per event — the server takes the board from the call and stamps the time itself, and ignores both if sent. `autoConnect: false` places freshly-created nodes without wiring them to their own/previous-column neighbors (avoids a stray nearest-left edge); `compact: true` returns `{persisted: <count>}` instead of the per-node hash map | §3 `POST .../nodes/events` |
|
|
29
29
|
| `delete_node` | `boardId`, `nodeId` | Delete a node. Deleting a chapter (timeline) cascades — every node placed in one of its cells, plus any node parented to it (e.g. SLICE_BORDER), is deleted too, along with all their edges | (via `node:deleted` event, §3) |
|
|
30
30
|
| `create_drawing` / `create_drawings` | `boardId`, `kind`, `x`, `y`, `width`, `height`, ... (plural: `drawings[]`) | Freehand canvas annotation (path/rect/text/sticky) — never placed in a cell. Use the plural form whenever an annotation is more than one stroke (a loop plus its arrows and label is one annotation, not three calls) | — (REST `POST .../drawing/draw` accepts a single drawing or an array) |
|
|
31
31
|
| `find_nodes_in_drawing` | `boardId`, `drawingId` | Nodes fully contained inside a drawing's bounding box | — (no REST equivalent; MCP-only) |
|
|
@@ -48,7 +48,7 @@ Server name: `eventmodelers`. Every tool takes `boardId` explicitly; none need `
|
|
|
48
48
|
| `update_slice_status` | `boardId`, `newStatus`, plus exactly one of `sliceId` / `sliceTitle` / `columnId` | Change a SLICE_BORDER's `sliceStatus`. With a title or column id there is no need to call `list_slices` first; an ambiguous title comes back with its candidates. A slice being created takes its status from `create_slice`/`create_slice_definition` instead | — (via `node:changed` event, §3) |
|
|
49
49
|
| `get_slice_data` | `boardId`, `contextName?`, `contextId?`, `sliceId?` | Full element graph for slices in a context | §8 `GET /slicedata` |
|
|
50
50
|
| `get_spec_info` | `boardId`, `timelineId`, `elementTypes?` | EVENT/COMMAND/READMODEL nodes valid in GWT steps. Pass `elementTypes` (subset of `EVENT`/`COMMAND`/`READMODEL`) to avoid pulling the full element list when only one or two types are needed — filtered server-side, not just after a full fetch | §6 `GET .../spec-info` |
|
|
51
|
-
| `get_board_outline` | `boardId`, `chapterId` | One chapter's structure, compact: per-column node lists (`{id, type, title, lane}`) + a flat edge list, no HTML pages / field bodies / meta. The cheap "what is where and how is it wired" read — prefer over `get_nodes` (no projection) for orientation checks | — (MCP-only convenience) |
|
|
51
|
+
| `get_board_outline` | `boardId`, `chapterId` | One chapter's structure, compact: per-column node lists (`{id, type, title, lane, cellName}`) + a flat edge list, no HTML pages / field bodies / meta. `cellName` is each node's real cell address (column letter + row number) — the one read that gives you every address in a chapter at once. The cheap "what is where and how is it wired" read — prefer over `get_nodes` (no projection) for orientation checks | — (MCP-only convenience) |
|
|
52
52
|
| `get_connected_nodes` | `boardId`, `nodeId`, `chapterId?`, `direction?` (`inbound`/`outbound`/`both`), `depth?`, `types?`, `includeFields?` | Neighbours of **one** node — what feeds it and what it feeds. Answers from a single anchor, unlike `get_attribute_chain` (which needs both ends of the chain as cell names up front). `depth` follows a whole chain; `types` filters the result only, never the traversal. Each neighbour carries `via`: `"edge"` for a real connection, `"layout"` when the node has none in that direction and the neighbour was inferred from the grid using auto-connect's own window (own column + adjacent one, forward-only pairs). Real edges always win. The `layout` fallback is what makes hand-built/imported chapters — which routinely carry **zero** edges — readable instead of falsely empty | — (MCP-only convenience) |
|
|
53
53
|
| `validate_model` | `boardId`, `chapterId`, `checks?[]` | Server-side Event Modeling structural checklist over one chapter — compact `findings` only. Checks: unplaced nodes, backward arrows (with the todo-list `EVENT→READMODEL` exception), zero/multi-issuer commands, sourceless read models, two-screens-in-a-column, missing scenarios. Replaces the manual per-type `get_nodes` + `get_node projection=edges` validation pass | — (MCP-only convenience) |
|
|
54
54
|
| `add_scenario` | `boardId`, `timelineId`, `columnId`, `scenarios[]`, `compact?` | Append GWT scenario(s) to a column's spec node — created automatically, and a scenario `id` is generated when omitted. A given/when/then step may be addressed by `{title, type}` instead of a node id, resolved against that timeline, so no `get_spec_info` call is needed first (an ambiguous title is reported with its candidates). `compact: true` returns `{specNodeId, added, scenarioCount, isNewNode}` instead of echoing every scenario back | §6 `POST .../scenarios` |
|
|
@@ -61,7 +61,7 @@ Server name: `eventmodelers`. Every tool takes `boardId` explicitly; none need `
|
|
|
61
61
|
| `create_screen` | `boardId`, `contentType` (`'image'\|'sketch'\|'html'`), `nodeId?`, `chapterId`, `cellId?`/`cellName?`, plus content fields (`imageBase64`/`mimeType`, `elements[]`, or `pages[]`/`backgroundColor`), `title?`, `description?`, `fields?`, `autoConnect?` | Create + place a new screen node (SCREEN or HTML_SCREEN) atomically, in one call. `title` names the node (`meta.title`) in the same call — no follow-up `node:changed` just to label the screen; `create_screens` takes it per entry. Batch form `create_screens` takes `screens[]` (HTML only) + `autoConnect?`. `autoConnect: false` places without wiring to timeline neighbors | §4 `POST .../images/:id/sketch` + `image-nodes` |
|
|
62
62
|
| `render_screen` | `boardId`, `nodeId`, `elements[]?` (SCREEN) or `pages[]?`+`backgroundColor?` (HTML_SCREEN), `description?` | Update an existing screen's content — exactly one of `elements`/`pages` | §4 `POST .../images/:id/sketch` + `image-nodes` |
|
|
63
63
|
| `add_field_examples` | `boardId`, `nodeId?`, `name?`, `cellName?`, `timelineId?` | Fill empty field examples using linked-node context | — (MCP-only convenience) |
|
|
64
|
-
| `get_attribute_chain` | `boardId`, `timelineId`, `targetCellName`, `sourceCellName` | Resolve every node between two cells, ordered target→source | — (MCP-only convenience) |
|
|
64
|
+
| `get_attribute_chain` | `boardId`, `timelineId`, `targetCellName`, `sourceCellName` | Resolve every node between two cells, ordered target→source. Both cell names must come from a node's reported `cellName` (`get_board_outline`, `get_nodes`, `get_node`) — a guessed address that happens to exist silently resolves the wrong chain | — (MCP-only convenience) |
|
|
65
65
|
| `verify_screen` | `boardId`, `nodeId` | Check a screen node exists and has rendered content — works for both SCREEN and HTML_SCREEN, dispatching on the node's actual type | — (MCP-only convenience) |
|
|
66
66
|
| `get_image_snapshot_description` | `boardId`, `nodeId` | Load the `{elements:[...]}` sketch description from storage | — (reads what §4 sketch endpoints write) |
|
|
67
67
|
| `validate_slice_data` | `sliceData` | Offline validation of a `SliceDataOutput` payload — no board access | — (MCP-only, pure function) |
|
|
@@ -337,8 +337,6 @@ Place a free-text markdown note in that lane the same way any other node is plac
|
|
|
337
337
|
"id": "<event-uuid>",
|
|
338
338
|
"eventType": "node:created",
|
|
339
339
|
"nodeId": "<node-uuid>",
|
|
340
|
-
"boardId": "<boardId>",
|
|
341
|
-
"timestamp": 1234567890,
|
|
342
340
|
"chapterId": "<chapterId>",
|
|
343
341
|
"cellId": "<feedbackRowId>-<columnId>",
|
|
344
342
|
"meta": {
|
|
@@ -370,13 +368,16 @@ A `node:deleted` event cascades: if the deleted node is a chapter (timeline), ev
|
|
|
370
368
|
|
|
371
369
|
**Request body**: `NodeChangeEvent[]`
|
|
372
370
|
|
|
371
|
+
Every event carries its own `id` — **required**, a fresh uuid per event and never the node id. An event without one is rejected (`400`, invalid event shape). It keys the response's `hashes` map, and it is what makes a resubmit safe: the board-event insert ignores a conflicting id, so the same batch sent twice writes one history row per event rather than two.
|
|
372
|
+
|
|
373
|
+
Don't send `boardId` or `timestamp` per event: the board is the path's (the one this request was authorized for) and the timestamp is the server's. Both are ignored if sent — older payloads that include them still work.
|
|
374
|
+
|
|
373
375
|
```typescript
|
|
374
376
|
interface NodeChangeEvent {
|
|
375
|
-
id: string // uuid
|
|
377
|
+
id: string // required — fresh uuid per event, NOT the node id; keys the response's hashes map
|
|
376
378
|
eventType: 'node:created' | 'node:changed' | 'node:deleted'
|
|
377
379
|
nodeId: string
|
|
378
|
-
boardId:
|
|
379
|
-
timestamp: number // unix ms
|
|
380
|
+
// boardId / timestamp: don't send them — server-derived, ignored if present
|
|
380
381
|
userId?: string
|
|
381
382
|
hash?: string // content hash
|
|
382
383
|
changedAttributes?: string[] // dot-paths e.g. 'meta.title'
|
|
@@ -128,8 +128,6 @@ curl -s -X POST "<BASE_URL>/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/events" \
|
|
|
128
128
|
"id": "<new-random-uuid>",
|
|
129
129
|
"eventType": "node:changed",
|
|
130
130
|
"nodeId": "<SLICE_NODE_ID>",
|
|
131
|
-
"boardId": "<BOARD_ID>",
|
|
132
|
-
"timestamp": <Date.now()>,
|
|
133
131
|
"changedAttributes": ["sliceStatus"],
|
|
134
132
|
"meta": {
|
|
135
133
|
"sliceStatus": "Blocked"
|
|
@@ -89,8 +89,6 @@ curl -s -X POST "<BASE_URL>/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/events" \
|
|
|
89
89
|
"id": "<new-random-uuid>",
|
|
90
90
|
"eventType": "node:changed",
|
|
91
91
|
"nodeId": "<SLICE_NODE_ID>",
|
|
92
|
-
"boardId": "<BOARD_ID>",
|
|
93
|
-
"timestamp": <Date.now()>,
|
|
94
92
|
"changedAttributes": ["sliceStatus"],
|
|
95
93
|
"meta": {
|
|
96
94
|
"sliceStatus": "<newStatus>"
|
|
@@ -42,6 +42,8 @@ mcp__eventmodelers__get_attribute_chain {
|
|
|
42
42
|
|
|
43
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
44
|
|
|
45
|
+
**Both cell names must be real.** When the task named a node (an id, a title, a comment on it) instead of a cell, read that node's `cellName` off `get_board_outline` (every node in the chapter, with its address), `get_nodes`, or `get_node` — all three report it. Never compute an address from where a node appeared in a list, and never hand `get_attribute_chain` an address you have not read: a cell that exists but holds a different node resolves a wrong chain without any error.
|
|
46
|
+
|
|
45
47
|
### Fallback (no MCP) — resolve both cells to nodes
|
|
46
48
|
|
|
47
49
|
For each cell (target and source), resolve it to a node using the exact same cell-resolution steps as the `examples` skill's "2c — Cell name" section (fetch chapters, fetch the chapter fresh to decode the grid, decode the cell name into a `CELL_ID`, then always fetch the cell live — `get_nodes` has no `cellId` filter) — see there for the full mechanics, substituting `x-user-id: attributes-skill`.
|
|
@@ -149,8 +151,6 @@ mcp__eventmodelers__submit_node_events {
|
|
|
149
151
|
"id": "<uuid>",
|
|
150
152
|
"eventType": "node:changed",
|
|
151
153
|
"nodeId": "<NODE_ID_1>",
|
|
152
|
-
"boardId": "$BOARD_ID",
|
|
153
|
-
"timestamp": <epoch-ms>,
|
|
154
154
|
"changedAttributes": ["meta.fields"],
|
|
155
155
|
"meta": { "fields": "<updated_fields_array_1>" }
|
|
156
156
|
},
|
|
@@ -15,13 +15,11 @@ Build the payload with Python to avoid JSON escaping issues, then POST it:
|
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
17
|
python3 - <<EOF > /tmp/attributes_payload.json
|
|
18
|
-
import json,
|
|
18
|
+
import json, uuid
|
|
19
19
|
payload = [{
|
|
20
20
|
"id": str(uuid.uuid4()),
|
|
21
21
|
"eventType": "node:changed",
|
|
22
22
|
"nodeId": "<NODE_ID>",
|
|
23
|
-
"boardId": "<BOARD_ID>",
|
|
24
|
-
"timestamp": int(time.time() * 1000),
|
|
25
23
|
"changedAttributes": ["meta.fields"],
|
|
26
24
|
"meta": {
|
|
27
25
|
"fields": <updated_fields_as_python_list>
|
|
@@ -232,8 +232,6 @@ mcp__eventmodelers__submit_node_events {
|
|
|
232
232
|
"id": "<uuid>",
|
|
233
233
|
"eventType": "node:changed",
|
|
234
234
|
"nodeId": "<CHAPTER_ID>",
|
|
235
|
-
"boardId": "<BOARD_ID>",
|
|
236
|
-
"timestamp": <NOW_MS>,
|
|
237
235
|
"changedAttributes": ["meta.title"],
|
|
238
236
|
"meta": { "type": "CHAPTER", "title": "<flow name>" },
|
|
239
237
|
"node": { "id": "<CHAPTER_ID>", "data": {} }
|
package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/references/api-fallback.md
CHANGED
|
@@ -22,8 +22,6 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
|
|
|
22
22
|
"id": "<uuid>",
|
|
23
23
|
"eventType": "node:changed",
|
|
24
24
|
"nodeId": "<CHAPTER_ID>",
|
|
25
|
-
"boardId": "<BOARD_ID>",
|
|
26
|
-
"timestamp": <NOW_MS>,
|
|
27
25
|
"changedAttributes": ["meta.title"],
|
|
28
26
|
"meta": { "type": "CHAPTER", "title": "<flow name>" },
|
|
29
27
|
"node": { "id": "<CHAPTER_ID>", "data": {} }
|
package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/SKILL.md
CHANGED
|
@@ -107,8 +107,6 @@ mcp__eventmodelers__submit_node_events {
|
|
|
107
107
|
"id": "<uuid>",
|
|
108
108
|
"eventType": "node:changed",
|
|
109
109
|
"nodeId": "<chapterId>",
|
|
110
|
-
"boardId": "<BOARD_ID>",
|
|
111
|
-
"timestamp": 1234567890,
|
|
112
110
|
"meta": {"type": "CHAPTER", "title": "Reservation & Lending"}
|
|
113
111
|
}]
|
|
114
112
|
}
|
|
@@ -200,8 +198,6 @@ mcp__eventmodelers__submit_node_events {
|
|
|
200
198
|
"id": "<event-uuid>",
|
|
201
199
|
"eventType": "node:created",
|
|
202
200
|
"nodeId": "<node-uuid>",
|
|
203
|
-
"boardId": "<BOARD_ID>",
|
|
204
|
-
"timestamp": 1234567890,
|
|
205
201
|
"chapterId": "<chapterId>",
|
|
206
202
|
"cellId": "<swimlaneRowId>-<columnId>",
|
|
207
203
|
"meta": {
|
|
@@ -35,8 +35,6 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
|
|
|
35
35
|
"id": "<uuid>",
|
|
36
36
|
"eventType": "node:changed",
|
|
37
37
|
"nodeId": "<chapterId>",
|
|
38
|
-
"boardId": "<boardId>",
|
|
39
|
-
"timestamp": 1234567890,
|
|
40
38
|
"meta": {"type": "CHAPTER", "title": "Reservation & Lending"}
|
|
41
39
|
}]'
|
|
42
40
|
```
|
|
@@ -78,8 +76,6 @@ Same body via `POST .../nodes/events`:
|
|
|
78
76
|
"id": "<event-uuid>",
|
|
79
77
|
"eventType": "node:created",
|
|
80
78
|
"nodeId": "<node-uuid>",
|
|
81
|
-
"boardId": "<boardId>",
|
|
82
|
-
"timestamp": 1234567890,
|
|
83
79
|
"chapterId": "<chapterId>",
|
|
84
80
|
"cellId": "<swimlaneRowId>-<columnId>",
|
|
85
81
|
"meta": {
|
|
@@ -95,7 +95,6 @@ mcp__eventmodelers__submit_node_events {
|
|
|
95
95
|
"boardId": "<BOARD_ID>",
|
|
96
96
|
"events": [{
|
|
97
97
|
"id": "<event-uuid>", "eventType": "node:changed", "nodeId": "<returned-node-id>",
|
|
98
|
-
"boardId": "<BOARD_ID>", "timestamp": 1234567890,
|
|
99
98
|
"meta": {"type": "READMODEL", "title": "NotificationsToSend", "fields": [...], "listElement": true}
|
|
100
99
|
}]
|
|
101
100
|
}
|
|
@@ -14,7 +14,6 @@ Only needed when MCP is not connected. Every call below has an MCP equivalent in
|
|
|
14
14
|
-H "Content-Type: application/json" \
|
|
15
15
|
-d '[{
|
|
16
16
|
"id":"<event-uuid>","eventType":"node:created","nodeId":"<node-uuid>",
|
|
17
|
-
"boardId":"<BOARD_ID>","timestamp":1234567890,
|
|
18
17
|
"chapterId":"<CHAPTER_ID>","cellId":"<interactionRowId>-<columnId>",
|
|
19
18
|
"meta":{"type":"READMODEL","title":"NotificationsToSend","fields":[...]}
|
|
20
19
|
}]'
|
package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/SKILL.md
CHANGED
|
@@ -160,8 +160,6 @@ mcp__eventmodelers__submit_node_events {
|
|
|
160
160
|
"id": "<event-uuid>",
|
|
161
161
|
"eventType": "node:changed",
|
|
162
162
|
"nodeId": "<returned-node-id>",
|
|
163
|
-
"boardId": "<BOARD_ID>",
|
|
164
|
-
"timestamp": 1234567890,
|
|
165
163
|
"meta": {
|
|
166
164
|
"type": "COMMAND",
|
|
167
165
|
"title": "ReserveBike",
|
|
@@ -34,8 +34,6 @@ curl -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
|
|
|
34
34
|
"id": "<event-uuid>",
|
|
35
35
|
"eventType": "node:created",
|
|
36
36
|
"nodeId": "<node-uuid>",
|
|
37
|
-
"boardId": "<boardId>",
|
|
38
|
-
"timestamp": 1234567890,
|
|
39
37
|
"chapterId": "<chapterId>",
|
|
40
38
|
"cellId": "<interactionRowId>-<columnId>",
|
|
41
39
|
"meta": {
|
package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/SKILL.md
CHANGED
|
@@ -267,7 +267,6 @@ mcp__eventmodelers__submit_node_events {
|
|
|
267
267
|
"boardId": "<BOARD_ID>",
|
|
268
268
|
"events": [{
|
|
269
269
|
"id": "<event-uuid>", "eventType": "node:changed", "nodeId": "<returned-node-id>",
|
|
270
|
-
"boardId": "<BOARD_ID>", "timestamp": 1234567890,
|
|
271
270
|
"meta": {"type": "READMODEL", "title": "ActiveReservationView", "fields": [...]}
|
|
272
271
|
}]
|
|
273
272
|
}
|
|
@@ -26,8 +26,6 @@ Only needed when MCP is not connected. Every call below has an MCP equivalent in
|
|
|
26
26
|
"id": "<event-uuid>",
|
|
27
27
|
"eventType": "node:created",
|
|
28
28
|
"nodeId": "<node-uuid>",
|
|
29
|
-
"boardId": "<BOARD_ID>",
|
|
30
|
-
"timestamp": 1234567890,
|
|
31
29
|
"chapterId": "<CHAPTER_ID>",
|
|
32
30
|
"cellId": "<interactionRowId>-<columnId>",
|
|
33
31
|
"meta": {"type": "READMODEL", "title": "ActiveReservationView", "fields": [...]}
|
|
@@ -431,7 +431,6 @@ Not delegated to a separate skill — performed directly by this orchestrating s
|
|
|
431
431
|
"boardId": "$BOARD_ID",
|
|
432
432
|
"events": [{
|
|
433
433
|
"id": "<event-uuid>", "eventType": "node:created", "nodeId": "<node-uuid>",
|
|
434
|
-
"boardId": "$BOARD_ID", "timestamp": 1234567890,
|
|
435
434
|
"chapterId": "$CHAPTER_ID", "cellId": "<feedbackLaneId>-<firstColumnId>",
|
|
436
435
|
"meta": { "type": "MARKDOWN", "title": "Modeling Reasoning — <Chapter Name>", "description": "<full markdown body>" }
|
|
437
436
|
}]
|
|
@@ -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>",
|
|
21
|
-
"
|
|
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>",
|
|
49
|
-
"
|
|
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
|
```
|
package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/SKILL.md
CHANGED
|
@@ -256,8 +256,6 @@ mcp__eventmodelers__submit_node_events {
|
|
|
256
256
|
"id": "<event-uuid>",
|
|
257
257
|
"eventType": "node:created",
|
|
258
258
|
"nodeId": "<node-uuid>",
|
|
259
|
-
"boardId": "<BOARD_ID>",
|
|
260
|
-
"timestamp": 1234567890,
|
|
261
259
|
"chapterId": "<CHAPTER_ID>",
|
|
262
260
|
"cellId": "<actorRowId>-<columnId>",
|
|
263
261
|
"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,
|
|
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>
|
|
@@ -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>",
|
|
@@ -174,7 +173,6 @@ mcp__eventmodelers__submit_node_events {
|
|
|
174
173
|
"boardId": "<BOARD_ID>",
|
|
175
174
|
"events": [{
|
|
176
175
|
"id": "<event-uuid>", "eventType": "node:changed", "nodeId": "<NODE_ID>",
|
|
177
|
-
"boardId": "<BOARD_ID>", "timestamp": <NOW_MS>,
|
|
178
176
|
"changedAttributes": ["meta.fields"],
|
|
179
177
|
"meta": { "type": "HTML_SCREEN", "fields": [
|
|
180
178
|
{"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"}
|
|
@@ -321,10 +321,9 @@ This step applies to `SCREEN` (view/output conflict case), `AUTOMATION`, `SCENAR
|
|
|
321
321
|
mcp__eventmodelers__submit_node_events {
|
|
322
322
|
"boardId": "<BOARD_ID>",
|
|
323
323
|
"events": [{
|
|
324
|
+
"id": "<event-uuid>",
|
|
324
325
|
"eventType": "node:created",
|
|
325
326
|
"nodeId": "<node-uuid>",
|
|
326
|
-
"boardId": "<BOARD_ID>",
|
|
327
|
-
"timestamp": <Date.now()>,
|
|
328
327
|
"chapterId": "<TIMELINE_ID>",
|
|
329
328
|
"cellId": "<CELL_ID>",
|
|
330
329
|
"meta": { "type": "<ELEMENT_TYPE>", "title": "<title>" },
|
|
@@ -343,10 +342,9 @@ mcp__eventmodelers__submit_node_events {
|
|
|
343
342
|
mcp__eventmodelers__submit_node_events {
|
|
344
343
|
"boardId": "<BOARD_ID>",
|
|
345
344
|
"events": [{
|
|
345
|
+
"id": "<event-uuid>",
|
|
346
346
|
"eventType": "node:created",
|
|
347
347
|
"nodeId": "<node-uuid>",
|
|
348
|
-
"boardId": "<BOARD_ID>",
|
|
349
|
-
"timestamp": <Date.now()>,
|
|
350
348
|
"chapterId": "<TIMELINE_ID>",
|
|
351
349
|
"cellName": "<CELL_NAME>",
|
|
352
350
|
"meta": { "type": "<ELEMENT_TYPE>", "title": "<title>" },
|
|
@@ -357,7 +355,7 @@ mcp__eventmodelers__submit_node_events {
|
|
|
357
355
|
|
|
358
356
|
**Fallback (no MCP):** see `references/api-fallback.md` — "Step 7b — Create any other node type (fast path, `cellName`)".
|
|
359
357
|
|
|
360
|
-
Response: `{ "hashes": { "<event-
|
|
358
|
+
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
359
|
|
|
362
360
|
> **`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
361
|
|
package/stacks/modeling-kit/templates/.claude/skills/place-element/references/api-fallback.md
CHANGED
|
@@ -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,7 +160,7 @@ 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-
|
|
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
|
|
|
@@ -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
|
|
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.
|
|
@@ -224,7 +224,6 @@ mcp__eventmodelers__submit_node_events {
|
|
|
224
224
|
"boardId": "<BOARD_ID>",
|
|
225
225
|
"events": [{
|
|
226
226
|
"id": "<event-uuid>", "eventType": "node:changed", "nodeId": "<SCREEN_NODE_ID>",
|
|
227
|
-
"boardId": "<BOARD_ID>", "timestamp": <NOW_MS>,
|
|
228
227
|
"changedAttributes": ["meta.fields"],
|
|
229
228
|
"meta": { "type": "HTML_SCREEN", "fields": [ /* planned fields */ ] }
|
|
230
229
|
}]
|
|
@@ -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"}
|
package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/references/api-fallback.md
CHANGED
|
@@ -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"}
|
|
@@ -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>" },
|
|
@@ -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": {} }
|
|
@@ -48,8 +48,6 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
|
|
|
48
48
|
"id": "<event-uuid>",
|
|
49
49
|
"eventType": "node:created",
|
|
50
50
|
"nodeId": "<node-uuid>",
|
|
51
|
-
"boardId": "<BOARD_ID>",
|
|
52
|
-
"timestamp": <Date.now()>,
|
|
53
51
|
"chapterId": "<CHAPTER_ID>",
|
|
54
52
|
"cellId": "<CELL_ID>",
|
|
55
53
|
"meta": { "type": "EVENT", "title": "<EventName>" },
|
|
@@ -67,8 +65,6 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
|
|
|
67
65
|
"id": "<new-uuid>",
|
|
68
66
|
"eventType": "node:changed",
|
|
69
67
|
"nodeId": "<eventNodeId>",
|
|
70
|
-
"boardId": "<BOARD_ID>",
|
|
71
|
-
"timestamp": <Date.now()>,
|
|
72
68
|
"changedAttributes": ["meta.title"],
|
|
73
69
|
"meta": { "type": "EVENT", "title": "<NewTitle>" },
|
|
74
70
|
"node": { "id": "<eventNodeId>", "data": {} }
|
|
@@ -84,8 +80,6 @@ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
|
|
|
84
80
|
-d '[{
|
|
85
81
|
"id": "<new-uuid>",
|
|
86
82
|
"eventType": "node:deleted",
|
|
87
|
-
"nodeId": "<eventNodeId>"
|
|
88
|
-
"boardId": "<BOARD_ID>",
|
|
89
|
-
"timestamp": <Date.now()>
|
|
83
|
+
"nodeId": "<eventNodeId>"
|
|
90
84
|
}]'
|
|
91
85
|
```
|
|
@@ -14,9 +14,10 @@ ones in a compressed, reusable form; only add if not already covered here.
|
|
|
14
14
|
- `/update-slice-status` rejects moving a slice into a status it's already in — this is a concurrency guard so two agents can't both claim the same slice. Treat this as `ALREADY_IN_STATUS`, not a task failure: drop the prompt, move on to the next task, and do not retry the same update.
|
|
15
15
|
- macOS/BSD `date` silently ignores GNU-only format specifiers like `%N`/`%3N` (sub-second precision) instead of erroring — it prints the literal characters, producing a malformed timestamp that only fails downstream. Don't shell out to `date` for sub-second precision; use `$(( $(date +%s) * 1000 ))` for whole-second-in-ms, or a runtime call (`Date.now()`, `process.hrtime()`) instead.
|
|
16
16
|
- Before retrying a failed shell command a second time, diagnose why it failed (e.g. a GNU/BSD flag mismatch) rather than re-running it unchanged — repeating the same command produces the same failure and just burns retries.
|
|
17
|
+
- A cell address (`B2`, `AE6`) is always read, never computed: `get_board_outline`, `get_nodes` and `get_node` each report a node's `cellName`. An address inferred from a column letter plus a node's place in a list is a guess, and a guess that happens to name an occupied cell is accepted silently by every cell-addressed tool.
|
|
17
18
|
- Orientation and working set are two different reads, in that order: `get_board_outline` (or `get_nodes` with `projection: "line"`) answers *where is the work*, and only then does one full-`meta` `get_nodes`, scoped by `chapterId`/`nodeIds`, cover the nodes actually being touched. Opening with an unscoped full-`meta` read pulls every field body and rendered HTML page on the board to answer the cheapest question of the turn.
|
|
18
19
|
- Both reads are once per turn. A chapter's outline and grid don't move unless something writes to them, so re-read only after a structural write. Three `get_board_outline` calls in one turn means the first two were thrown away.
|
|
19
|
-
- Mint ids
|
|
20
|
+
- Mint ids once per turn, in one shell: `for i in $(seq <n>); do uuidgen; done` — one per new node, plus one per event, since every event needs its own fresh `id` (required; not the node id). Nothing in it depends on anything being read, so splitting it across several calls buys round trips for nothing. Never mint a per-event `boardId` or `timestamp` — both are server-derived and ignored if sent.
|
|
20
21
|
- A subagent is a fresh session: it gets `token=`/`org=`/`baseUrl=`/`board=` inline as already-resolved values (which satisfies `connect` at its Step 0 — tell it not to invoke `/connect`) plus the board state already read for it, inline. Handed bare node ids instead, it has exactly one way to recover the rest — re-reading the whole board, once per agent.
|
|
21
22
|
- Dispatch executor agents with `model:` set to the session header's `subagent_model` (default `sonnet`). The judging happened before the dispatch, on this session's model; what's left is execution against a written brief. Keep an agent on the session model only where its piece re-derives modeling structure (a chain's shape, a slice boundary).
|
|
22
23
|
- Only slices in status `Created` may be modified. `get_nodes` returns `sliceStatus` per node and `get_board_outline` per column, so the board read at `/connect` Step 5 already answers it — absent means the element is in no slice (writable), not locked. Never spend a `list_slices`/`get_slice_data` call just to check whether you may write.
|
|
@@ -96,7 +96,7 @@ stale. Then a single full-`meta` `get_nodes`, scoped by
|
|
|
96
96
|
`chapterId` or `nodeIds`, covering the nodes you concluded you will touch. Both tiers are once per turn: keep what
|
|
97
97
|
came back and answer later questions from it instead of re-fetching a chapter you already hold. `/connect` Step 5
|
|
98
98
|
carries the full discipline — the two tiers, the one-call `submit_node_events` rule for writes, and the per-turn
|
|
99
|
-
pool for the ids
|
|
99
|
+
pool for the ids a `node:created` needs (one for the node, one for the event itself). Whatever you hand a subagent comes out of that same read,
|
|
100
100
|
never out of a second one it pays for itself (step 2).
|
|
101
101
|
|
|
102
102
|
**Every prompt gets exactly two `/update-prompt-status` calls per turn — never zero, never one.** `IN_PROGRESS` before you start the work (step 4), `DONE` after you finish it (step 6). This holds even for a prompt that turns out to be trivial or a no-op — the board UI has no other way to know the agent picked it up and finished it.
|