@eventmodelers/cli 1.0.125 → 1.0.127
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 +1 -1
- package/package.json +1 -1
- package/shared/skills/learn-eventmodelers-api/SKILL.md +20 -15
- package/stacks/modeling-kit/templates/.claude/skills/examples/SKILL.md +1 -1
- package/stacks/modeling-kit/templates/.claude/skills/walkthrough/SKILL.md +66 -40
- package/stacks/modeling-kit/templates/kit/CLAUDE.md +3 -3
package/README.md
CHANGED
|
@@ -106,7 +106,7 @@ Use skills in Claude Code with `/skill-name`:
|
|
|
106
106
|
| `/connect` | Set up board connection |
|
|
107
107
|
| `/timeline` | Live event storming facilitator |
|
|
108
108
|
| `/wdyt` | Business analyst review of your event model |
|
|
109
|
-
| `/walkthrough` |
|
|
109
|
+
| `/walkthrough` | Slice-by-slice player through a feature, or through every slice a planned feature needs (existing, to adjust, new) |
|
|
110
110
|
| `/storyboard` | Build a full visual storyboard |
|
|
111
111
|
| `/html-screen` | Design individual real HTML/CSS screens (default) |
|
|
112
112
|
| `/storyboard-screen` | Design individual wireframe/sketch screens (explicit request only) |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eventmodelers/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.127",
|
|
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": {
|
|
@@ -26,7 +26,7 @@ Write tools take their items as an array (`nodeIds[]`, `elements[]`, `connection
|
|
|
26
26
|
| Tool | Args | Purpose | REST equivalent |
|
|
27
27
|
|---|---|---|---|
|
|
28
28
|
| `list_boards` | — | List boards for the org | §1 `GET /api/boards` (org-scoped) |
|
|
29
|
-
| `get_nodes` | `boardId`, `type?`, `name?`, `chapterId?`, `nodeIds?`, `projection?` (`"line"`) | List nodes, optionally by type and/or a partial case-insensitive title match. **Unscoped with full `meta` it is expensive** — about 2 KB per node, ~1 MB on a 500-node board — so always pass a filter or
|
|
29
|
+
| `get_nodes` | `boardId`, `type?`, `name?`, `chapterId?`, `nodeIds?`, `projection?` (`"line"` \| `"fields"`) | List nodes, optionally by type and/or a partial case-insensitive title match. **Unscoped with full `meta` it is expensive** — about 2 KB per node, ~1 MB on a 500-node board — so always pass a filter or a projection. `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, fields}` — `fields` being just the attribute names; `projection: "fields"` to `{id, type, title, parentId, fields}` with the full field definitions (type, example, idAttribute, …) but no html, description, sketch or grid data. No `cellName` — an existing node is addressed by its `id`; when a cell address is needed (placing into a cell), read it from `get_board_outline`. No `sliceStatus` — take it per column from `get_board_outline` | §3 `GET .../nodes` (REST records carry no `cellName`, `projection=line`/`fields` included) |
|
|
30
30
|
| `get_node` | `boardId`, `nodeId`, `projection?` (`"cells"` \| `"edges"`) | Get one node (no `cellName` — address it by `nodeId`; cell addresses come only from `get_board_outline`). `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. An unknown id is a `NODE_NOT_FOUND` error | §3 `GET .../nodes/:nodeId` (REST returns the node as stored, without `cellName`; `404` carries `code: 'NODE_NOT_FOUND'`) |
|
|
31
31
|
| `get_node_comments` | `boardId`, `nodeId` | List comments on a node | §1 `GET .../nodes/:nodeId/comments` |
|
|
32
32
|
| `get_chat_attachment` | `boardId`, `sessionId`, `attachmentId` | The file a chat message came with — the message's `attachments` list `{id, type, ending}`. Images come back as images, a PDF as an embedded resource, csv / xml / txt / json as text. Only the agent the message was addressed to can read it (`CHAT_ATTACHMENT_NOT_FOUND`); needs the connection's `x-agent-id` (`CHAT_AGENT_REQUIRED`). Max 5 MB per file. | §15 `GET /api/org/:orgId/chat/sessions/:sessionId/attachments/:attachmentId` |
|
|
@@ -83,13 +83,14 @@ Pick the cheapest read that answers the step's question, and name the reason in
|
|
|
83
83
|
| a chapter's grid / cell occupancy | `get_node { nodeId: <chapterId>, projection: "cells" }` |
|
|
84
84
|
| one node's connections | `get_node { nodeId, projection: "edges" }` |
|
|
85
85
|
| what is where in a chapter (incl. cell names for placement), plus `sliceStatus` per column | `get_board_outline` |
|
|
86
|
-
| field types, examples, descriptions
|
|
86
|
+
| field types, examples, field descriptions | `get_nodes` with `projection: "fields"`, scoped by `chapterId` or `nodeIds` |
|
|
87
|
+
| a node's description, position, HTML | full `get_nodes`, scoped by `chapterId` or `nodeIds` — never board-wide when avoidable |
|
|
87
88
|
| finding slices / their elements / element counts | `get_slice_data` with `projection: "outline"` (format `json`/`yaml`/`toon`) |
|
|
88
89
|
| attribute, field-flow or completeness work | `get_slice_data` with `projection: "fields"` |
|
|
89
90
|
| scenario / spec review, spec coverage | `get_slice_data` with `projection: "specs"` (format `json`/`yaml`/`toon`) |
|
|
90
91
|
| elements **and** specs **and** comments/prompts together (e.g. a business review) | full `get_slice_data` — say why |
|
|
91
92
|
|
|
92
|
-
Two cheap projected calls (e.g. `outline` + `specs`) beat one full call when the step doesn't need comments, prompts or field bodies. `projection: "line"` never carries `sliceStatus`, `meta`, positions, field types or examples — if a later step reads any of those, use the full read. `get_nodes { type: "CHAPTER" }` without a projection returns every chapter's full grid; to just list or pick chapters, add `projection: "line"`.
|
|
93
|
+
Two cheap projected calls (e.g. `outline` + `specs`) beat one full call when the step doesn't need comments, prompts or field bodies. `projection: "line"` never carries `sliceStatus`, `meta`, positions, field types or examples; `projection: "fields"` adds the full field definitions and `parentId`, still no `sliceStatus`, positions or node description — if a later step reads any of those, use the full read. `get_nodes { type: "CHAPTER" }` without a projection returns every chapter's full grid; to just list or pick chapters, add `projection: "line"`.
|
|
93
94
|
|
|
94
95
|
---
|
|
95
96
|
|
|
@@ -473,21 +474,21 @@ List all nodes on a board.
|
|
|
473
474
|
- `type?: ElementType` — exact match.
|
|
474
475
|
- `name?: string` — partial, case-insensitive title match.
|
|
475
476
|
- `chapterId?: string` — only nodes placed in this chapter (timeline).
|
|
476
|
-
- `projection?: "line"` — compact `{id, type, title, fields?}` per node (`fields` = attribute names only, absent on nodes without fields) instead of the full record. Neither form carries `cellName` — address existing nodes by `id`. Any other value is `400 PROJECTION_INVALID`.
|
|
477
|
+
- `projection?: "line" | "fields"` — `line`: compact `{id, type, title, fields?}` per node (`fields` = attribute names only, absent on nodes without fields); `fields`: `{id, type, title, parentId, fields?}` with the full field definitions as stored, but no html, description, sketch or grid data. Either instead of the full record. Neither form carries `cellName` — address existing nodes by `id`. Any other value is `400 PROJECTION_INVALID`.
|
|
477
478
|
- `cellId?: string` — return only the node occupying this timeline cell (format `<rowId>-<colId>`). Requires `timelineId`. Empty array if the cell is unoccupied.
|
|
478
479
|
- `colId?: string` — return every node occupying this column, across *all* rows of the timeline (e.g. to check for an existing COMMAND/READMODEL/SCREEN/AUTOMATION before placing one, since the server caps those at one per column even across separate lane rows). Requires `timelineId`. Combine with `type` to narrow to one element type.
|
|
479
480
|
- `timelineId?: string` — the CHAPTER node `cellId`/`colId` are resolved against. Required together with either of those two; `400` if omitted.
|
|
480
481
|
|
|
481
482
|
Cell/column occupancy lives only in the CHAPTER node's `meta.timelineData.cells`, never on the node rows themselves — this endpoint resolves `cellId`/`colId` against that timeline internally so callers don't have to fetch and parse the whole chapter node just to check occupancy.
|
|
482
483
|
|
|
483
|
-
**Response**: `200` — node record array (or `line` projections). `400` — `cellId`/`colId` given without `timelineId`, `PROJECTION_INVALID`, or `QUERY_PARAM_INVALID`. `404` — `timelineId` doesn't reference an existing CHAPTER node with grid data.
|
|
484
|
+
**Response**: `200` — node record array (or `line`/`fields` projections). `400` — `cellId`/`colId` given without `timelineId`, `PROJECTION_INVALID`, or `QUERY_PARAM_INVALID`. `404` — `timelineId` doesn't reference an existing CHAPTER node with grid data.
|
|
484
485
|
|
|
485
486
|
---
|
|
486
487
|
|
|
487
488
|
### POST `/api/org/:orgId/boards/:boardId/nodes/query`
|
|
488
489
|
Fetch a known set of nodes in one call.
|
|
489
490
|
|
|
490
|
-
**Body**: `{ "ids": string[], "projection"?: "line" }` — `ids` non-empty. Missing ids are silently omitted. Without `projection`, full stored records; `line`
|
|
491
|
+
**Body**: `{ "ids": string[], "projection"?: "line" | "fields" }` — `ids` non-empty. Missing ids are silently omitted. Without `projection`, full stored records; `line`/`fields` give the shapes above. Neither carries `cellName`.
|
|
491
492
|
|
|
492
493
|
**Response**: `200` — node array. `400` — `ids` empty/not an array, or `PROJECTION_INVALID`.
|
|
493
494
|
|
|
@@ -1120,7 +1121,7 @@ Rule of thumb: if you are about to write "Shall I…?", "Want me to…?", "A or
|
|
|
1120
1121
|
| to show a picture | `image` | nothing |
|
|
1121
1122
|
| to show a command or payload | `code` | nothing |
|
|
1122
1123
|
| to show numbers as a diagram (counts per slice, a trend, shares of a whole) | `report` | nothing |
|
|
1123
|
-
| to explain how a
|
|
1124
|
+
| to explain how a feature works, or walk through what a planned feature takes, slice by slice ("how does registration work?", "we need to add an email — walk me through it") | `walkthrough` | nothing — selecting a step pans the canvas |
|
|
1124
1125
|
|
|
1125
1126
|
`confirm`, `poll`, `tasks` and `changes` are questions: a person answers once, then they show as answered. `link`, `image`, `code`, `report` and `walkthrough` are display only and never wait for anything.
|
|
1126
1127
|
|
|
@@ -1144,13 +1145,17 @@ Rule of thumb: if you are about to write "Shall I…?", "Want me to…?", "A or
|
|
|
1144
1145
|
labels: string[], // 1–50 points: x axis, or the pie slices
|
|
1145
1146
|
series: Array<{ name: string, values: number[] }>, // one number per label; bar/line up to 6 series, pie uses only the first (no negatives)
|
|
1146
1147
|
confirm?: { headline: string, yesLabel?: string, noLabel?: string } } // optional yes/no question under the diagram, like a confirm snippet
|
|
1147
|
-
{ kind: 'walkthrough', title: string,
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1148
|
+
{ kind: 'walkthrough', title: string, // a slice-by-slice player through a feature
|
|
1149
|
+
summary: string, // 1–3 sentences on how it works, shown on the first page under the slice count
|
|
1150
|
+
steps: Array<{ title: string, // 1+, one per slice, in the order the feature runs
|
|
1151
|
+
description?: string, // what happens in this slice, in business words
|
|
1152
|
+
nodeId?: string, // the slice's SLICE_BORDER — drawn in its lanes, selecting the step zooms to it; none for a new slice
|
|
1153
|
+
status?: 'existing' | 'changed' | 'new', // planned feature: used as is / needs adjustment / built from scratch
|
|
1154
|
+
elements?: Array<{ type: 'SCREEN' | 'COMMAND' | 'EVENT' | 'READMODEL' | 'AUTOMATION',
|
|
1155
|
+
title: string, fields?: string[] }>, // a new slice only: its sketch, drawn in lanes
|
|
1156
|
+
screenId?: string, // a SCREEN / HTML_SCREEN outside the slice the person sees in this step
|
|
1157
|
+
rules?: string[], // business rules of this slice
|
|
1158
|
+
changes?: string[] }> } // planned feature: what has to change or be built here
|
|
1154
1159
|
```
|
|
1155
1160
|
|
|
1156
1161
|
### How to use them
|
|
@@ -1161,7 +1166,7 @@ Rule of thumb: if you are about to write "Shall I…?", "Want me to…?", "A or
|
|
|
1161
1166
|
- **Answers are text.** For a `tasks` answer, match the titles (or ids) back to your list; an element the person left unticked was declined, not forgotten. A `poll` option with a `message` of your own makes the answer unambiguous.
|
|
1162
1167
|
- `get_chat_session` shows your snippet on the message as `snippet`, and the person's answer is the user message after it, carrying `context.snippetReply.messageId` (your message's id) — useful to tell an answer to a snippet from a new message.
|
|
1163
1168
|
- **`report`** draws the numbers you send — it computes nothing, so aggregate first. A series whose length differs from `labels`, or a non-number, makes the whole snippet invisible. Keep `text` as a one-line summary of what the diagram shows. Add `confirm` when the diagram leads to a follow-up question ("Want me to look into the backward arrows?"): the answer comes back like a `confirm` answer, and without it the report is display only.
|
|
1164
|
-
- **`walkthrough`** answers "how does X work?" and "walk me through what changes for Y"
|
|
1169
|
+
- **`walkthrough`** answers "how does X work?" and "walk me through what changes for Y", **one step per slice**. It opens with a summary page — the slice count (with `status`: how many exist, need adjustment, are new) above your `summary` — then shows each slice in its lanes like Slice View (screen, command / read model, events), a `new` slice sketched from its `elements`; each step zooms the canvas to its slice, and **Play** opens it full-screen with description, changes and rules underneath. Build it from the board, never from memory — the `walkthrough` skill (modeling kit) has the procedure. Every `nodeId`/`screenId` must be a real id from this board. Keep `text` to one line naming the feature and the number of slices.
|
|
1165
1170
|
- A snippet is shown exactly as you send it — keep secrets and tokens out of `code` and `image`.
|
|
1166
1171
|
|
|
1167
1172
|
---
|
|
@@ -37,7 +37,7 @@ with a `confirm` snippet — `CLAUDE.md` § *Locked slices in a chat* — and po
|
|
|
37
37
|
|
|
38
38
|
`target` is singular, but the common real request is "fill in the examples across this chapter". When you have more than one target, **do not run this skill once per element and do not fetch context a node at a time.**
|
|
39
39
|
|
|
40
|
-
1. Read the chapter **once**: `mcp__eventmodelers__get_nodes { "boardId": "$BOARD_ID", "chapterId": "$CHAPTER_ID" }`. That single response carries every element's `
|
|
40
|
+
1. Read the chapter **once**: `mcp__eventmodelers__get_nodes { "boardId": "$BOARD_ID", "chapterId": "$CHAPTER_ID", "projection": "fields" }`. That single response carries every element's `fields` *including the `example` values already filled in*, without the html, descriptions and grid data a full read drags along — which is exactly the canonical-value pool Step 3c asks for, for the whole chapter, in one call.
|
|
41
41
|
2. Pick the canonical value per field name from that pool (e.g. `customerId: "cust-123"`, `email: "jane@example.com"`) before writing anything, so every element ends up consistent.
|
|
42
42
|
3. Then generate every target's values and write them all in a single `submit_node_events { events: [...] }` call — one `node:changed` event per element, never one call per element.
|
|
43
43
|
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: walkthrough
|
|
3
|
-
description: Walk a person through
|
|
3
|
+
description: Walk a person through a feature slice by slice, as a player in the chat. It opens with a summary page (how many slices, how the feature works in 1–3 sentences), then one step per slice, each shown in its lanes like Slice View (screen, command / read model, events). Two modes — explain ("how does registration work?") follows the feature's slices in the order they run; impact ("we need to add an email — walk me through the changes") lists every slice a planned feature needs, marked as existing, needing adjustment or new, with new slices sketched. Each step carries a description, the business rules that apply, what changes there and a link that zooms the canvas to the slice. Read-only — changes nothing on the board.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Walkthrough —
|
|
6
|
+
# Walkthrough — slice by slice through a feature
|
|
7
7
|
|
|
8
8
|
> **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.
|
|
9
9
|
|
|
10
10
|
Prefer `mcp__eventmodelers__*` tools. See `learn-eventmodelers-api` for the curl fallback and §16 *Chat snippets* for the `walkthrough` shape.
|
|
11
11
|
|
|
12
|
-
The result is **one `walkthrough` snippet** in the chat. The
|
|
12
|
+
The result is **one `walkthrough` snippet** in the chat. **Its unit is the slice**: one step per slice, never per element. The player always opens with a **summary page** — "This feature consists of 6 slices" (for a planned feature: "…: 2 of them exist, 1 existing one needs adjustment and 3 have to be implemented from scratch"), worked out from the steps, plus your 1–3 sentence `summary` of how it works. Each step after that shows its slice the way Slice View does — the screen on top, command / read model in the next lane, events at the bottom — and a slice that doesn't exist yet is drawn as a sketch from the elements you give it. Selecting a step zooms the canvas to the slice; **Play** opens everything full-screen with the description, the changes and the rules underneath. The walkthrough is only as good as its links: every existing slice points at its real `SLICE_BORDER` on this board.
|
|
13
13
|
|
|
14
14
|
**This skill never writes to the board.** In impact mode it shows what would change; making those changes is separate work the person asks for afterwards.
|
|
15
15
|
|
|
@@ -21,11 +21,13 @@ From `$ARGUMENTS` / the message, and the turn's `context=` (selected nodes, `tim
|
|
|
21
21
|
|
|
22
22
|
| Mode | Typical message | The steps are |
|
|
23
23
|
|---|---|---|
|
|
24
|
-
| `explain` | "How does registration work?", "walk me through checkout", "/walkthrough Registration" | the
|
|
25
|
-
| `impact` | "We need to add an email — walk me through the changes", "what does it take to support refunds?" | every
|
|
24
|
+
| `explain` | "How does registration work?", "walk me through checkout", "/walkthrough Registration" | the feature's slices in the order they run, as a person experiences them |
|
|
25
|
+
| `impact` | "We need to add an email — walk me through the changes", "what does it take to support refunds?" | every slice the planned feature needs — existing ones it uses, existing ones to adjust, new ones to build — in the order they run |
|
|
26
26
|
|
|
27
27
|
The **subject** is the process or the change, in the person's words. "This"/"here" means what they have selected or zoomed to.
|
|
28
28
|
|
|
29
|
+
**Which mode** — decide by whether the subject is on the board yet, not by the phrasing. Anything the person calls *new*, *planned*, *a feature we want/need*, *support for X*, or that the board doesn't model yet (a new license type, a new field, a new flow) is **impact**, even when they say "walk me through the X feature". Only a flow that is fully modelled as it should work is **explain**. In doubt, impact — an impact walkthrough of an unchanged flow just marks every slice `existing`, while an explain walkthrough of a planned feature hides which slices are new.
|
|
30
|
+
|
|
29
31
|
### No subject yet — ask first
|
|
30
32
|
|
|
31
33
|
Called without one (a bare `/walkthrough`, the chat menu's entry sent as is, "walk me through" with nothing named), **ask before reading anything in detail** — the selection or the chapter in view is not enough on its own to guess which flow or which feature they mean. One cheap read for the options: `get_nodes { boardId, type: "CHAPTER", projection: "line" }` (and, for a single chapter, `list_slices`). Then reply once and **end the turn**:
|
|
@@ -60,46 +62,57 @@ Orient cheaply before reading anything in detail — the board can be large, and
|
|
|
60
62
|
|
|
61
63
|
1. **Chapters**: `get_nodes { boardId, type: "CHAPTER", projection: "line" }` — pick the chapter(s) the subject belongs to by title. With a `timelineId` in context, start there.
|
|
62
64
|
2. **Context notes**: for each candidate chapter, `get_board_outline { boardId, chapterId }`, then read the MARKDOWN note in the first column's `feedback` lane (`get_node`, `meta.description`) if there is one. It says what the chapter is for and often names the decisions behind it — use it in the descriptions.
|
|
63
|
-
3. **Slices**: `list_slices { boardId, contextName }` and `get_slice_data { boardId, contextName, projection: "outline", format: "toon" }` — every slice with its elements as `{id, title, type}`.
|
|
64
|
-
4. **Find the
|
|
65
|
-
- **explain**: the slices whose commands, events, read models or screens are about the subject; follow the edges in the outline (screen → command → event → read model → next screen, events → automations) from where the
|
|
66
|
-
- **impact**: start from the
|
|
65
|
+
3. **Slices**: `list_slices { boardId, contextName }` and `get_slice_data { boardId, contextName, projection: "outline", format: "toon" }` — every slice with its elements as `{id, title, type}`. This trimmed outline is your overview of the feature: pick the slices from it, and read nothing else board-wide.
|
|
66
|
+
4. **Find the slices that matter.** With the outline in hand, decide which **slices** belong to the subject — elements only tell you which slice to pick:
|
|
67
|
+
- **explain**: the slices whose commands, events, read models or screens are about the subject; follow the edges in the outline (screen → command → event → read model → next screen, events → automations) from the slice where the feature starts to the one where it ends. Other chapters only when the flow crosses into them (an external or translated event).
|
|
68
|
+
- **impact**: start from the slice the change lands on first (where the new data enters, or whose event changes meaning), then follow the flow **downstream** — every slice whose events would carry it, every state view and automation fed by those events, every screen that shows them — and **upstream** where the data has to come from. A name search helps: `get_nodes { boardId, name: "<term>", projection: "line" }` for the field or concept ("email") finds the slices that mention it already. Then work out the slices the feature needs that **don't exist yet** (a new command, a new state view, a new automation) — each is one new slice.
|
|
67
69
|
|
|
68
|
-
Stop widening when a further
|
|
70
|
+
Stop widening when a further slice adds nothing the person asked about. A walkthrough of 3–12 slices is typical; 20+ means the subject is really several features — say so in the text and walk the first one.
|
|
69
71
|
|
|
70
72
|
---
|
|
71
73
|
|
|
72
74
|
## Step 3 — Read only those
|
|
73
75
|
|
|
74
|
-
Now read the
|
|
76
|
+
Now read the chosen slices in detail — never the whole board:
|
|
75
77
|
|
|
76
|
-
- `get_slice_data { boardId, contextName, sliceId, projection: "fields" }` per
|
|
78
|
+
- `get_slice_data { boardId, contextName, sliceId, projection: "fields", format: "toon" }` per chosen slice — fields and dependencies, compact. Not the `textual` format: it repeats the slice's specs under every element.
|
|
77
79
|
- `get_slice_data { boardId, contextName, sliceId, projection: "specs", format: "toon" }` — the **scenarios**: these are the business rules. A scenario's title in business words ("Email must be unique") is a rule; its Given/When/Then says when it applies.
|
|
78
|
-
- `get_nodes { boardId, type: "SCENARIO", chapterId, projection: "line" }` — the ids of the scenario nodes, so an impact step can point at a scenario directly.
|
|
79
80
|
- Full `get_nodes { boardId, nodeIds: [...] }` only for the few nodes whose `description` you need.
|
|
80
81
|
|
|
81
82
|
---
|
|
82
83
|
|
|
83
|
-
## Step 4 — Build the steps
|
|
84
|
+
## Step 4 — Build the summary and the steps
|
|
85
|
+
|
|
86
|
+
**One step per slice**, in the order the feature runs. Never split a slice into element steps (no separate "command" and "event" steps) — the player already draws the slice's screen, commands, read models and events in its lanes. Scenarios are not steps either: their rules go into the slice's `rules`, new or changed cases into its `changes`.
|
|
87
|
+
|
|
88
|
+
**explain** — the slices as the person living the feature experiences them: *what they see and do → what is recorded → what that makes visible or triggers*.
|
|
84
89
|
|
|
85
|
-
|
|
90
|
+
**impact** — every slice the feature needs, existing or not, in the order the feature runs (not grouped by status). **Every step carries a `status`** — it is what the summary page counts ("8 slices: 3 exist, 2 need adjustment, 3 are new") and what each slice's chip shows; a step without one leaves the person guessing what is new:
|
|
91
|
+
|
|
92
|
+
| `status` | When |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `existing` | the slice is used as it is — the person should see it to understand the feature, but nothing changes |
|
|
95
|
+
| `changed` | the slice exists and needs adjustment — say what in `changes` |
|
|
96
|
+
| `new` | the slice doesn't exist yet and is built from scratch — sketch it with `elements`, say what it does in `description` |
|
|
86
97
|
|
|
87
|
-
|
|
98
|
+
Leave out existing slices that are neither changed nor needed to follow the feature. Say what is *not* affected only if the person would reasonably expect it to be.
|
|
88
99
|
|
|
89
|
-
**
|
|
100
|
+
**Summary** (snippet level) — always. 1–3 sentences on how the feature works (explain) or what it adds and how (impact), in the board's language. Don't count the slices in it — the player puts the count above it ("This feature consists of 6 slices: 2 of them exist, …"), computed from the steps and their `status`.
|
|
90
101
|
|
|
91
102
|
Per step:
|
|
92
103
|
|
|
93
104
|
| Field | What goes in |
|
|
94
105
|
|---|---|
|
|
95
|
-
| `title` |
|
|
96
|
-
| `description` | 1–3 sentences: what happens
|
|
97
|
-
| `nodeId` | the
|
|
98
|
-
| `
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
106
|
+
| `title` | the slice's name as on the board; for a new slice a name in the board's style ("Confirm Email") |
|
|
107
|
+
| `description` | 1–3 sentences: what happens in this slice and why it matters, in the board's language. No ids, no cell addresses. |
|
|
108
|
+
| `nodeId` | the slice's `SLICE_BORDER` id from `list_slices` — the player draws the slice from it and zooms the canvas to it. Left out for a `new` slice |
|
|
109
|
+
| `status` | **impact mode: required on every step** — `existing`, `changed` or `new` (table above). Omitted in explain mode |
|
|
110
|
+
| `elements` | **`new` slices only**: the sketch — `[{ "type": "SCREEN" \| "COMMAND" \| "EVENT" \| "READMODEL" \| "AUTOMATION", "title": "…", "fields": ["…"] }]`, the elements the slice will have (a state change: screen → command → event; a state view: event(s) → read model → screen; an automation: read model → automation → command → event). Titles and fields in the board's style; reuse the names of existing events the slice reads from |
|
|
111
|
+
| `screenId` | only when the screen a person sees in this step is not part of the slice itself |
|
|
112
|
+
| `rules` | the business rules of this slice, taken from its scenarios (and the context note); one line each, thresholds verbatim. Empty when there are none — never invent one |
|
|
113
|
+
| `changes` | **impact mode only**: what has to change or be built in this slice, one line each — "add field `email` (String) to Register Customer", "new scenario: duplicate email is rejected" |
|
|
101
114
|
|
|
102
|
-
**Faithfulness.**
|
|
115
|
+
**Faithfulness.** Existing slices come from the board. A rule nobody modelled is not a rule — if the walkthrough reveals a gap ("nothing says what happens when confirmation never arrives"), mention it in the step's `description` as an open question, not as a rule. A sketched new slice is a proposal, and the `description` should read like one.
|
|
103
116
|
|
|
104
117
|
---
|
|
105
118
|
|
|
@@ -111,36 +124,49 @@ Per step:
|
|
|
111
124
|
mcp__eventmodelers__post_chat_message {
|
|
112
125
|
"boardId": "$BOARD_ID",
|
|
113
126
|
"replyTo": "<message_id>",
|
|
114
|
-
"text": "Registration in
|
|
127
|
+
"text": "Registration in 4 slices — step through it here, or press Play.",
|
|
115
128
|
"snippet": {
|
|
116
129
|
"kind": "walkthrough",
|
|
117
130
|
"title": "How registration works",
|
|
118
|
-
"
|
|
131
|
+
"summary": "A customer signs up with name, email and password. The account stays inactive until the email is confirmed through the link sent to them.",
|
|
119
132
|
"steps": [
|
|
120
|
-
{ "title": "Customer
|
|
121
|
-
"description": "Name, email and password are entered on the registration screen.",
|
|
133
|
+
{ "title": "Register Customer", "nodeId": "<slice border id>",
|
|
134
|
+
"description": "Name, email and password are entered on the registration screen and recorded as Customer Registered.",
|
|
122
135
|
"rules": ["Email must be unique", "Password at least 12 characters"] },
|
|
123
|
-
{ "title": "
|
|
124
|
-
"description": "
|
|
136
|
+
{ "title": "Send Confirmation Mail", "nodeId": "<slice border id>",
|
|
137
|
+
"description": "An automation picks up every new registration and sends the confirmation link." }
|
|
125
138
|
]
|
|
126
139
|
}
|
|
127
140
|
}
|
|
128
141
|
```
|
|
129
142
|
|
|
130
|
-
Impact mode, same shape with `changes` per step:
|
|
143
|
+
Impact mode, same shape with `status` (and `changes`, or `elements` for a new slice) per step:
|
|
131
144
|
|
|
132
145
|
```
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
"
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
146
|
+
"summary": "Customers register with an email that has to be confirmed before the account becomes active. Registration stores the email, and a new confirmation flow sends and checks the link.",
|
|
147
|
+
"steps": [
|
|
148
|
+
{ "title": "Register Customer", "nodeId": "<slice border id>", "status": "changed",
|
|
149
|
+
"description": "The email enters here and has to be validated before anything is recorded.",
|
|
150
|
+
"changes": ["Add field email (String) to Register Customer and Customer Registered", "New scenario: duplicate email is rejected"],
|
|
151
|
+
"rules": ["Customer name is required"] },
|
|
152
|
+
{ "title": "Confirm Email", "status": "new",
|
|
153
|
+
"description": "Proposed: the customer opens the link and the email is marked as confirmed.",
|
|
154
|
+
"elements": [
|
|
155
|
+
{ "type": "SCREEN", "title": "Confirm Email Page" },
|
|
156
|
+
{ "type": "COMMAND", "title": "Confirm Email", "fields": ["customerId", "token"] },
|
|
157
|
+
{ "type": "EVENT", "title": "Email Confirmed", "fields": ["customerId", "confirmedAt"] }
|
|
158
|
+
],
|
|
159
|
+
"changes": ["New slice: Confirm Email (state change)"] },
|
|
160
|
+
{ "title": "Customer List", "nodeId": "<slice border id>", "status": "existing",
|
|
161
|
+
"description": "Shows the customers as before; confirmation doesn't change it." }
|
|
162
|
+
]
|
|
139
163
|
```
|
|
140
164
|
|
|
141
|
-
- `text` is one line: the subject and the number of
|
|
142
|
-
-
|
|
165
|
+
- `text` is one line: the subject and the number of slices — in impact mode with the split ("Startup license in 8 slices: 3 new, 2 to adjust"). It is the fallback, so it must make sense alone.
|
|
166
|
+
- Impact mode: before posting, check that every step has a `status`, every `changed` step has `changes` and every `new` step has `elements` and no `nodeId`.
|
|
167
|
+
- `summary` is always there — the first page shows it under the slice count.
|
|
168
|
+
- Every `nodeId` / `screenId` is an id you read in Steps 2–3 — never a guessed or remembered one. A `new` slice has no `nodeId`.
|
|
143
169
|
- The snippet is at most 64 KB; keep descriptions short rather than dropping steps.
|
|
144
170
|
- **Impact mode** ends there: the walkthrough is the proposal. If the person then asks for the changes, that is ordinary work (prompts per the kit's CLAUDE.md) — and a slice that is not `Created` still needs their confirmation first.
|
|
145
171
|
|
|
146
|
-
**No chat** (run from a terminal): print the steps as a numbered list with the same fields instead of posting.
|
|
172
|
+
**No chat** (run from a terminal): print the slice count and the summary, then the steps as a numbered list with the same fields, instead of posting.
|
|
@@ -204,9 +204,9 @@ for it. Instead:
|
|
|
204
204
|
*"On it — looking at Registration."*
|
|
205
205
|
- **walkthrough** — "how does X work?", "walk me through …", "what does it take to add …?", or `/walkthrough …`:
|
|
206
206
|
run the `/walkthrough` skill **in this turn** — it only reads the board, so no prompt is needed. It finds the
|
|
207
|
-
slices,
|
|
207
|
+
slices involved (one step per slice, after a summary page) and its `walkthrough` snippet is your one reply (step 4). Without a
|
|
208
208
|
subject (a bare `/walkthrough`) it asks first — which flow, or which new feature — and that question is the reply. A planned change
|
|
209
|
-
("we need to add an email") is its impact mode: the walkthrough is the proposal, and the changes become work only
|
|
209
|
+
("we need to add an email") is its impact mode: every slice marked existing / needs adjustment / new, new ones sketched — the walkthrough is the proposal, and the changes become work only
|
|
210
210
|
when the person asks for them afterwards.
|
|
211
211
|
- **a skill by name** — the message starts with `/<name>` of one of your skills (the chat panel's menu
|
|
212
212
|
writes these: `/analyze-existing-model`, `/analyze-code-base`, `/detect-model-drift`, `/add-next-slice`, `/examples`, `/timeline …`,
|
|
@@ -364,7 +364,7 @@ nothing to sanitize either, since a board change is not user text.
|
|
|
364
364
|
| Analyse the existing model structure, slice coverage, element counts | `/analyze-existing-model` |
|
|
365
365
|
| Reverse-engineer the business process of an existing code base into the model, as an interview — all chapters first, then one chapter at a time | `/analyze-code-base` |
|
|
366
366
|
| Find where the model and the code have drifted apart (fields, specs, screens, edges, missing/extra slices) and propose fixes | `/detect-model-drift` |
|
|
367
|
-
| Walk someone through a
|
|
367
|
+
| Walk someone through a feature slice by slice, or through every slice a planned feature needs (existing, to adjust, new), as a player in the chat | `/walkthrough` |
|
|
368
368
|
| Turn a document or image (e.g. a tender/RFP) into a chaptered event model with screens, scenarios and a written blueprint summary | `/summarize` |
|
|
369
369
|
| Look up any API endpoint or element type not already covered by the skill you're executing | `/learn-eventmodelers-api` |
|
|
370
370
|
| Add or rename an attribute across a chain of elements | `/attributes` |
|