@eventmodelers/cli 1.0.46 → 1.0.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/shared/skills/learn-eventmodelers-api/SKILL.md +52 -46
  4. package/shared/skills/request-feedback/SKILL.md +7 -5
  5. package/stacks/axon/templates/build-kit/CLAUDE.md +1 -1
  6. package/stacks/blank/templates/build-kit/CLAUDE.md +1 -1
  7. package/stacks/cratis-csharp/templates/build-kit/CLAUDE.md +9 -0
  8. package/stacks/kurrent/templates/build-kit/CLAUDE.md +3 -1
  9. package/stacks/modeling-kit/templates/.claude/skills/add-next-slice/SKILL.md +2 -2
  10. package/stacks/modeling-kit/templates/.claude/skills/attributes/SKILL.md +0 -1
  11. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/SKILL.md +1 -1
  12. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/references/examples.md +2 -2
  13. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-core-rules/SKILL.md +2 -2
  14. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/SKILL.md +1 -1
  15. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-interview-protocol/SKILL.md +1 -1
  16. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/SKILL.md +4 -4
  17. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/SKILL.md +1 -1
  18. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models/SKILL.md +1 -1
  19. package/stacks/modeling-kit/templates/.claude/skills/examples/SKILL.md +1 -1
  20. package/stacks/modeling-kit/templates/.claude/skills/handle-comment/SKILL.md +13 -4
  21. package/stacks/modeling-kit/templates/.claude/skills/place-element/SKILL.md +2 -2
  22. package/stacks/modeling-kit/templates/.claude/skills/wdyt/SKILL.md +5 -5
  23. package/stacks/modeling-kit/templates/kit/AGENTS.md +1 -1
  24. package/stacks/modeling-kit/templates/kit/CLAUDE.md +2 -2
  25. package/stacks/node/templates/build-kit/CLAUDE.md +1 -1
  26. package/stacks/opencqrs/templates/build-kit/CLAUDE.md +3 -1
  27. package/stacks/supabase/templates/build-kit/CLAUDE.md +1 -1
  28. package/stacks/umadb/templates/build-kit/CLAUDE.md +1 -1
package/README.md CHANGED
@@ -97,7 +97,7 @@ Use skills in Claude Code with `/skill-name`:
97
97
  | `/update-slice-status` | Update slice status on the board |
98
98
  | `/load-slice` | Persist board slices to disk (backend stacks) |
99
99
  | `/build-state-change`, `/build-state-view`, `/build-automation`, `/build-webhook` | Implement a slice's command/view/automation/webhook (backend stacks) |
100
- | `/request-feedback` | Post a QUESTION comment and mark a slice `Blocked` when it's genuinely ambiguous (backend stacks) |
100
+ | `/request-feedback` | Post a comment and mark a slice `Blocked` when it's genuinely ambiguous (backend stacks) |
101
101
 
102
102
  Which skills install depends on the chosen stack — see `stacks/<name>/templates/.claude/skills/`. `/connect`, `/learn-eventmodelers-api`, `/update-slice-status`, and `/request-feedback` have no stack-specific content and install into every stack from `shared/skills/` instead.
103
103
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventmodelers/cli",
3
- "version": "1.0.46",
3
+ "version": "1.0.47",
4
4
  "description": "Eventmodelers CLI — real-time Claude agent + skills for Claude Code, for any stack (Node, Supabase, Axon, Cratis, OpenCQRS, UmaDB, Kurrent, or modeling-only)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -54,7 +54,7 @@ Server name: `eventmodelers`. Every tool takes `boardId` explicitly; none need `
54
54
  | `set_connection` | `boardId`, `source`, `target`, `action` (`'connect'\|'remove'`) | Add or remove a type-checked directed edge. Batch form `set_connections` takes `connections[]` (applied in order) plus `compact?` — `compact: true` returns a `{connected, existed, removed, notFound, failed, errors}` tally instead of one row per edge | — (via `edges` on §3 events) |
55
55
  | `auto_connect_node` | `boardId`, `nodeId` | Re-run auto-connect for a node | §3 `POST .../nodes/:nodeId/auto-connect` |
56
56
  | `link_element` | `boardId`, `nodeId`, `targetNodeId` | Link two existing same-type nodes: `targetNodeId` is replaced with a full copy of `nodeId`'s meta plus `meta.linkedTo`. Linking means first create, then link | §3 `POST .../nodes/:nodeId/link` |
57
- | `add_comment` | `boardId`, `nodeId`, `text`, `type?` (`'COMMENT'\|'TASK'\|'QUESTION'`), `author?` | Add a comment — `QUESTION` flags gaps/edge cases during review | — (via comment events) |
57
+ | `add_comment` | `boardId`, `nodeId`, `text`, `type?` (`'COMMENT'\|'TASK'`), `author?` | Add a comment — word the `text` as a question to flag gaps/edge cases during review; there is no separate `QUESTION` type | — (via comment events) |
58
58
  | `update_comment` | `boardId`, `nodeId`, `commentId`, `action` (`'resolve'\|'delete'`) | Resolve or delete a comment | — (via comment events) |
59
59
  | `create_screen` | `boardId`, `contentType` (`'image'\|'sketch'\|'html'`), `nodeId?`, `chapterId`, `cellId?`/`cellName?`, plus content fields (`imageBase64`/`mimeType`, `elements[]`, or `pages[]`/`backgroundColor`), `description?`, `fields?`, `autoConnect?` | Create + place a new screen node (SCREEN or HTML_SCREEN) atomically, in one call. Batch form `create_screens` takes `screens[]` (HTML only) + `autoConnect?`. `autoConnect: false` places without wiring to timeline neighbors | §4 `POST .../images/:id/sketch` + `image-nodes` |
60
60
  | `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` |
