@milehimikey/em 0.2.0 → 1.0.0
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/.claude/skills/event-modeling/SKILL.md +80 -25
- package/.claude/skills/event-modeling/reference/em-dsl.md +18 -0
- package/.claude/skills/event-modeling/reference/frontmatter.md +129 -0
- package/.claude/skills/event-modeling/reference/methodology.md +10 -0
- package/.claude/skills/event-modeling/templates/model-readme.md +4 -4
- package/.claude/skills/event-modeling/templates/slice.md +4 -2
- package/.claude/skills/event-modeling/templates/state.md +14 -3
- package/README.md +31 -2
- package/dist/cli.js +227 -4
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +15 -0
- package/dist/config.js +60 -0
- package/dist/config.js.map +1 -0
- package/dist/migrate/migrate.d.ts +26 -0
- package/dist/migrate/migrate.js +276 -0
- package/dist/migrate/migrate.js.map +1 -0
- package/dist/model/deriveSliceFields.d.ts +21 -0
- package/dist/model/deriveSliceFields.js +60 -0
- package/dist/model/deriveSliceFields.js.map +1 -0
- package/dist/model/frontmatter.d.ts +21 -0
- package/dist/model/frontmatter.js +38 -0
- package/dist/model/frontmatter.js.map +1 -0
- package/dist/model/model.js +2 -17
- package/dist/model/model.js.map +1 -1
- package/dist/model/sliceDoc.d.ts +56 -0
- package/dist/model/sliceDoc.js +28 -0
- package/dist/model/sliceDoc.js.map +1 -0
- package/dist/model/validate.d.ts +2 -0
- package/dist/model/validate.js +1 -1
- package/dist/model/validate.js.map +1 -1
- package/dist/model/validateSliceDocs.d.ts +7 -0
- package/dist/model/validateSliceDocs.js +195 -0
- package/dist/model/validateSliceDocs.js.map +1 -0
- package/dist/slice/generate.d.ts +17 -0
- package/dist/slice/generate.js +61 -0
- package/dist/slice/generate.js.map +1 -0
- package/dist/slice/query.d.ts +42 -0
- package/dist/slice/query.js +96 -0
- package/dist/slice/query.js.map +1 -0
- package/dist/slice/sync.d.ts +18 -0
- package/dist/slice/sync.js +104 -0
- package/dist/slice/sync.js.map +1 -0
- package/dist/util/findModel.d.ts +1 -0
- package/dist/util/findModel.js +27 -0
- package/dist/util/findModel.js.map +1 -0
- package/dist/util/slug.d.ts +4 -0
- package/dist/util/slug.js +32 -0
- package/dist/util/slug.js.map +1 -0
- package/package.json +4 -3
|
@@ -16,9 +16,10 @@ You are facilitating an Event Modeling session. Your job is to **extract an accu
|
|
|
16
16
|
the user through Socratic questioning** — never to invent the domain. You drive the `em` CLI to
|
|
17
17
|
render the model live, and you produce implementation-ready slice design docs.
|
|
18
18
|
|
|
19
|
-
Read `reference/methodology.md` (the 7 steps + 4 patterns)
|
|
20
|
-
|
|
21
|
-
`
|
|
19
|
+
Read `reference/methodology.md` (the 7 steps + 4 patterns), `reference/em-dsl.md` (DSL syntax +
|
|
20
|
+
validation rules), and — before the `slice` phase specifically — `reference/frontmatter.md` (the
|
|
21
|
+
slice-doc frontmatter schema, lifecycle, and `em slice` CLI) before doing real work; they are the
|
|
22
|
+
source of truth. Templates live in `templates/`.
|
|
22
23
|
|
|
23
24
|
## Operating principles (every phase)
|
|
24
25
|
|
|
@@ -45,7 +46,8 @@ Read `reference/methodology.md` (the 7 steps + 4 patterns) and `reference/em-dsl
|
|
|
45
46
|
only that one adjacent event, so every arrow is short (a read model far from its source events
|
|
46
47
|
draws long arrows that look like a forbidden read→read link). Repeats render cleanly — em only
|
|
47
48
|
warns on a duplicate name that's *referenced* by `from`/`arrow`. Slice order matters: a reaction
|
|
48
|
-
must be directly followed by its command slice, and a read slice must not be
|
|
49
|
+
must be directly followed by its command slice, and a read slice must not be immediately
|
|
50
|
+
followed by a command slice (see `em-dsl.md`).
|
|
49
51
|
See `reference/methodology.md` (State View) and `reference/em-dsl.md`.
|
|
50
52
|
- **Validate continuously.** Run `em validate` and fix errors/warnings as you go (see DSL ref).
|
|
51
53
|
- **Save state at the end of every session** so work resumes cleanly.
|
|
@@ -57,7 +59,13 @@ Read `reference/methodology.md` (the 7 steps + 4 patterns) and `reference/em-dsl
|
|
|
57
59
|
2. Locate the model. Look for an existing `<dir>/.event-modeling.md` and `*.em` in the working
|
|
58
60
|
directory (or a `models/` subfolder). If found, read the state file. If not, and the phase
|
|
59
61
|
needs one, ask the user for the model name and where to create it.
|
|
60
|
-
3.
|
|
62
|
+
3. **Pre-1.0 model check.** If a `slices/*.md` doc exists with no YAML frontmatter block (run
|
|
63
|
+
`em validate <model>.em` — a missing-frontmatter doc errors with a message pointing at this),
|
|
64
|
+
tell the user this model predates the frontmatter standard and offer to run
|
|
65
|
+
`em migrate <model-dir>` before continuing (it refuses a dirty git tree by default — commit
|
|
66
|
+
first, or pass `--force`). Don't hand-edit old-format docs around this; migrate once, then
|
|
67
|
+
proceed normally.
|
|
68
|
+
4. Parse the argument (`$ARGUMENTS`) to pick the phase below. With **no argument**, read the
|
|
61
69
|
state file and resume the recorded phase/step; if no model exists, propose starting `discover`.
|
|
62
70
|
|
|
63
71
|
## Project layout this skill creates
|
|
@@ -68,14 +76,24 @@ Read `reference/methodology.md` (the 7 steps + 4 patterns) and `reference/em-dsl
|
|
|
68
76
|
<model-name>.svg # render target for em watch
|
|
69
77
|
live.html # auto-refresh viewer (copy of templates/live.html, SVG_FILE set)
|
|
70
78
|
README.md # overview + slice index (from templates/model-readme.md)
|
|
71
|
-
.event-modeling.md # resumable state (from templates/state.md)
|
|
72
|
-
|
|
79
|
+
.event-modeling.md # resumable state (from templates/state.md, with frontmatter)
|
|
80
|
+
em.config.json # optional: { "sliceTemplate": "..." } for a team's own slice template
|
|
81
|
+
slices/<slice-id>.md # one rich slice doc per slice, scaffolded via `em slice new`
|
|
73
82
|
```
|
|
74
83
|
|
|
75
|
-
When creating a new model, scaffold the directory, copy the
|
|
76
|
-
placeholders), and set `SVG_FILE` in the copied `live.html` to
|
|
77
|
-
`em init` for a starter `.em`, but usually you'll build it up from
|
|
78
|
-
instead. Fill template placeholders — never leave `{{...}}` in
|
|
84
|
+
When creating a new model, scaffold the directory, copy the `model-readme.md`/`state.md`
|
|
85
|
+
templates in (filling the placeholders), and set `SVG_FILE` in the copied `live.html` to
|
|
86
|
+
`<model-name>.svg`. You may use `em init` for a starter `.em`, but usually you'll build it up from
|
|
87
|
+
the discovery conversation instead. Fill template placeholders — never leave `{{...}}` in
|
|
88
|
+
delivered files. **Slice docs are the one exception**: don't hand-copy `templates/slice.md` —
|
|
89
|
+
use `em slice new` (see the `slice` phase below), which injects the required frontmatter and
|
|
90
|
+
respects a project's `em.config.json` custom template if one is configured.
|
|
91
|
+
|
|
92
|
+
Ask the **Regulatory scope** session input (state.md) up front, alongside Scope line / PRD
|
|
93
|
+
reference / Headless-API-model: does this domain have compliance requirements (PCI-DSS, SOX,
|
|
94
|
+
HIPAA, GDPR, ...) or none? This decides whether the `slice` phase asks about the `compliance:`
|
|
95
|
+
frontmatter block per slice (see `reference/frontmatter.md`) — don't ask about compliance at all
|
|
96
|
+
for a model with no regulatory scope.
|
|
79
97
|
|
|
80
98
|
---
|
|
81
99
|
|
|
@@ -84,9 +102,16 @@ instead. Fill template placeholders — never leave `{{...}}` in delivered files
|
|
|
84
102
|
Goal: a draft model of events, storyboard, commands, and views. Loose is OK; structure comes next.
|
|
85
103
|
|
|
86
104
|
1. **Brainstorm events (step 1).** Ask the user to name everything that happens, as past-tense
|
|
87
|
-
facts.
|
|
105
|
+
facts. Probe for missed state changes. For each candidate, apply the **"is it an event?"
|
|
106
|
+
test** (`reference/methodology.md` step 1 — the "would this wake the CEO at 3am" heuristic):
|
|
107
|
+
reject derived values (belong in a read model) and telemetry/activity (not business state).
|
|
108
|
+
Don't silently drop rejections — park them in the state file's Decisions log with why, so
|
|
109
|
+
they aren't re-proposed later. Capture the survivors as a flat list.
|
|
88
110
|
2. **Plot / storyboard (step 2).** Order the events into the narrative. Identify **personas**
|
|
89
111
|
(actors) and the **UI** screens at each step. Add `persona` declarations and `ui` elements.
|
|
112
|
+
In a **headless/API** model there are no personas or screens — identify the external
|
|
113
|
+
**callers** at each step instead; they become the inbound write translations and read
|
|
114
|
+
translations (see `reference/methodology.md`).
|
|
90
115
|
3. **Inputs (step 3).** For each event, find the **command** that causes it (imperative name).
|
|
91
116
|
Form `command → event` slices (State Change pattern).
|
|
92
117
|
4. **Outputs (step 4).** Identify the **read models / views** consumers need and wire them with
|
|
@@ -134,17 +159,33 @@ the corresponding event/slice to the `.em` and re-render. The happy-path spine f
|
|
|
134
159
|
phases is the starting point, not the finished event set.
|
|
135
160
|
|
|
136
161
|
For each slice:
|
|
137
|
-
1.
|
|
138
|
-
|
|
139
|
-
|
|
162
|
+
1. Scaffold the doc: `em slice new "<Slice Name>" --pattern <state-change|state-view|automation|translation>`.
|
|
163
|
+
This writes `slices/<id>.md` with the required frontmatter already filled in (`id`, `pattern`,
|
|
164
|
+
`status: draft`, `version: 1`, …) and the body template (custom, if `em.config.json` configures
|
|
165
|
+
one; the shipped default otherwise) ready to fill in.
|
|
166
|
+
2. Hold a Socratic deep-dive to fill every body section: intent, trigger/actor, command + field
|
|
167
|
+
table (types & rules), event(s) + payload (mark immutable facts), invariants (give each a
|
|
168
|
+
stable ID), Given/When/Then scenarios (happy path + rule boundaries + edge cases),
|
|
140
169
|
alternate/error flows (retries, idempotency, compensations), read models affected, open
|
|
141
|
-
questions. Park anything unresolved rather than guessing.
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
170
|
+
questions. Park anything unresolved rather than guessing. Pattern and status are frontmatter
|
|
171
|
+
now, not prose — see `reference/frontmatter.md`. If the model's **Regulatory scope** (state
|
|
172
|
+
file) isn't "none," additionally ask whether *this* slice touches regulated data or processes;
|
|
173
|
+
if so, hand-add a `compliance:` block to the doc's frontmatter (see `reference/frontmatter.md`
|
|
174
|
+
for the suggested shape — `em` never validates it, so use whatever sub-fields fit). Skip this
|
|
175
|
+
question entirely for non-regulated models, and skip the block for slices with no compliance
|
|
176
|
+
relevance even in a regulated model — don't ask by rote.
|
|
177
|
+
3. Wire it into the `.em`: add `note "slices/<id>.md"` to the slice's primary element (the command
|
|
178
|
+
for State Change, the view for State View, the processor for Automation, the translation for
|
|
179
|
+
Translation).
|
|
180
|
+
4. Run `em slice sync <id>` — it discovers the linked element from that `note` and fills in the
|
|
181
|
+
generated frontmatter fields (`commands`/`events`/`readModels`/`contexts`/`personas`, and
|
|
182
|
+
`triggers`/`triggeredBy` for automation/translation). **Re-run `em slice sync <id>` (or
|
|
183
|
+
`--all`) after any later `.em` edit that touches this slice's elements** — generated fields
|
|
184
|
+
drift otherwise, and `em validate` will flag it.
|
|
185
|
+
5. When the doc is solid, move it forward: `em slice update <id> --status reviewed` (and later
|
|
186
|
+
`--status ready-to-implement`). Update `README.md`'s slice index.
|
|
187
|
+
6. Re-render and `em validate` (validates the `.em` **and** every slice doc's frontmatter by
|
|
188
|
+
default).
|
|
148
189
|
|
|
149
190
|
## Phase: `watch` — live team view
|
|
150
191
|
|
|
@@ -159,8 +200,13 @@ For each slice:
|
|
|
159
200
|
## Phase: `validate`
|
|
160
201
|
|
|
161
202
|
Run `em validate <model-name>.em` and walk through each diagnostic with the user, explaining the
|
|
162
|
-
rule (see `reference/em-dsl.md`
|
|
163
|
-
|
|
203
|
+
rule (see `reference/em-dsl.md` for `.em` rules, `reference/frontmatter.md` for slice-doc
|
|
204
|
+
frontmatter rules) and proposing the fix. Apply fixes on agreement:
|
|
205
|
+
- `.em`-level fixes: split an automation's command into the next slice, add a missing `from`, give
|
|
206
|
+
a command its event.
|
|
207
|
+
- Slice-doc-level fixes: no frontmatter block → run `em migrate` (pre-1.0 model); "out of sync
|
|
208
|
+
with .em" → run `em slice sync <id>`; orphan doc → wire a `note "slices/<id>.md"` onto the
|
|
209
|
+
right element, then sync.
|
|
164
210
|
|
|
165
211
|
Then do one check `em validate` can't: scan every `translation`/`processor`/`automation` slice and
|
|
166
212
|
confirm none contains an `event` — each reaction must trigger a `command` in the next slice
|
|
@@ -174,11 +220,20 @@ two slices and route it through a command.
|
|
|
174
220
|
```bash
|
|
175
221
|
em --version
|
|
176
222
|
em init <name>.em # optional starter scaffold
|
|
177
|
-
em validate <name>.em # check rules
|
|
223
|
+
em validate <name>.em # check .em rules + slice-doc frontmatter
|
|
178
224
|
em render <name>.em -o <name>.svg # render (svg/png/pdf by extension)
|
|
179
225
|
em render <name>.em --emit-dot # inspect generated Graphviz DOT
|
|
180
226
|
em watch <name>.em -o <name>.svg # re-render on save (run in background)
|
|
227
|
+
|
|
228
|
+
em slice new "<Slice Name>" --pattern <pattern> # scaffold slices/<id>.md with frontmatter
|
|
229
|
+
em slice sync <id> # after wiring note "slices/<id>.md" into the .em
|
|
230
|
+
em slice update <id> --status <status> # move a slice's lifecycle status forward
|
|
231
|
+
em slice list / show <id> / search "<query>" # query slice docs by frontmatter (--format json)
|
|
232
|
+
em slice search "<q>" --format json --full # ...with every field, not just the summary row
|
|
233
|
+
em migrate <model-dir> # one-time upgrade from a pre-1.0 model
|
|
181
234
|
```
|
|
182
235
|
|
|
236
|
+
See `reference/frontmatter.md` for the full slice-doc frontmatter schema and CLI reference.
|
|
237
|
+
|
|
183
238
|
Always finish a working session by: re-rendering, running `em validate`, and updating
|
|
184
239
|
`.event-modeling.md` with the current phase/step, decisions, and open questions.
|
|
@@ -20,6 +20,21 @@ em validate <file> # check event-modeling rules; exit 0 if only warn
|
|
|
20
20
|
Install if missing: `npm i -g @milehimikey/em`. PNG works with no system deps; PDF needs
|
|
21
21
|
`rsvg-convert`.
|
|
22
22
|
|
|
23
|
+
**Slice docs** (frontmatter, lifecycle, search — see `reference/frontmatter.md` for the schema):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
em slice new "Slice Name" [--pattern state-change] [--id <id>] # scaffold slices/<id>.md
|
|
27
|
+
em slice sync <id> # after wiring note "slices/<id>.md" into the .em
|
|
28
|
+
em slice sync --all # re-sync every doc in the model directory
|
|
29
|
+
em slice list [--status <s>] [--pattern <p>] [--context <c>] [--tag <t>] [--format json] [--full]
|
|
30
|
+
em slice show <id> [--body] [--format json]
|
|
31
|
+
em slice search "<query>" [--pattern <p>] [--status <s>] [--context <c>] [--tag <t>] [--format json] [--full]
|
|
32
|
+
em slice update <id> [--status <s>] [--bump-version]
|
|
33
|
+
em migrate <model-dir> [--dry-run] [--report <path>] # one-time upgrade from a pre-1.0 model
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`em validate <file>` also validates every doc in `slices/` by default (`--skip-slices` to opt out).
|
|
37
|
+
|
|
23
38
|
---
|
|
24
39
|
|
|
25
40
|
## Grammar
|
|
@@ -156,6 +171,9 @@ slice "Read Quote — created" { view Quote from "QuoteCreated" translation S
|
|
|
156
171
|
- A **read** slice (read model → read translation, no command) must **not** be immediately followed
|
|
157
172
|
by a `command` slice, or the read translation will be mis-wired to that command. Put reads after a
|
|
158
173
|
command+event slice, or before another read / a reaction / an inbound `(request)` slice.
|
|
174
|
+
- A read model fed by an early event (e.g. a queue or to-do view) can't always sit directly after
|
|
175
|
+
its source event when a reaction must immediately precede its command slice — placing the read
|
|
176
|
+
later, in narrative order with a longer arrow, is the correct trade-off, not something to force-fix.
|
|
159
177
|
|
|
160
178
|
---
|
|
161
179
|
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Slice Frontmatter Reference
|
|
2
|
+
|
|
3
|
+
Every slice doc (`slices/<id>.md`) starts with a required YAML frontmatter block, injected by
|
|
4
|
+
`em slice new` and kept fresh by `em slice sync`. This is what makes slices searchable and
|
|
5
|
+
versionable by AI agents across a model with hundreds of slices, without reading every doc's body.
|
|
6
|
+
Full rationale: `docs/1.0.0-spec.md` in the `em` repo. This file is the quick reference for
|
|
7
|
+
day-to-day use.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Fields
|
|
12
|
+
|
|
13
|
+
**Core identity** (required, `em slice new` sets these):
|
|
14
|
+
|
|
15
|
+
| Field | Meaning |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `schemaVersion` | Frontmatter format version. `1`. |
|
|
18
|
+
| `id` | Stable key, kebab-case, generated once. **Never** re-derived from the title. Reference slices by `id`, never by title or filename. |
|
|
19
|
+
| `title` | Human display name. |
|
|
20
|
+
| `pattern` | `state-change \| state-view \| automation \| translation` — the read/write/automation/translation facet. |
|
|
21
|
+
| `status` | See Lifecycle below. |
|
|
22
|
+
| `version` | Integer, bumped via `em slice update --bump-version` on a meaningful content change. Git log is the real history — this is just a "has it changed" signal. |
|
|
23
|
+
| `model` | Relative path to the `.em` file. |
|
|
24
|
+
| `sliceElement` | The `.em` `Element.id` this doc is linked from (via `note "slices/<id>.md"`). |
|
|
25
|
+
|
|
26
|
+
**Generated** (never hand-edit — run `em slice sync` after any `.em` edit that touches this
|
|
27
|
+
slice's elements):
|
|
28
|
+
|
|
29
|
+
| Field | Meaning |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `commands`, `events`, `readModels` | Names of the command/event/view elements in this slice. |
|
|
32
|
+
| `contexts`, `personas` | Contexts/personas touched by this slice's event/ui elements. |
|
|
33
|
+
| `triggers` | (automation/translation only) The `id` of the slice doc for the command this reaction triggers, in the next slice. |
|
|
34
|
+
| `triggeredBy` | (command slices only) The inverse — set on the doc for the command an automation/translation triggers. |
|
|
35
|
+
|
|
36
|
+
`em validate` warns "frontmatter out of sync with .em; run \`em slice sync\`" if these drift from
|
|
37
|
+
what the `.em` actually says. It never auto-fixes this — you have to run `sync` yourself.
|
|
38
|
+
|
|
39
|
+
**Optional / authored:**
|
|
40
|
+
|
|
41
|
+
| Field | Meaning |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `swimlane` | `{ persona, context }` — structured form of the body's `**Swimlane:**` line. |
|
|
44
|
+
| `upstreamEvents` | Only for dependencies **not** visible in the `.em`'s wiring (an invariant reading state from an event not consumed via `from`). If the `.em` already expresses it, it belongs in the generated fields above, not here. |
|
|
45
|
+
| `relatedSlices` | Freeform cross-references to other slice `id`s. |
|
|
46
|
+
| `tags` | Free text, searchable via `em slice search --tag`. |
|
|
47
|
+
| `owner`, `created`, `updated` | |
|
|
48
|
+
| `supersededBy`, `implementedRef` | Written by external build tools, not by `em` — see Handoff below. |
|
|
49
|
+
|
|
50
|
+
**`compliance` — reserved, unvalidated.** For regulated domains (financial, medical, etc.). `em`
|
|
51
|
+
never writes, reads, or validates this key — it's a documented convention only, so it works the
|
|
52
|
+
same way across industries without `em` having to know any regulation's specifics. Only ask about
|
|
53
|
+
it when the model's Regulatory scope (state file) isn't "none" — see the `slice` phase below.
|
|
54
|
+
|
|
55
|
+
```yaml
|
|
56
|
+
compliance:
|
|
57
|
+
frameworks: [PCI-DSS, SOX, GAAP] # or [HIPAA], [GDPR], etc. — whatever applies
|
|
58
|
+
dataClassification: restricted # public | internal | confidential | restricted
|
|
59
|
+
sensitiveDataCategories: [PCI, financial] # freeform: PCI, PHI, PII, financial, biometric, ...
|
|
60
|
+
controlRefs: [PCI-DSS-3.4, SOX-404] # specific control/citation ids
|
|
61
|
+
retention: 7y
|
|
62
|
+
dataResidency: US-only
|
|
63
|
+
reviewedBy: jane@co.com
|
|
64
|
+
reviewedAt: 2026-06-01
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`em slice search` includes this block in its free-text match, so it stays findable even though
|
|
68
|
+
it's unvalidated (e.g. `em slice search "PCI-DSS"`).
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Lifecycle
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
draft → reviewed → ready-to-implement → in-progress → implemented → (deprecated | superseded)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
- `draft` / `reviewed` / `ready-to-implement` — the `slice` phase drives these. Move a doc forward
|
|
79
|
+
with `em slice update <id> --status <status>`.
|
|
80
|
+
- `in-progress` / `implemented` / `deprecated` / `superseded` — **post-handoff.** `em` never writes
|
|
81
|
+
these; they exist so validation tolerates a build tool writing them back into the same file.
|
|
82
|
+
Don't set these yourself during a design session.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Handoff to build / SDD tooling
|
|
87
|
+
|
|
88
|
+
A slice is **ready** when `status` is `ready-to-implement` or later, **and** `em validate` is
|
|
89
|
+
clean for both the `.em` and this doc. At that point, here's what's authoritative for whatever
|
|
90
|
+
implements it:
|
|
91
|
+
|
|
92
|
+
- **`id`** — the only stable key. Never key generated code, tests, or tickets on title/filename.
|
|
93
|
+
- **Command/Input field table** — the real parameter contract (richer than the `.em`'s lightweight
|
|
94
|
+
inline `{ field: Type }`, which is a structural preview only — they aren't cross-validated in
|
|
95
|
+
1.0, so the doc wins if they disagree).
|
|
96
|
+
- **Event table's "Immutable Fact?" column** — treat as compile-time-enforced immutability.
|
|
97
|
+
- **`INV-n` invariant ids** — cite them in generated tests (`test("INV-1: ...")`).
|
|
98
|
+
- **Given/When/Then** — acceptance criteria. Happy path is the floor; rule-boundary scenarios
|
|
99
|
+
trace to their `INV-n`.
|
|
100
|
+
- **Alternate & Error Flows** — required test cases, not optional.
|
|
101
|
+
- `triggers`/`triggeredBy` plus upstream/downstream (joining doc + `.em`) — a sequencing hint for
|
|
102
|
+
a build orchestrator (don't build a slice until its upstream slices are `implemented`),
|
|
103
|
+
advisory only.
|
|
104
|
+
|
|
105
|
+
`em` never clobbers fields it doesn't recognize on write (`sync`/`update` shallow-merge) — a build
|
|
106
|
+
tool's own bookkeeping fields survive.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## CLI
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
em slice new "Place Order" [--pattern state-change] [--id <id>] # scaffold slices/<id>.md
|
|
114
|
+
em slice sync <id> # after wiring `note "slices/<id>.md"` into the .em
|
|
115
|
+
em slice sync --all # re-sync every doc in the directory
|
|
116
|
+
em slice list [--status <s>] [--pattern <p>] [--context <c>] [--tag <t>] [--format json] [--full]
|
|
117
|
+
em slice show <id> [--body] [--format json]
|
|
118
|
+
em slice search "<query>" [--pattern <p>] [--status <s>] [--context <c>] [--tag <t>] [--format json] [--full]
|
|
119
|
+
em slice update <id> [--status <s>] [--bump-version]
|
|
120
|
+
em migrate <model-dir> [--dry-run] [--report <path>] # one-time upgrade from a pre-1.0 model
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
All commands take `--dir <path>` (default `.`) and `--model <path.em>` if a directory has more
|
|
124
|
+
than one `.em` file. `list`/`show`/`search` read **frontmatter only** — never the `.em`, never the
|
|
125
|
+
doc body — so they stay cheap across a large model.
|
|
126
|
+
|
|
127
|
+
`list`/`search` emit a summary row per slice by default. Add **`--full`** (with `--format json`)
|
|
128
|
+
to get every frontmatter field instead — use it when you need the filtered slices' commands,
|
|
129
|
+
events, or contexts, so you don't follow a search with one `slice show` per hit.
|
|
@@ -111,6 +111,16 @@ List the domain **events** as past-tense facts, unordered at first. Go wide; cap
|
|
|
111
111
|
state change anyone can think of. No commands, no UI yet — just facts.
|
|
112
112
|
- Prompts: *"What are all the things that happen in this process? Say each as something that
|
|
113
113
|
already occurred. What changed when that happened?"*
|
|
114
|
+
- **Is it an event?** Events here are *business* facts, not technical ones. Test: if this fact
|
|
115
|
+
failed to occur, would it wake the CEO at 3am? Yes → event. No → not an event.
|
|
116
|
+
- **Yes:** Order Created, Item Added to Order, Order Shipped, Order Delivered, Order
|
|
117
|
+
Cancelled, User Registered, Item Provisioned.
|
|
118
|
+
- **No — derived values** (a read model computes these from other events; they aren't
|
|
119
|
+
independent facts): Order Total Calculated, Order Tax Calculated, Discount Applied.
|
|
120
|
+
- **No — activity, not business state** (telemetry, not something the domain decides on):
|
|
121
|
+
User Clicked Button, User Viewed Page, User Logged In.
|
|
122
|
+
- Model the process the business **needs**, not how the current system happens to work. Existing
|
|
123
|
+
system behavior is a common source of fake events — screens and tables leaking in as facts.
|
|
114
124
|
- Output: a flat list of candidate `event` names.
|
|
115
125
|
|
|
116
126
|
### Step 2 — The Plot / Storyboard *(discover)*
|
|
@@ -19,10 +19,10 @@ Static render: `em render {{model-name}}.em -o {{model-name}}.svg`
|
|
|
19
19
|
- **Translation** — External input (or Read Model) → Translation → (next slice) Command → Event
|
|
20
20
|
|
|
21
21
|
## Slices
|
|
22
|
-
<!-- Keep this index in sync as slice docs are written. -->
|
|
23
|
-
| # | Slice | Pattern | Design doc |
|
|
24
|
-
|
|
25
|
-
| 1 | {{Slice Name}} | {{Pattern}} | [slices/{{slice-
|
|
22
|
+
<!-- Keep this index in sync as slice docs are written (or regenerate from `em slice list`). -->
|
|
23
|
+
| # | Slice | Pattern | Status | Design doc |
|
|
24
|
+
|---|-------|---------|--------|------------|
|
|
25
|
+
| 1 | {{Slice Name}} | {{Pattern}} | {{status}} | [slices/{{slice-id}}.md](slices/{{slice-id}}.md) |
|
|
26
26
|
|
|
27
27
|
## Status
|
|
28
28
|
See [`.event-modeling.md`](.event-modeling.md) for current phase, decisions, and open questions.
|
|
@@ -3,13 +3,15 @@ Rich slice design document. One per slice, stored in <model>/slices/<slice-name>
|
|
|
3
3
|
linked from the .em model with: note "slices/<slice-name>.md" on the slice's defining element.
|
|
4
4
|
Fill every section through Socratic questioning. Leave "Open Questions" rather than guessing.
|
|
5
5
|
Replace the bracketed placeholders; delete guidance comments before finishing.
|
|
6
|
+
|
|
7
|
+
This is the body template only — `em slice new` injects the required frontmatter block above
|
|
8
|
+
this content (id, pattern, status, version, sliceElement, and the generated search fields).
|
|
9
|
+
Pattern and status live there now, not as prose here — see reference/frontmatter.md.
|
|
6
10
|
-->
|
|
7
11
|
|
|
8
12
|
# Slice: {{Slice Name}}
|
|
9
13
|
|
|
10
|
-
- **Pattern:** {{State Change | State View | Automation | Translation}}
|
|
11
14
|
- **Swimlane:** {{Persona/Actor}} → {{Context/Aggregate}}
|
|
12
|
-
- **Status:** {{draft | reviewed | ready-to-implement}}
|
|
13
15
|
|
|
14
16
|
## Intent
|
|
15
17
|
{{Why this slice exists — the user or business goal it serves, in one or two sentences.}}
|
|
@@ -4,6 +4,11 @@ The skill reads this on `/event-modeling` (no arg) to resume where you left off.
|
|
|
4
4
|
Keep it current at the end of every working session.
|
|
5
5
|
-->
|
|
6
6
|
|
|
7
|
+
---
|
|
8
|
+
schemaVersion: 1
|
|
9
|
+
model: {{model-name}}.em
|
|
10
|
+
---
|
|
11
|
+
|
|
7
12
|
# Event Modeling Progress — {{Model Name}}
|
|
8
13
|
|
|
9
14
|
- **Model file:** `{{model-name}}.em`
|
|
@@ -11,6 +16,12 @@ Keep it current at the end of every working session.
|
|
|
11
16
|
- **Current step:** {{1–7, see methodology}}
|
|
12
17
|
- **Last updated:** {{YYYY-MM-DD}}
|
|
13
18
|
|
|
19
|
+
## Session inputs
|
|
20
|
+
- **Scope line:** {{one-line description of what's in/out of bounds for this model}}
|
|
21
|
+
- **PRD / spec reference:** {{path, link, or "none"}}
|
|
22
|
+
- **Headless/API model:** {{yes | no}}
|
|
23
|
+
- **Regulatory scope:** {{e.g. PCI-DSS, SOX, HIPAA, or "none"}}
|
|
24
|
+
|
|
14
25
|
## Steps completed
|
|
15
26
|
- [ ] 1. Brainstorm events
|
|
16
27
|
- [ ] 2. Plot / storyboard (personas + UI)
|
|
@@ -29,6 +40,6 @@ Keep it current at the end of every working session.
|
|
|
29
40
|
- [ ] {{question}}
|
|
30
41
|
|
|
31
42
|
## Slice inventory
|
|
32
|
-
| Slice | Pattern | Doc status |
|
|
33
|
-
|
|
34
|
-
| {{Slice Name}} | {{
|
|
43
|
+
| Slice | Id | Pattern | Doc status |
|
|
44
|
+
|-------|-----|---------|------------|
|
|
45
|
+
| {{Slice Name}} | {{slice-id}} | {{state-change/state-view/automation/translation}} | {{none / draft / reviewed / ready-to-implement}} |
|
package/README.md
CHANGED
|
@@ -148,9 +148,12 @@ em render <file> -o out.png # PNG (in-process, no system deps)
|
|
|
148
148
|
em render <file> --emit-dot # print the generated DOT instead of rendering
|
|
149
149
|
em render <file> --keep-empty-lanes # don't collapse the API lane when empty
|
|
150
150
|
em watch <file> [-o out.svg] # re-render on every save
|
|
151
|
-
em validate <file> # check event-modeling rules
|
|
151
|
+
em validate <file> # check event-modeling rules + slice-doc frontmatter
|
|
152
|
+
em migrate <model-dir> # one-time upgrade of a pre-1.0 model to the frontmatter standard
|
|
152
153
|
```
|
|
153
154
|
|
|
155
|
+
See [Slice docs & frontmatter](#slice-docs--frontmatter) below for the `em slice` command group.
|
|
156
|
+
|
|
154
157
|
## Validation rules (`em validate`)
|
|
155
158
|
|
|
156
159
|
- two same-band elements in one slice (collision) → **error** (split into separate slices)
|
|
@@ -162,8 +165,34 @@ em validate <file> # check event-modeling rules (non-zero exi
|
|
|
162
165
|
- a read model with no source event → **warning**
|
|
163
166
|
- a name defined more than once and referenced → **warning** (resolves to first)
|
|
164
167
|
|
|
168
|
+
## Slice docs & frontmatter
|
|
169
|
+
|
|
170
|
+
Slice design docs (`slices/<id>.md`, written during the skill's `slice` phase or via
|
|
171
|
+
`em slice new`) carry a required YAML frontmatter block — a stable `id`, lifecycle `status`,
|
|
172
|
+
integer `version`, and fields generated from the `.em` (`commands`/`events`/`readModels`/
|
|
173
|
+
`contexts`/`personas`, plus `triggers`/`triggeredBy` for automation/translation) — so an AI agent
|
|
174
|
+
can search and filter across a model with hundreds of slices from frontmatter alone, without
|
|
175
|
+
reading every doc's body or re-parsing the `.em`:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
em slice new "Place Order" --pattern state-change # scaffold slices/place-order.md
|
|
179
|
+
em slice sync place-order # after wiring note "slices/..." into the .em
|
|
180
|
+
em slice list --status ready-to-implement
|
|
181
|
+
em slice search --pattern automation --context Payment --format json
|
|
182
|
+
em slice search --status ready-to-implement --format json --full # every field, not just a summary
|
|
183
|
+
em slice update place-order --status reviewed --bump-version
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The doc body itself is **yours to define** — point `em.config.json` at a custom template
|
|
187
|
+
(`{ "sliceTemplate": "path/to/template.md" }`) and `em` injects the frontmatter on top of it
|
|
188
|
+
regardless of what sections you ask for. Full schema, lifecycle model, and the handoff contract a
|
|
189
|
+
build/SDD tool should treat as authoritative once a slice is `ready-to-implement`:
|
|
190
|
+
[docs/1.0.0-spec.md](docs/1.0.0-spec.md).
|
|
191
|
+
|
|
165
192
|
## Documentation
|
|
166
193
|
|
|
194
|
+
- [docs/1.0.0-spec.md](docs/1.0.0-spec.md) — slice frontmatter standard, config, `em slice`/
|
|
195
|
+
`em migrate`, and the SDD handoff contract
|
|
167
196
|
- [docs/why-dot-not-plantuml.md](docs/why-dot-not-plantuml.md) — why DOT + the strict-grid /
|
|
168
197
|
self-drawn-edges architecture
|
|
169
198
|
- [docs/features.md](docs/features.md) — full feature list and roadmap
|
|
@@ -195,7 +224,7 @@ Then, in Claude Code, run:
|
|
|
195
224
|
/event-modeling # start (or resume) a guided session
|
|
196
225
|
/event-modeling discover # steps 1–4: brainstorm events, timeline, commands, read models
|
|
197
226
|
/event-modeling model # steps 5–7: swimlanes, patterns, completeness check
|
|
198
|
-
/event-modeling slice # deep implementation specs, one per slice
|
|
227
|
+
/event-modeling slice # deep implementation specs, one per slice (frontmatter via `em slice new`)
|
|
199
228
|
/event-modeling watch # open a live browser view for team modeling sessions
|
|
200
229
|
/event-modeling validate # run em validate and resolve all diagnostics
|
|
201
230
|
```
|