@milehimikey/em 0.2.1 → 1.1.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 +75 -24
- package/.claude/skills/event-modeling/reference/em-dsl.md +15 -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 +9 -3
- package/README.md +43 -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/edges.js +25 -1
- package/dist/model/edges.js.map +1 -1
- 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.d.ts +4 -0
- package/dist/model/model.js +15 -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 +51 -6
- 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/parser/ast.d.ts +2 -0
- package/dist/parser/parser.js +9 -0
- package/dist/parser/parser.js.map +1 -1
- package/dist/render/drawEdges.js +46 -1
- package/dist/render/drawEdges.js.map +1 -1
- 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 +6 -5
|
@@ -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
|
|
|
@@ -58,7 +59,13 @@ Read `reference/methodology.md` (the 7 steps + 4 patterns) and `reference/em-dsl
|
|
|
58
59
|
2. Locate the model. Look for an existing `<dir>/.event-modeling.md` and `*.em` in the working
|
|
59
60
|
directory (or a `models/` subfolder). If found, read the state file. If not, and the phase
|
|
60
61
|
needs one, ask the user for the model name and where to create it.
|
|
61
|
-
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
|
|
62
69
|
state file and resume the recorded phase/step; if no model exists, propose starting `discover`.
|
|
63
70
|
|
|
64
71
|
## Project layout this skill creates
|
|
@@ -69,14 +76,24 @@ Read `reference/methodology.md` (the 7 steps + 4 patterns) and `reference/em-dsl
|
|
|
69
76
|
<model-name>.svg # render target for em watch
|
|
70
77
|
live.html # auto-refresh viewer (copy of templates/live.html, SVG_FILE set)
|
|
71
78
|
README.md # overview + slice index (from templates/model-readme.md)
|
|
72
|
-
.event-modeling.md # resumable state (from templates/state.md)
|
|
73
|
-
|
|
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`
|
|
74
82
|
```
|
|
75
83
|
|
|
76
|
-
When creating a new model, scaffold the directory, copy the
|
|
77
|
-
placeholders), and set `SVG_FILE` in the copied `live.html` to
|
|
78
|
-
`em init` for a starter `.em`, but usually you'll build it up from
|
|
79
|
-
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.
|
|
80
97
|
|
|
81
98
|
---
|
|
82
99
|
|
|
@@ -85,7 +102,11 @@ instead. Fill template placeholders — never leave `{{...}}` in delivered files
|
|
|
85
102
|
Goal: a draft model of events, storyboard, commands, and views. Loose is OK; structure comes next.
|
|
86
103
|
|
|
87
104
|
1. **Brainstorm events (step 1).** Ask the user to name everything that happens, as past-tense
|
|
88
|
-
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.
|
|
89
110
|
2. **Plot / storyboard (step 2).** Order the events into the narrative. Identify **personas**
|
|
90
111
|
(actors) and the **UI** screens at each step. Add `persona` declarations and `ui` elements.
|
|
91
112
|
In a **headless/API** model there are no personas or screens — identify the external
|
|
@@ -138,17 +159,33 @@ the corresponding event/slice to the `.em` and re-render. The happy-path spine f
|
|
|
138
159
|
phases is the starting point, not the finished event set.
|
|
139
160
|
|
|
140
161
|
For each slice:
|
|
141
|
-
1.
|
|
142
|
-
|
|
143
|
-
|
|
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),
|
|
144
169
|
alternate/error flows (retries, idempotency, compensations), read models affected, open
|
|
145
|
-
questions. Park anything unresolved rather than guessing.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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).
|
|
152
189
|
|
|
153
190
|
## Phase: `watch` — live team view
|
|
154
191
|
|
|
@@ -163,8 +200,13 @@ For each slice:
|
|
|
163
200
|
## Phase: `validate`
|
|
164
201
|
|
|
165
202
|
Run `em validate <model-name>.em` and walk through each diagnostic with the user, explaining the
|
|
166
|
-
rule (see `reference/em-dsl.md`
|
|
167
|
-
|
|
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.
|
|
168
210
|
|
|
169
211
|
Then do one check `em validate` can't: scan every `translation`/`processor`/`automation` slice and
|
|
170
212
|
confirm none contains an `event` — each reaction must trigger a `command` in the next slice
|
|
@@ -178,11 +220,20 @@ two slices and route it through a command.
|
|
|
178
220
|
```bash
|
|
179
221
|
em --version
|
|
180
222
|
em init <name>.em # optional starter scaffold
|
|
181
|
-
em validate <name>.em # check rules
|
|
223
|
+
em validate <name>.em # check .em rules + slice-doc frontmatter
|
|
182
224
|
em render <name>.em -o <name>.svg # render (svg/png/pdf by extension)
|
|
183
225
|
em render <name>.em --emit-dot # inspect generated Graphviz DOT
|
|
184
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
|
|
185
234
|
```
|
|
186
235
|
|
|
236
|
+
See `reference/frontmatter.md` for the full slice-doc frontmatter schema and CLI reference.
|
|
237
|
+
|
|
187
238
|
Always finish a working session by: re-rendering, running `em validate`, and updating
|
|
188
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
|
|
@@ -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`
|
|
@@ -15,6 +20,7 @@ Keep it current at the end of every working session.
|
|
|
15
20
|
- **Scope line:** {{one-line description of what's in/out of bounds for this model}}
|
|
16
21
|
- **PRD / spec reference:** {{path, link, or "none"}}
|
|
17
22
|
- **Headless/API model:** {{yes | no}}
|
|
23
|
+
- **Regulatory scope:** {{e.g. PCI-DSS, SOX, HIPAA, or "none"}}
|
|
18
24
|
|
|
19
25
|
## Steps completed
|
|
20
26
|
- [ ] 1. Brainstorm events
|
|
@@ -34,6 +40,6 @@ Keep it current at the end of every working session.
|
|
|
34
40
|
- [ ] {{question}}
|
|
35
41
|
|
|
36
42
|
## Slice inventory
|
|
37
|
-
| Slice | Pattern | Doc status |
|
|
38
|
-
|
|
39
|
-
| {{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
|
@@ -98,6 +98,12 @@ read model. The empty API lane is dropped when a model has neither; pass `--keep
|
|
|
98
98
|
to keep it.
|
|
99
99
|
|
|
100
100
|
`@Persona` / `@Context` choose the row within a band (undeclared tags create a new row).
|
|
101
|
+
`view <Name> again [from "Event", …]` declares a LATER INSTANCE of an already-declared read
|
|
102
|
+
model — the Event Modeling device for keeping the timeline forward-only as a view evolves.
|
|
103
|
+
Instances are one logical view: the first declaration owns the `note` doc; each instance lists
|
|
104
|
+
the events that reach it there; instances are linked left-to-right with a continuity arrow, and
|
|
105
|
+
reactions (`processor … from "View"`) read the nearest instance at-or-before their slice.
|
|
106
|
+
|
|
101
107
|
`view … from "Event"[, "Event2"]` declares which events feed a read model and draws the
|
|
102
108
|
data-flow arrow. Arrows within a slice are inferred from the pattern; use `arrow A -> B` for
|
|
103
109
|
anything extra (e.g. a read model feeding a different screen).
|
|
@@ -148,13 +154,22 @@ em render <file> -o out.png # PNG (in-process, no system deps)
|
|
|
148
154
|
em render <file> --emit-dot # print the generated DOT instead of rendering
|
|
149
155
|
em render <file> --keep-empty-lanes # don't collapse the API lane when empty
|
|
150
156
|
em watch <file> [-o out.svg] # re-render on every save
|
|
151
|
-
em validate <file> # check event-modeling rules
|
|
157
|
+
em validate <file> # check event-modeling rules + slice-doc frontmatter
|
|
158
|
+
em migrate <model-dir> # one-time upgrade of a pre-1.0 model to the frontmatter standard
|
|
152
159
|
```
|
|
153
160
|
|
|
161
|
+
See [Slice docs & frontmatter](#slice-docs--frontmatter) below for the `em slice` command group.
|
|
162
|
+
|
|
154
163
|
## Validation rules (`em validate`)
|
|
155
164
|
|
|
156
165
|
- two same-band elements in one slice (collision) → **error** (split into separate slices)
|
|
157
166
|
- a read model whose `from "Event"` doesn't exist → **error**
|
|
167
|
+
- **time flows left to right** (the Two Laws): an event feeding an EARLIER view instance,
|
|
168
|
+
a reaction reading a view that only exists later, or an explicit backward `arrow` → **error**
|
|
169
|
+
(fix: add `view X again` at the point on the timeline where the event lands)
|
|
170
|
+
- `again` on a view with no earlier declaration → **error**; `again` on non-views → parse error
|
|
171
|
+
- multi-event slices always render as a FAN from the command (never event→event); fanned
|
|
172
|
+
arrows route around the column gutter so they cannot read as a chain
|
|
158
173
|
- an automation/translation whose `from "<read model>"` doesn't exist → **error**
|
|
159
174
|
- an `arrow` endpoint that matches no element → **error**
|
|
160
175
|
- an automation/translation slice that also holds the command it triggers → **warning**
|
|
@@ -162,8 +177,34 @@ em validate <file> # check event-modeling rules (non-zero exi
|
|
|
162
177
|
- a read model with no source event → **warning**
|
|
163
178
|
- a name defined more than once and referenced → **warning** (resolves to first)
|
|
164
179
|
|
|
180
|
+
## Slice docs & frontmatter
|
|
181
|
+
|
|
182
|
+
Slice design docs (`slices/<id>.md`, written during the skill's `slice` phase or via
|
|
183
|
+
`em slice new`) carry a required YAML frontmatter block — a stable `id`, lifecycle `status`,
|
|
184
|
+
integer `version`, and fields generated from the `.em` (`commands`/`events`/`readModels`/
|
|
185
|
+
`contexts`/`personas`, plus `triggers`/`triggeredBy` for automation/translation) — so an AI agent
|
|
186
|
+
can search and filter across a model with hundreds of slices from frontmatter alone, without
|
|
187
|
+
reading every doc's body or re-parsing the `.em`:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
em slice new "Place Order" --pattern state-change # scaffold slices/place-order.md
|
|
191
|
+
em slice sync place-order # after wiring note "slices/..." into the .em
|
|
192
|
+
em slice list --status ready-to-implement
|
|
193
|
+
em slice search --pattern automation --context Payment --format json
|
|
194
|
+
em slice search --status ready-to-implement --format json --full # every field, not just a summary
|
|
195
|
+
em slice update place-order --status reviewed --bump-version
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The doc body itself is **yours to define** — point `em.config.json` at a custom template
|
|
199
|
+
(`{ "sliceTemplate": "path/to/template.md" }`) and `em` injects the frontmatter on top of it
|
|
200
|
+
regardless of what sections you ask for. Full schema, lifecycle model, and the handoff contract a
|
|
201
|
+
build/SDD tool should treat as authoritative once a slice is `ready-to-implement`:
|
|
202
|
+
[docs/1.0.0-spec.md](docs/1.0.0-spec.md).
|
|
203
|
+
|
|
165
204
|
## Documentation
|
|
166
205
|
|
|
206
|
+
- [docs/1.0.0-spec.md](docs/1.0.0-spec.md) — slice frontmatter standard, config, `em slice`/
|
|
207
|
+
`em migrate`, and the SDD handoff contract
|
|
167
208
|
- [docs/why-dot-not-plantuml.md](docs/why-dot-not-plantuml.md) — why DOT + the strict-grid /
|
|
168
209
|
self-drawn-edges architecture
|
|
169
210
|
- [docs/features.md](docs/features.md) — full feature list and roadmap
|
|
@@ -195,7 +236,7 @@ Then, in Claude Code, run:
|
|
|
195
236
|
/event-modeling # start (or resume) a guided session
|
|
196
237
|
/event-modeling discover # steps 1–4: brainstorm events, timeline, commands, read models
|
|
197
238
|
/event-modeling model # steps 5–7: swimlanes, patterns, completeness check
|
|
198
|
-
/event-modeling slice # deep implementation specs, one per slice
|
|
239
|
+
/event-modeling slice # deep implementation specs, one per slice (frontmatter via `em slice new`)
|
|
199
240
|
/event-modeling watch # open a live browser view for team modeling sessions
|
|
200
241
|
/event-modeling validate # run em validate and resolve all diagnostics
|
|
201
242
|
```
|