@@ -66,7 +66,7 @@ Server name: `eventmodelers`. Every tool takes `boardId` explicitly; none need `
66
66
  | `commit_board_to_git` | `boardId` | Force a git-extension commit/push, bypassing the autoCommit gate | — (MCP-only; git extension) |
67
67
  | `update_prompt_status` | `promptId`, `newStatus`, `comment?` | Update a prompt's lifecycle status (`ADDED`/`CLAIMED`/`IN_PROGRESS`/`DONE`), optionally with a progress comment. Not board-scoped — no `boardId` arg; the prompt's board is resolved server-side. | §14 `POST .../prompts/:id/status` |
68
68
 
69
- **Not exposed via MCP at all** — always use REST/curl for these: §7 Config Import, §10 Snapshots, §11–12 User Management, §13 Utility (`/api/user`, swagger), and the rest of §14 Prompts (submission, claiming, deletion, realtime-token) — only the status-update endpoint has an MCP tool (`update_prompt_status`, used by the `update-prompt-status` skill); everything else in Prompts is an intentionally separate lifecycle the board-content MCP server doesn't otherwise own.
69
+ **Not exposed via MCP at all** — always use REST/curl for these: §7 Config Import, §10 Snapshots, §11–12 Invitations, §13 Utility (`/api/user`, swagger), and the rest of §14 Prompts (submission, claiming, deletion, realtime-token) — only the status-update endpoint has an MCP tool (`update_prompt_status`, used by the `update-prompt-status` skill); everything else in Prompts is an intentionally separate lifecycle the board-content MCP server doesn't otherwise own.
70
70
 
71
71
  **Capabilities with no direct MCP filter** — e.g. REST's `GET .../nodes?cellId=<id>&timelineId=<id>` and `?colId=<id>&timelineId=<id>` (§3) have no equivalent params on `get_nodes`. Either call the REST endpoint directly, or get the same answer by calling `get_node` on the CHAPTER and reading `meta.timelineData.cells` (sparse array; a cell absent from it is empty) instead of asking the server to filter by cell/column.
72
72
 
@@ -736,58 +736,48 @@ Delete a snapshot.
736
736
 
737
737
  ---
738
738
 
739
- ## 11. User Management — Commands (Event Sourced)
739
+ ## 11. Invitations (Organization Membership) — Commands
740
740
 
741
- All commands respond with:
742
- ```typescript
743
- {
744
- ok: true
745
- next_expected_stream_version: number
746
- last_event_global_position: number
747
- }
748
- ```
749
-
750
- Optional headers on all: `correlation_id`, `causation_id`
741
+ **Files**: `src/slices/organization/InviteUser/routes.ts`, `src/slices/organization/ConfirmInvitation/routes.ts`, `src/slices/organization/DeleteInvitation/routes.ts`
751
742
 
752
- ### POST `/api/creategroup`
753
- **Body**: `{ groupId: string, name: string }`
754
- **Event emitted**: `GroupCreated`
743
+ There is no generic "group"/"role-assignment" API — an organization *is* the group, and a
744
+ member's role is set once, at invite time (there is no separate call to change an existing
745
+ member's role afterward). All of these require a Supabase JWT (`Authorization: Bearer`), never
746
+ a bot `x-token`.
755
747
 
756
- ---
748
+ ### POST `/api/org/:orga_id/invitations`
749
+ Invite a user to join an organization with a given role. Caller must already be an `admin` of `orga_id`.
757
750
 
758
- ### POST `/api/inviteuser`
759
- **Body**: `{ groupId: string, email: string, invitationId: string }`
760
- **Event emitted**: `UserInvited`
751
+ **Body**: `{ role: string, email: string, description?: string }`
752
+ **Response**: `201` invitation created
753
+ **Errors**: `400` role/email missing · `403` caller is not an org admin · `409` user already invited or already a member
761
754
 
762
755
  ---
763
756
 
764
- ### POST `/api/acceptinvite`
765
- **Body**: `{ userId: string, groupId: string, invitationId: string }`
766
- **Event emitted**: `InvitationAccepted`
767
-
768
- ---
757
+ ### POST `/api/invitations/:token/confirm`
758
+ Accept an invitation — `token` is the invitation's own token (from the invite email link), not an API token. The confirming user's own account email must match the invited email.
769
759
 
770
- ### POST `/api/assignrole`
771
- **Body**: `{ userId: string, groupId: string, role: string }`
772
- **Event emitted**: `RoleAssigned`
760
+ **Response**: `200` — invitation confirmed, membership created
761
+ **Errors**: `404` invitation not found
773
762
 
774
763
  ---
775
764
 
776
- ## 12. User Management — Read Models (Projections)
765
+ ### DELETE `/api/org/:orga_id/invitations/:invitation_id`
766
+ Cancel a pending invitation.
777
767
 
778
- All require authentication. Optional query param `_id` to filter by ID.
768
+ **Response**: `200`/`204` on success
769
+
770
+ ---
779
771
 
780
- ### GET `/api/query/group-details-lookup`
781
- Group details. Filter: `?_id=groupId`
772
+ ## 12. Invitations (Organization Membership) — Read Models
782
773
 
783
- ### GET `/api/query/open-invites`
784
- Pending invitations. Filter: `?_id=invitationId`
774
+ All require a Supabase JWT (`Authorization: Bearer`).
785
775
 
786
- ### GET `/api/query/user-group-assignments`
787
- User-to-group mappings. Filter: `?_id=groupId`
776
+ ### GET `/api/user-organizations`
777
+ Organizations (and the caller's role in each) that the authenticated user belongs to.
788
778
 
789
- ### GET `/api/query/users-to-assign-to-groups`
790
- Users available for group assignment. Filter: `?_id=userId`
779
+ ### GET `/api/client/org/:orgId/invitations`
780
+ Pending invitations for an organization (client-facing list — used by the org settings UI).
791
781
 
792
782
  ---
793
783
 
@@ -883,6 +873,22 @@ Exchange an `x-token` for a short-lived Supabase-compatible JWT, used to subscri
883
873
 
884
874
  ---
885
875
 
876
+ ### POST `/api/agent-alive`
877
+ Record a heartbeat ping for a running modeling/build agent. Auth: Supabase JWT (`Authorization: Bearer`) — exchange the `x-token` for one first via `GET /api/org/:orgId/prompts/realtime-token` above; a raw `x-token` alone is not accepted here.
878
+
879
+ **Body**: `{ token: string, board_id?: string, agent_type: 'MODELING' | 'BUILD', agent_id: string }`
880
+ **Response**: `200` — `{ ok: true }`
881
+ **Errors**: `400` `agent_id`/`agent_type` missing · `404` token not found
882
+
883
+ ---
884
+
885
+ ### GET `/api/org/:orgId/boards/:boardId/agent-alive`
886
+ Check whether an agent has pinged for a board within the last 45s. Auth: `x-token` (bot) or a Supabase JWT (`Authorization: Bearer`) — either works.
887
+
888
+ **Response**: `200` — `{ alive: boolean, agentTypes: string[] }`
889
+
890
+ ---
891
+
886
892
  ## Domain Events
887
893
 
888
894
  ### Snapshot Events (`src/events/SnapshotsEvents.ts`)
@@ -896,14 +902,14 @@ SnapshotShared // { id }
896
902
  SnapshotPublished // { id, payloadId, bucket, path }
897
903
  ```
898
904
 
899
- ### User Management Events (`src/events/UserManagementEvents.ts`)
905
+ ### Invitation Events (`src/slices/organization/OrganizationEvent.ts`)
900
906
 
901
907
  ```typescript
902
- GroupCreated // { groupId, owner, name }
903
- UserAssignedToGroup // { groupId, userId }
904
- UserInvited // { groupId, invitationId, email }
905
- InvitationAccepted // { invitationId, groupId, userId }
906
- RoleAssigned // { groupId, userId, role }
908
+ UserInvited // { orgaId, userId, role, invitationId, token, description?, boardId?, email? }
909
+ InvitationConfirmed // { orgaId, userId, invitationId, token?, email? }
910
+ InvitationDeleted // { invitationId }
911
+ UserAssignedToOrganization // { id, userId, orgaId, role?, boardId?, email? }
912
+ UserRemovedFromOrganization // { orgaId, userId }
907
913
  ```
908
914
 
909
915
  All events support optional metadata: `user_id`, `correlation_id`, `causation_id`
@@ -928,7 +934,7 @@ All events support optional metadata: `user_id`, `correlation_id`, `causation_id
928
934
  | `src/slices/slicedata/routes.ts` | Slice data read models |
929
935
  | `src/slices/extensions/routes.ts` | Extension management |
930
936
  | `src/slices/Snapshots/routes.ts` | Snapshot CRUD |
931
- | `src/slices/usermanagement/*/routes*.ts` | User management commands + projections |
937
+ | `src/slices/organization/InviteUser/routes.ts`, `ConfirmInvitation/routes.ts`, `DeleteInvitation/routes.ts` | Organization invitation commands |
932
938
  | `src/events/SnapshotsEvents.ts` | Snapshot domain events |
933
- | `src/events/UserManagementEvents.ts` | User management domain events |
939
+ | `src/slices/organization/OrganizationEvent.ts` | Organization/invitation domain events |
934
940
  | `backend/src/server.ts` | Route wiring, CORS, `/api/user` |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: request-feedback
3
- description: Post a QUESTION comment on a slice and mark it Blocked when the slice's requirements are genuinely ambiguous, contradictory, or missing something a decision depends on. This is an escalation path, not a routine step — reach for it only when you cannot proceed without guessing.
3
+ description: Post a comment on a slice and mark it Blocked when the slice's requirements are genuinely ambiguous, contradictory, or missing something a decision depends on. This is an escalation path, not a routine step — reach for it only when you cannot proceed without guessing.
4
4
  ---
5
5
 
6
6
  # Request Feedback
@@ -57,7 +57,7 @@ From `$ARGUMENTS` or the calling skill's context, extract:
57
57
  |-------|---------------|---------|
58
58
  | `sliceName` or `sliceId` | the slice being worked on | **required** — one of the two |
59
59
  | `question` | the specific ambiguity or missing piece, phrased as a question | **required** |
60
- | `author` | author identifier string | `agent` |
60
+ | `author` | author identifier string | `agent-$CLAUDE_CODE_SESSION_ID` (falls back to `agent` if that env var is unset) |
61
61
 
62
62
  ## Step 2 — Resolve the slice's node id
63
63
 
@@ -81,12 +81,14 @@ Find the slice whose `title` matches `sliceName` (case-insensitive), or whose `i
81
81
  If no match is found, stop and list the available slice titles so the caller can pick one. Save the
82
82
  matched slice's `id` as `SLICE_NODE_ID` and its current `status` as `CURRENT_STATUS`.
83
83
 
84
- ## Step 3 — Post the QUESTION comment
84
+ ## Step 3 — Post the comment
85
+
86
+ There is no separate `QUESTION` type at the API level — post a normal `COMMENT` worded as a question.
85
87
 
86
88
  Prefer MCP:
87
89
 
88
90
  ```
89
- mcp__eventmodelers__add_comment { "boardId": "<BOARD_ID>", "nodeId": "<SLICE_NODE_ID>", "text": "<question>", "type": "QUESTION", "author": "<author>" }
91
+ mcp__eventmodelers__add_comment { "boardId": "<BOARD_ID>", "nodeId": "<SLICE_NODE_ID>", "text": "<question>", "type": "COMMENT", "author": "<author>" }
90
92
  ```
91
93
 
92
94
  **Fallback (no MCP):**
@@ -95,7 +97,7 @@ mcp__eventmodelers__add_comment { "boardId": "<BOARD_ID>", "nodeId": "<SLICE_NOD
95
97
  curl -s -X POST "<BASE_URL>/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/<SLICE_NODE_ID>/comments" \
96
98
  -H "Authorization: Bearer <TOKEN>" \
97
99
  -H "Content-Type: application/json" \
98
- -d '{"text":"<question>","type":"QUESTION","author":"<author>"}'
100
+ -d '{"text":"<question>","type":"COMMENT","author":"<author>"}'
99
101
  ```
100
102
 
101
103
  Response: `201 {"id":"<commentId>"}`. Save it as `COMMENT_ID` — the calling skill may want to reference
@@ -58,7 +58,7 @@ When asked to build a slice, always follow this flow:
58
58
  - **State-view** — `projections` or `queries` array is non-empty → invoke `/build-state-view`
59
59
  - **State-change** — default (has `commands` / `events`) → invoke `/build-state-change`
60
60
  3. Invoke the matching skill and follow its instructions completely. Do not deviate.
61
- 4. **Verify against slice.json**: After the skill completes, check that every command field, event field, and specification in slice.json appears in the implementation. No invented fields — if it is not in slice.json, it must not be in the code.
61
+ 4. **Verify against slice.json**: After the skill completes, check that every command field, event field, and specification in slice.json appears in the implementation. No invented fields — if it is not in slice.json, it must not be in the code. This applies even when the slice was previously `Done` and reappears as `Planned` — never dismiss a mismatch as "already implemented" or harmless drift; diff slice.json against the code field by field and update the code to match every change.
62
62
  5. Run quality checks (`./mvnw compile -q`, then the slice tests only).
63
63
  6. If checks pass, commit with `feat: [Slice Name]` and set slice status to `Done`.
64
64
 
@@ -48,7 +48,7 @@ When asked to build a slice, always follow this flow:
48
48
  - **State-view** — `projections` or `queries` array is non-empty → invoke `/build-state-view`
49
49
  - **State-change** — default (has `commands` / `events`) → invoke `/build-state-change`
50
50
  3. Invoke the matching skill and follow its instructions completely. Do not deviate.
51
- 4. **Verify against slice.json**: After the skill completes, check that every command field, event field, and specification in slice.json appears in the implementation. No invented fields — if it is not in slice.json, it must not be in the code.
51
+ 4. **Verify against slice.json**: After the skill completes, check that every command field, event field, and specification in slice.json appears in the implementation. No invented fields — if it is not in slice.json, it must not be in the code. This applies even when the slice was previously `Done` and reappears as `Planned` — never dismiss a mismatch as "already implemented" or harmless drift; diff slice.json against the code field by field and update the code to match every change.
52
52
  5. Run quality checks (TODO: this stack's build + test commands), then the slice tests only.
53
53
  6. If checks pass, commit with `feat: [Slice Name]` and set slice status to `Done`.
54
54
 
@@ -16,6 +16,15 @@ then stop work on this slice for this run. This is an escalation path, not a rou
16
16
  `slice.json` and the matching build skill's own instructions fully first; most slices are fully
17
17
  specified and need none of this.
18
18
 
19
+ ## No such thing as harmless drift
20
+
21
+ `slice.json` is always the desired state — the code follows what it defines, never the other way
22
+ around. If code for a slice already exists — most often because it was previously `Done` and got moved
23
+ back to `Planned` — never conclude "already implemented" and move on. A slice does not return to
24
+ `Planned` without a reason: diff the current `slice.json` against the existing implementation field by
25
+ field (events, commands, params, specifications, routes) and update the code to match every difference
26
+ you find. Only mark it `Done` once there is no gap left.
27
+
19
28
  ## Structure (learn from `SomeModule/SomeFeature/`)
20
29
 
21
30
  ```
@@ -95,7 +95,9 @@ When asked to build a slice, always follow this flow:
95
95
  3. Invoke the matching skill and follow its instructions completely. Do not deviate.
96
96
  4. **Verify against slice.json**: After the skill completes, check that every command field, event field,
97
97
  and specification in slice.json appears in the implementation. No invented fields — if it is not in
98
- slice.json, it must not be in the code.
98
+ slice.json, it must not be in the code. This applies even when the slice was previously `Done` and
99
+ reappears as `Planned` — never dismiss a mismatch as "already implemented" or harmless drift; diff
100
+ slice.json against the code field by field and update the code to match every change.
99
101
  5. Run quality checks (`./mvnw compile -q`, then the slice tests only).
100
102
  6. If checks pass, commit with `feat: [Slice Name]` and set slice status to `Done`.
101
103
 
@@ -23,7 +23,7 @@ Same rules as `eventmodeling-slicing-event-models`'s own "Core Concept" section
23
23
 
24
24
  "I don't know what the next capability is" is not the same as "any guess risks doing the wrong thing." A plausible next slice — the next lifecycle stage, an unaddressed affordance on an existing screen, a natural CRUD/notification gap — always exists for a working domain, and a wrong guess here costs nothing: it's just another slice on the board, easy to rename or discard later.
25
25
 
26
- **Posting a comment and closing the prompt with no board mutation is not an acceptable outcome of this skill.** That only defers the same empty decision to the next identical prompt, forever. If you already posted a `QUESTION`/`TASK` comment about this exact ambiguity on a previous turn, that does not make it acceptable to do so again instead of creating something — the comment already served its purpose (flagging the assumption for a human to correct later); this turn should still create the slice.
26
+ **Posting a comment and closing the prompt with no board mutation is not an acceptable outcome of this skill.** That only defers the same empty decision to the next identical prompt, forever. If you already posted a `COMMENT`/`TASK` comment about this exact ambiguity on a previous turn, that does not make it acceptable to do so again instead of creating something — the comment already served its purpose (flagging the assumption for a human to correct later); this turn should still create the slice.
27
27
 
28
28
  ---
29
29
 
@@ -37,7 +37,7 @@ Same rules as `eventmodeling-slicing-event-models`'s own "Core Concept" section
37
37
 
38
38
  If a specific instruction *is* given (the prompt names a capability, or references a comment/discussion that does), use that instead of inferring one.
39
39
 
40
- If, after looking at the existing slices, it's genuinely unclear which of several equally-reasonable next steps to pick, post a `QUESTION` comment (via `handle-comment`) noting the assumption you're about to make — then make it and create the slice in the same turn, every time. Never stop at just the comment.
40
+ If, after looking at the existing slices, it's genuinely unclear which of several equally-reasonable next steps to pick, post a comment (via `handle-comment`) noting the assumption you're about to make — then make it and create the slice in the same turn, every time. Never stop at just the comment.
41
41
 
42
42
  ## Step 2: Create the slice
43
43
 
@@ -100,7 +100,6 @@ For each node:
100
100
  "name": "<attributeName>",
101
101
  "type": "String",
102
102
  "query": false,
103
- "edited": false,
104
103
  "optional": false,
105
104
  "generated": false,
106
105
  "subfields": [],
@@ -34,7 +34,7 @@ Use these results as the source of truth for the completeness check.
34
34
  - Never propose deleting, suppressing, or "cleaning up" either node in a linked pair. Specifically, never target the node that has *no* `linkedTo` (the original) for removal — copies reference it via `moveToWidget=<originNodeId>`, so deleting it breaks every copy.
35
35
  - Only flag same-titled nodes as an actual duplicate gap when **none** of them has `linkedTo` — i.e., they are genuinely two independent, unlinked nodes describing the same concept.
36
36
 
37
- After the analysis, use the `handle-comment` skill to post findings on relevant nodes — `TASK` for required fixes, `QUESTION` for gaps that need clarification.
37
+ After the analysis, use the `handle-comment` skill to post findings on relevant nodes — `TASK` for required fixes, `COMMENT` for gaps that need clarification.
38
38
 
39
39
  ## Workflow
40
40
 
@@ -1,6 +1,6 @@
1
1
  # Checking Completeness — Worked Examples
2
2
 
3
- These are conceptual worked examples (Order/Payment domain) illustrating the completeness-check reasoning this skill applies — useful for understanding the reasoning, but the actual mechanics live in the numbered Workflow sections of the main SKILL.md (reading board state and posting `TASK`/`QUESTION` comments via `handle-comment`), not in writing a document like this.
3
+ These are conceptual worked examples (Order/Payment domain) illustrating the completeness-check reasoning this skill applies — useful for understanding the reasoning, but the actual mechanics live in the numbered Workflow sections of the main SKILL.md (reading board state and posting `TASK`/`COMMENT` comments via `handle-comment`), not in writing a document like this.
4
4
 
5
5
  ## 1. Field Origin & Destination Matrix
6
6
 
@@ -265,7 +265,7 @@ Actions taken:
265
265
 
266
266
  ## Legacy markdown-document format (superseded — kept for reference only)
267
267
 
268
- Older versions of this skill wrote the completeness check as a markdown report. The actual mechanism today is reading board state and posting `TASK`/`QUESTION` comments via `handle-comment` (see "Board Context" in the main SKILL.md) — this template is kept only so the shape of the information (what a complete completeness report covers) stays documented somewhere.
268
+ Older versions of this skill wrote the completeness check as a markdown report. The actual mechanism today is reading board state and posting `TASK`/`COMMENT` comments via `handle-comment` (see "Board Context" in the main SKILL.md) — this template is kept only so the shape of the information (what a complete completeness report covers) stays documented somewhere.
269
269
 
270
270
  ```markdown
271
271
  # Completeness Check: [Domain Name]
@@ -150,10 +150,10 @@ Every AUTOMATION, translation or worker, needs its own todo-list READMODEL (open
150
150
 
151
151
  Two different things are easy to conflate, and conflating them corrupts completeness checking:
152
152
 
153
- - **Open question** — something genuinely undecided. Post it as a `QUESTION`-type comment (`handle-comment`) on the relevant node. It stays open until someone actually answers it resolving means answering, not deleting the comment.
153
+ - **Open question** — something genuinely undecided. Post it as a `COMMENT` (`handle-comment`) on the relevant node, worded as a question. There is no separate question type at the API level — it stays open (unresolved) until someone actually answers it, resolving means answering, not deleting the comment.
154
154
  - **Decided failure** — a rejection or error case whose behavior is already decided (e.g. "payment fails → reject, no event"). Model it as a SCENARIO with `expectError: true` and an `errorDescription` (see `eventmodeling-elaborating-scenarios`), never as a comment. It's permanent, specified behavior, not something waiting on an answer.
155
155
 
156
- A decided failure left as a lingering `QUESTION` comment looks unresolved when it isn't. When counting completeness (`eventmodeling-checking-completeness`), only a genuinely unanswered `QUESTION` counts as a gap — a decided failure path needs its `expectError` scenario, not a comment standing in for one.
156
+ A decided failure left as a lingering, unresolved question comment looks unresolved when it isn't. When counting completeness (`eventmodeling-checking-completeness`), only a genuinely unanswered question comment counts as a gap — a decided failure path needs its `expectError` scenario, not a comment standing in for one.
157
157
 
158
158
  ## Offline-First Thinking
159
159
 
@@ -193,7 +193,7 @@ Before finalizing any read model, ask: "does this screen contain more than one c
193
193
 
194
194
  ### Step 5d — Pull field mappings from Step 3 — they are the spec, not a guess
195
195
 
196
- **Do not re-derive read model needs from a screen's title or description alone, and do not rely on the orchestrator's phase-summary handoff for this** — if you arrived here via `eventmodeling-orchestrating-event-modeling`, the handoff after Step 3 is a short hand-written prose summary (`.trogonai/interviews/.../EVENTMODELING.md`), not the actual field data. It will not reliably carry the per-field mappings forward. Go back to the board itself:
196
+ **Do not re-derive read model needs from a screen's title or description alone, and do not rely on the orchestrator's phase-summary handoff for this** — if you arrived here via `eventmodeling-orchestrating-event-modeling`, the handoff after Step 3 is a short hand-written prose summary (`.eventmodelers/interviews/.../EVENTMODELING.md`), not the actual field data. It will not reliably carry the per-field mappings forward. Go back to the board itself:
197
197
 
198
198
  For every SCREEN node, fetch it directly (`get_node`/`get_nodes`, never from memory) and read its `meta.fields`. Step 3 already required every field to carry a `mapping`, and for view fields that mapping is already in the exact form `"<ReadModelTitle>.<fieldName>"` — recorded specifically so this step doesn't have to re-guess it.
199
199
 
@@ -17,7 +17,7 @@ Already have everything the step needs? Skip straight to the step's own workflow
17
17
 
18
18
  ## Recording the outcome
19
19
 
20
- Append to the project's event modeling file: `.trogonai/interviews/[project-name]/EVENTMODELING.md`, under a section for this step:
20
+ Append to the project's event modeling file: `.eventmodelers/interviews/[project-name]/EVENTMODELING.md`, under a section for this step:
21
21
 
22
22
  ```markdown
23
23
  ## <Step Number>. <Step Name> (<skill-name>)
@@ -185,7 +185,7 @@ scope, and stated output goal (code, design, learning, docs).
185
185
  Confirm understanding before proceeding: "So we're modeling [domain], goal is
186
186
  [goal], constraints are [constraints]. Starting from [step]. Does that match?"
187
187
 
188
- **Capture findings** — create `.trogonai/interviews/[project-name]/EVENTMODELING.md` with this header (this step is what creates the file; every later step appends to it per `eventmodeling-interview-protocol`):
188
+ **Capture findings** — create `.eventmodelers/interviews/[project-name]/EVENTMODELING.md` with this header (this step is what creates the file; every later step appends to it per `eventmodeling-interview-protocol`):
189
189
 
190
190
  ```markdown
191
191
  # Event Modeling: [Project Name]
@@ -209,7 +209,7 @@ Then follow **`eventmodeling-interview-protocol`** to record this step's own fin
209
209
 
210
210
  After each step completes, before invoking the next skill, write a phase summary to memory.
211
211
 
212
- Append a summary block to `.trogonai/interviews/[project-name]/EVENTMODELING.md`:
212
+ Append a summary block to `.eventmodelers/interviews/[project-name]/EVENTMODELING.md`:
213
213
 
214
214
  ```markdown
215
215
  ### Step N complete — [Skill Name]
@@ -448,7 +448,7 @@ Not delegated to a separate skill — performed directly by this orchestrating s
448
448
  - **Business rules deliberately encoded as scenarios, not new events** — so a reader doesn't mistake a missing event for an oversight.
449
449
  - **Sequencing or design corrections made mid-workflow** — e.g. a column reorder because an event's original placement implied the wrong causality.
450
450
  - **Read model design rationale** — especially where one read model deliberately serves several screens/automations, so it doesn't read as a missing 1:1 mapping.
451
- - **Any cross-context or integration gaps found** (Step 6 Conway's Law, or discovered incidentally, e.g. a same-timeline connection constraint blocking a needed cross-chapter data dependency) — state the finding and the viable resolutions, matching whatever TASK/QUESTION comment was also posted on the affected node.
451
+ - **Any cross-context or integration gaps found** (Step 6 Conway's Law, or discovered incidentally, e.g. a same-timeline connection constraint blocking a needed cross-chapter data dependency) — state the finding and the viable resolutions, matching whatever TASK/COMMENT comment was also posted on the affected node.
452
452
  - **Closing summary**: element counts and the validation verdict for this chapter's slice of the model.
453
453
 
454
454
  If a chapter's story is genuinely simple, say so briefly rather than padding — but for any chapter with real design decisions behind it, this note is the place those decisions survive past the session that made them.
@@ -505,5 +505,5 @@ specific needs:
505
505
  - [ ] At least one view scenario (GWT or storyline) exists per READMODEL — not just per command
506
506
  - [ ] Completeness check shows no unresolved field traceability gaps
507
507
  - [ ] Validation returns PASS or PASS WITH WARNINGS with all critical issues resolved
508
- - [ ] Interview trail in `.trogonai/` updated with status of each completed step
508
+ - [ ] Interview trail in `.eventmodelers/` updated with status of each completed step
509
509
  - [ ] Phase summary written to memory after every completed step before loading the next skill
@@ -100,7 +100,7 @@ mcp__eventmodelers__get_nodes { "boardId": "$BOARD_ID", "type": "SCREEN" }
100
100
 
101
101
  **Fallback (no MCP):** see `references/api-fallback.md` — "Board Integration — Check existing screen nodes".
102
102
 
103
- After completing the screen analysis, use the `handle-comment` skill to post a QUESTION comment on any screen node where data fields are unclear or missing sources are identified.
103
+ After completing the screen analysis, use the `handle-comment` skill to post a comment on any screen node where data fields are unclear or missing sources are identified.
104
104
 
105
105
  ## Resolve One Actor Lane Per Human Role (do this once, before placing any screens)
106
106
 
@@ -37,7 +37,7 @@ mcp__eventmodelers__get_nodes { "boardId": "$BOARD_ID", "type": "READMODEL" }
37
37
 
38
38
  **Fallback (no MCP):** see `references/api-fallback.md` — "Board Context".
39
39
 
40
- After validation, use the `handle-comment` skill to post findings on the relevant nodes — `TASK` for critical violations that must be fixed, `QUESTION` for warnings and recommendations. (That skill already handles the `add_comment` MCP-vs-curl choice internally — no separate rewrite needed here.)
40
+ After validation, use the `handle-comment` skill to post findings on the relevant nodes — `TASK` for critical violations that must be fixed, `COMMENT` for warnings and recommendations. (That skill already handles the `add_comment` MCP-vs-curl choice internally — no separate rewrite needed here.)
41
41
 
42
42
  ## Purpose
43
43
 
@@ -79,7 +79,7 @@ Rules for generating examples:
79
79
  - Make examples **domain-specific**: if the element is called "Order Placed", use order-domain values; if it's "User Registered", use registration-domain values.
80
80
  - Keep examples **short** — one value per field, no paragraphs.
81
81
 
82
- Build the updated `fields` array: same structure as the original, only the `example` property changed where needed. Set `edited: true` on any field you modify.
82
+ Build the updated `fields` array: same structure as the original, only the `example` property changed where needed.
83
83
 
84
84
  ---
85
85
 
@@ -21,20 +21,29 @@ From `$ARGUMENTS` or the calling skill's context, extract:
21
21
  | `nodeId` | UUID of the target node | **required** |
22
22
  | `text` | Comment text (place) or substring to match (resolve/delete) | required for `place`; used to look up comment when `commentId` is absent |
23
23
  | `commentId` | UUID of the comment to resolve/delete | preferred over `text` for resolve/delete |
24
- | `type` | `COMMENT`, `TASK`, or `QUESTION` | `QUESTION` (place only) |
25
- | `author` | Author identifier string | `agent` (place only) |
24
+ | `type` | `COMMENT` or `TASK` | `COMMENT` (place only) |
25
+ | `author` | Author identifier string | `agent-$CLAUDE_CODE_SESSION_ID` (place only) |
26
26
  | `boardId` | Board UUID | from `connect` skill (`BOARD_ID`) |
27
27
 
28
+ Use the session env var, not the literal string `agent` — `CLAUDE_CODE_SESSION_ID` is set by the
29
+ host for every session, so two agents working the same board at once post under distinguishable
30
+ authors instead of an identical one. If the env var is unset (non-Claude-Code host), fall back to
31
+ the literal `agent`.
32
+
33
+ There is no `QUESTION` type at the API level — a question is just a `COMMENT` whose text happens
34
+ to be phrased as a question. Callers that want to flag something as a question should word the
35
+ `text` accordingly, not pass a special `type`.
36
+
28
37
  Route to the matching section below based on `action`.
29
38
 
30
39
  ---
31
40
 
32
41
  ## Action: place
33
42
 
34
- **Prefer MCP** — one call, `type` (`COMMENT`/`TASK`/`QUESTION`) passed straight through:
43
+ **Prefer MCP** — one call, `type` (`COMMENT`/`TASK`) passed straight through:
35
44
 
36
45
  ```
37
- mcp__eventmodelers__add_comment { "boardId": "$BOARD_ID", "nodeId": "$NODE_ID", "text": "<text>", "type": "<COMMENT|TASK|QUESTION>", "author": "<author>" }
46
+ mcp__eventmodelers__add_comment { "boardId": "$BOARD_ID", "nodeId": "$NODE_ID", "text": "<text>", "type": "<COMMENT|TASK>", "author": "<author>" }
38
47
  ```
39
48
 
40
49
  **Fallback (no MCP):** see `references/api-fallback.md` — "Action: place".
@@ -376,9 +376,9 @@ Count inbound edges where `target === COMMAND_NODE_ID` and the source node is ty
376
376
  mcp__eventmodelers__set_connection { "boardId": "<BOARD_ID>", "source": "<extra-issuer-node-id>", "target": "<COMMAND_NODE_ID>", "action": "remove" }
377
377
  ```
378
378
 
379
- If it's not clear which edge is the deliberate one (e.g. neither source sits in the COMMAND's own column), do not guess — leave both edges and post a `QUESTION` comment on the COMMAND node via `handle-comment` instead, describing the ambiguity.
379
+ If it's not clear which edge is the deliberate one (e.g. neither source sits in the COMMAND's own column), do not guess — leave both edges and post a comment on the COMMAND node via `handle-comment` instead, describing the ambiguity.
380
380
 
381
- **Fallback (no MCP)**: there is no documented single-purpose REST endpoint for edge removal outside `/nodes/events`. Connect MCP via the `connect` skill first; if that's genuinely not possible, skip the auto-fix and post a `QUESTION` comment on the COMMAND node flagging the double issuer for manual resolution instead of fabricating a payload.
381
+ **Fallback (no MCP)**: there is no documented single-purpose REST endpoint for edge removal outside `/nodes/events`. Connect MCP via the `connect` skill first; if that's genuinely not possible, skip the auto-fix and post a comment on the COMMAND node flagging the double issuer for manual resolution instead of fabricating a payload.
382
382
 
383
383
  ---
384
384
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: wdyt
3
- description: Business analyst exploration of an event model board. Reads all slices, analyzes them from a business perspective, and posts questions/observations as QUESTION-type comments on relevant nodes. Findings about a relationship between elements or a cluster of elements are always additionally drawn on the canvas (arrows, group loops) — comments carry every textual question, drawings carry every visual/structural hint.
3
+ description: Business analyst exploration of an event model board. Reads all slices, analyzes them from a business perspective, and posts questions/observations as comments on relevant nodes. Findings about a relationship between elements or a cluster of elements are always additionally drawn on the canvas (arrows, group loops) — comments carry every textual question, drawings carry every visual/structural hint.
4
4
  ---
5
5
 
6
6
  # WDYT — What Do You Think?
@@ -113,17 +113,17 @@ Each of these four is inherently about a relationship or cluster of elements, so
113
113
 
114
114
  The two channels have a strict division of labor, always applied the same way — never swap them:
115
115
 
116
- - **Every textual question is a comment.** If the finding is "what happens / who does this / what do we expect" about a single element, it is worded and lives only in a `QUESTION` comment. Never draw a text callout on the canvas to carry a question — that content belongs in 4.1, full stop.
116
+ - **Every textual question is a comment.** If the finding is "what happens / who does this / what do we expect" about a single element, it is worded and lives only in a comment. Never draw a text callout on the canvas to carry a question — that content belongs in 4.1, full stop.
117
117
  - **Every visual/structural hint is a drawing.** If the finding is inherently about *where things are relative to each other* — a relationship between two elements, or a cluster of elements sharing one concern — it is always additionally drawn on the canvas (4.2), not left as text alone. This isn't a selective "top 3" step; it's determined by the shape of the finding itself: relational or clustered → draw it, every time.
118
118
 
119
119
  ### 4.1 Comments (every textual question, always)
120
120
 
121
- For each question you want to ask, post it as a `QUESTION`-type comment on the most relevant node (the COMMAND, EVENT, SCREEN, or READMODEL the question is about). If a question is about the whole slice rather than a specific element, post it on the first/primary EVENT of the slice.
121
+ For each question you want to ask, post it as a comment on the most relevant node (the COMMAND, EVENT, SCREEN, or READMODEL the question is about). If a question is about the whole slice rather than a specific element, post it on the first/primary EVENT of the slice.
122
122
 
123
123
  Use the `handle-comment` skill with `action=place` to post each comment. Pass:
124
124
  - `nodeId` — the UUID of the element the question is about
125
125
  - `text` — your question (one sentence, plain business language)
126
- - `type` — `QUESTION`
126
+ - `type` — `COMMENT` (there is no separate question type — the text itself carries the question)
127
127
  - `author` — `wdyt`
128
128
 
129
129
  The comment API has no batch endpoint — `handle-comment` sends one request per comment. Fire them sequentially.
@@ -137,7 +137,7 @@ Use `POST /api/org/{orgId}/boards/{boardId}/drawing/draw` (auth headers same as
137
137
  - **Arrow** (`kind: "path"`, `arrowEnd: true`) — the concern is about a missing or unclear relationship *between two elements* (e.g. "does this event actually reach this automation?"). Draw a straight line from one element's position to the other's. `path` is `M 0 0 L <dx> <dy>` in the box's own local coordinates; `x`/`y`/`width`/`height` describe that box in canvas space (so `width`/`height` = the delta between the two elements' positions). Get element positions from the slice data already loaded in Step 2 (or `GET .../nodes/{nodeId}` if not present).
138
138
  - **Group loop** (`kind: "rect"`, drawn around a computed bounding box) — the concern spans a *cluster* of elements together (e.g. "this whole flow assumes nothing ever fails"). There's no dedicated group endpoint — union the elements' own `x`/`y`/`width`/`height` (plus some padding) yourself and draw one `rect` around that box via `.../drawing/draw`. This is a visual grouping only — unrelated to the `MODEL_CONTEXT` node type; never touch a `modelContext` field to satisfy this.
139
139
 
140
- Every arrow/group loop is paired with a `QUESTION` comment on the relevant node(s) from 4.1 — the drawing makes the concern visible at a glance on the canvas itself, the comment carries the actual worded question. Post both; neither replaces the other.
140
+ Every arrow/group loop is paired with a comment on the relevant node(s) from 4.1 — the drawing makes the concern visible at a glance on the canvas itself, the comment carries the actual worded question. Post both; neither replaces the other.
141
141
 
142
142
  A finding about a single element with no relational or cluster dimension gets a comment only — don't manufacture an arrow or loop for it just to add a drawing.
143
143
 
@@ -4,7 +4,7 @@ Reusable learnings accumulated while processing prompts for this board. Append n
4
4
  ones in a compressed, reusable form; only add if not already covered here.
5
5
 
6
6
  - `/place-element` requires an existing column — create one via the timeline API if missing.
7
- - `/wdyt` posts QUESTION comments onto nodes — use for analysis only, not modifications.
7
+ - `/wdyt` posts comments onto nodes — use for analysis only, not modifications.
8
8
  - The `board_id`, `timeline_id`, and `organization_id` from each prompt provide full context — pass them to skills that need them.
9
9
  - If a prompt's `context.timelineId` is present and non-null, it overrules the prompt's own `timeline_id` field — it's the chapter the user was pointing at on the canvas, which can differ from whatever chapter the prompt/voice session was scoped to. Resolve `TIMELINE_ID` from `context.timelineId` first, falling back to `timeline_id` only when it's absent, before passing it to any skill.
10
10
  - Same pattern for node references: if a prompt's `context.selectedNodes` array is present and non-empty, its first entry overrules the prompt's own `node_id` field (e.g. for `/handle-comment`'s `nodeId`) — it reflects the actual canvas selection at prompt time, whereas `node_id` is only set when the prompt originated from a specific node/comment.
@@ -42,9 +42,9 @@ At the start of every session, read `.agent-modeling-kit/AGENTS.md` if it exists
42
42
  5. **Invoke the matched skill — never substitute direct tool calls for it.** Execute the prompt using the skill matched in the Skill Selection table below, passing the resolved `TIMELINE_ID`, `NODE_ID`, and `CELL_ID` from step 3 as that skill's `timelineId`/node-reference/`cellName` arguments (not the raw `timeline_id`/`node_id` fields, and not a cell reference parsed from the prompt text). For a skill like `/place-element` that accepts a `cellName`, pass the resolved `CELL_ID` as `cellName` whenever it's present — skip parsing the prompt text for a cell reference entirely in that case.
43
43
 
44
44
  `mcp__eventmodelers__*` tools (and the REST fallback) are building blocks a skill calls *internally* once you've invoked it — they are not a substitute for invoking the skill. Being able to see `mcp__eventmodelers__get_node`/`create_slice`/etc. in your tool list does not mean you should reach for them directly to satisfy a prompt that matches a row in the Skill Selection table: e.g. "add the next slice" always goes through `/eventmodeling-slicing-event-models` (falling through to `/add-next-slice` when nothing existing is left to slice) or `/place-element`, even though technically a couple of raw MCP calls could produce something on the board. The skill is what encodes the actual domain reasoning (which node type follows which, naming, field derivation, dependency notes) — a raw tool call skips all of that and produces a shallower result even when it "works." Only call MCP/REST directly when no row in the table matches the prompt's intent at all.
45
- **Questioning rule**: you are running autonomously — no human is available to answer questions. If you need clarification, do not pause or ask interactively — post a `QUESTION`-type comment (`/handle-comment` with `action=place`, `type=QUESTION`) on the most relevant node. Then:
45
+ **Questioning rule**: you are running autonomously — no human is available to answer questions. If you need clarification, do not pause or ask interactively — post a comment (`/handle-comment` with `action=place`, `type=COMMENT`) on the most relevant node. Then:
46
46
  - If a reasonable default interpretation exists, continue with it.
47
- - If it doesn't — the prompt is ambiguous enough that any guess risks doing the wrong thing — stop instead of guessing. Skip straight to step 6 and mark the prompt `DONE` with a comment explaining what's unclear and pointing to the `QUESTION` comment you just posted. Never leave a prompt neither progressed nor closed.
47
+ - If it doesn't — the prompt is ambiguous enough that any guess risks doing the wrong thing — stop instead of guessing. Skip straight to step 6 and mark the prompt `DONE` with a comment explaining what's unclear and pointing to the comment you just posted. Never leave a prompt neither progressed nor closed.
48
48
  6. **Mark the prompt as finished** — invoke `/update-prompt-status` with this turn's `prompt_id`, `newStatus=DONE`, and a `comment` that summarizes what you actually did (e.g. "Added the OrderPlaced event and wired it to the read model"). Do this once, right after the work is done — not per skill call within the turn.
49
49
  7. If this turn has a `comment_id` field, invoke `/handle-comment` with `action=resolve`, `nodeId` from the resolved `NODE_ID` (step 3), `commentId` from `comment_id`.
50
50
  8. Append a progress entry to `progress.txt` — see the Progress Entry Format below. Fill in the `Learnings` line with anything reusable noticed this turn (pattern, gotcha, useful context), or "none".
@@ -51,7 +51,7 @@ When asked to build a slice, always follow this flow:
51
51
  - **State-view** — `projections` or `queries` array is non-empty → invoke `/build-state-view`
52
52
  - **State-change** — default (has `commands` / `events`) → invoke `/build-state-change`
53
53
  3. Invoke the matching skill and follow its instructions completely. Do not deviate.
54
- 4. **Verify against slice.json**: After the skill completes, check that every command field, event field, and specification in slice.json appears in the implementation. No invented fields — if it is not in slice.json, it must not be in the code.
54
+ 4. **Verify against slice.json**: After the skill completes, check that every command field, event field, and specification in slice.json appears in the implementation. No invented fields — if it is not in slice.json, it must not be in the code. This applies even when the slice was previously `Done` and reappears as `Planned` — never dismiss a mismatch as "already implemented" or harmless drift; diff slice.json against the code field by field and update the code to match every change.
55
55
  5. Run quality checks (`npm run build`, then the slice tests only).
56
56
  6. If checks pass, commit with `feat: [Slice Name]` and set slice status to `Done`.
57
57
 
@@ -81,7 +81,9 @@ When asked to build a slice, always follow this flow:
81
81
  3. Invoke the matching skill and follow its instructions completely. Do not deviate.
82
82
  4. **Verify against slice.json**: After the skill completes, check that every command field, event field,
83
83
  and specification in slice.json appears in the implementation. No invented fields — if it is not in
84
- slice.json, it must not be in the code.
84
+ slice.json, it must not be in the code. This applies even when the slice was previously `Done` and
85
+ reappears as `Planned` — never dismiss a mismatch as "already implemented" or harmless drift; diff
86
+ slice.json against the code field by field and update the code to match every change.
85
87
  5. Run quality checks (`./mvnw compile -q`, then the slice tests only).
86
88
  6. If checks pass, commit with `feat: [Slice Name]` and set slice status to `Done`.
87
89
 
@@ -52,7 +52,7 @@ When asked to build a slice, always follow this flow:
52
52
  - **State-view** — `projections` or `queries` array is non-empty → invoke `/build-state-view`
53
53
  - **State-change** — default (has `commands` / `events`) → invoke `/build-state-change`
54
54
  3. Invoke the matching skill and follow its instructions completely. Do not deviate.
55
- 4. **Verify against slice.json**: After the skill completes, check that every command field, event field, and specification in slice.json appears in the implementation. No invented fields — if it is not in slice.json, it must not be in the code.
55
+ 4. **Verify against slice.json**: After the skill completes, check that every command field, event field, and specification in slice.json appears in the implementation. No invented fields — if it is not in slice.json, it must not be in the code. This applies even when the slice was previously `Done` and reappears as `Planned` — never dismiss a mismatch as "already implemented" or harmless drift; diff slice.json against the code field by field and update the code to match every change.
56
56
  5. Run quality checks (`npm run build`, then the slice tests only).
57
57
  6. If checks pass, commit with `feat: [Slice Name]` and set slice status to `Done`.
58
58
 
@@ -64,7 +64,7 @@ When asked to build a slice, always follow this flow:
64
64
  - **State-view** — `projections` or `queries` array is non-empty → invoke `/build-state-view`
65
65
  - **State-change** — default (has `commands` / `events`) → invoke `/build-state-change`
66
66
  3. Invoke the matching skill and follow its instructions completely. Do not deviate.
67
- 4. **Verify against slice.json**: After the skill completes, check that every command field, event field, and specification in slice.json appears in the implementation. No invented fields — if it is not in slice.json, it must not be in the code.
67
+ 4. **Verify against slice.json**: After the skill completes, check that every command field, event field, and specification in slice.json appears in the implementation. No invented fields — if it is not in slice.json, it must not be in the code. This applies even when the slice was previously `Done` and reappears as `Planned` — never dismiss a mismatch as "already implemented" or harmless drift; diff slice.json against the code field by field and update the code to match every change.
68
68
  5. Run quality checks (`./mvnw compile -q`, then the slice tests only).
69
69
  6. If checks pass, commit with `feat: [Slice Name]` and set slice status to `Done`.
70
70