The cheat sheet
Blocks, attributes, values, and commands in one page. Specification v0.4.0 defines the language.
Top-level blocks
| Block | Category | Purpose |
|---|---|---|
bounded_context | Catalog | Owns aggregates, field types, and Events |
actor | Catalog | A reusable human or system actor |
team | Catalog | A reusable owning team |
system | Catalog | A reusable external or internal system |
state_change | Workflow | Screen/API → Command → Event |
state_view | Workflow | Event → Read Model → Screen |
automation | Workflow | Internal Event → Processor → Command → Event |
translation | Workflow | External Event → Processor → Command → internal Event |
chapter | Workshop notation | Groups workflows. In a one-file model the list is a contiguous range. With two or more member files, chapter lists set the board order. |
hotspot | Workshop notation | An unresolved question or blocker |
Inside a bounded_context
| Block | Purpose |
|---|---|
aggregate | A context-owned consistency boundary |
field_type | A reusable field from the ubiquitous language |
event | A canonical past-tense fact with field children |
Inside a workflow
| Block | Used by | Purpose |
|---|---|---|
screen | State Change, State View | A human-facing interaction surface |
screen_image | Any workflow | A presentation-only rough wireframe or mockup with a url |
command | State Change, Automation, Translation | An intent that can succeed or fail. Needs a reason (to-flow, api_endpoint, or external_trigger). |
readmodel | State View, Automation, Translation | Requires question |
processor | Automation, Translation | A machine reaction (the "gear") |
table | Any workflow | Presentation-only illustrative tabular or example data |
scenario | Any workflow | Pattern-specific Given/When/Then (see below) |
Scenario grammar
| Workflow | Given | When | Then |
|---|---|---|---|
| State Change | Event, zero or more | one Command | Event or Error, one or more |
| State View | Event, one or more | none | Read Model or Error, one or more |
| Automation / Translation | Event or Read Model | one Processor or Command | Event or Error, one or more |
Reference forms
| Target | Form |
|---|---|
| Bounded context | bounded_context.clinic |
| Actor / Team / System | actor.clinic_staff / team.clinic_team / system.partner |
| Workflow | workflow.add_pet |
| Event | event.pet_management.pet_added |
| Aggregate | aggregate.pet_management.pet (or aggregate.pet inside its own context) |
| Field type | field_type.pet_management.pet_id (or field_type.pet_id inside its own context) |
| Local workflow element | command.add_pet |
| Workflow-qualified element (for a hotspot) | command.add_pet.add_pet_command |
Field types and flags
Built-in types: String, Boolean, Double, Decimal, Long, Custom, Date, DateTime, UUID, Int.
A field can omit type when a same-named field_type can be inferred. Use fields = [field_type.context.name] to add several reusable fields without per-field overrides. A field_type always declares its built-in type.
| Attribute | Meaning |
|---|---|
id_attribute = true | This field identifies the record |
optional = true | The field can be absent (fields are required by default) |
pii = true | Personally identifiable information |
cardinality = "List" | The field is list-valued |
example = ... | A native HCL literal, checked against the effective type |
Workflow status values
created, planned, assigned, in_progress, review, blocked, done, informational.
Validation profiles
| Profile | Judgment diagnostics (EM404, EM406, EM407, the four smells) |
|---|---|
workshop | Informational |
valid (default) | Warnings |
strict | EM404 / EM406 / EM407 become errors. The four smells stay non-blocking. |
Diagnostic families
| Prefix | Category |
|---|---|
EM0xx | Structural |
EM1xx | References |
EM2xx | Flow |
EM3xx | Scenarios |
EM4xx | Modeling judgment |
Diagnostics print as file:line:column: Severity EMxxx: message. In a folder model, file is the member file that the diagnostic points to.
CLI commands
| Command | Does |
|---|---|
emhcl validate <model.em.hcl | folder> | Validates with the default valid profile |
emhcl validate --profile <workshop|valid|strict> <model.em.hcl | folder> | Validates with an explicit profile |
emhcl diagram <model.em.hcl | folder> -o <file> | Renders a self-contained interactive HTML canvas with switchable Model, Compact, Storming, and Context Map views (or writes to stdout without -o) |
emhcl serve <model.em.hcl | folder> | Serves the canvas on 127.0.0.1:8080 and reloads when the model file changes. For a folder, reloads when you add, remove, rename, or edit a member file. An empty folder shows EM001. Options: --addr, --port (0 picks a free port), --profile |
emhcl fmt -w <model.em.hcl> | Canonicalizes whitespace and attribute order in place. Formats one file. It refuses a folder. |
emhcl export <model.em.hcl | folder> -o <file.json> | Converts a valid model to slice-based Event Modeling JSON. Without -o, writes to stdout. Refuses a target that ends in .em.hcl or is the source file (exit code 2). |
emhcl import <file.json> -o <model.em.hcl> | Converts Event Modeling JSON to one formatted .em.hcl file and validates it (or writes to stdout without -o) |
emhcl version | Prints the installed version |
JSON conversion is a projection, not a lossless canvas copy. Both commands check the published JSON schema and report faults by JSON path. Warnings identify data with no equivalent, such as layout, canvas IDs, catalog metadata, and hotspots.
Import keeps the declared sliceType and warns when it omits unsupported children or scenarios. IDs, field names, and reusable types can change. Import rejects a slice with two or more actors, even without screens. Export rejects a workflow whose screens reference two or more actors. Neither command chooses an actor for you.
Folder models
A model is one .em.hcl file or a folder of .em.hcl files. Folder models need specification v0.4.0 and emhcl v0.9.0 or newer. Use a folder when one file becomes too large or when different people own different contexts or workflows.
- Every regular file directly in the folder that ends in
.em.hcland does not start with.is a member file. A symlink to a file counts. The tool ignores subfolders and other files. - The tool sorts member files by name, byte by byte. Model order is file order, then source order in each file. A number prefix such as
10-only sets the file order. - References resolve across member files. IDs keep their existing scopes, with no file namespace. Duplicate IDs in the same top-level ID space produce
EM002. Its detail names the first declaration asfile:line:column. Workflow children and fields keep their local scopes. - Each file must parse on its own. A block cannot span files. A
bounded_contextwith all its events, aggregates, and field types is in one file. - With two or more member files, all
chapterblocks are in one file. Splitting them producesEM013. A workflow in two chapters producesEM014. Chapter source order, then eachworkflowslist, sets board order. The contiguous-range ruleEM006does not apply. - With two or more member files, a workflow in no chapter produces
EM407. It is information inworkshop, a warning invalid, and an error instrict. These workflows follow all chaptered workflows in model order, even when no chapters exist. - A folder with no member file is error
EM001. A folder with one member file behaves like that file.
The language has no include or import block, no subfolder members, and no references across folders. The pet clinic example shows one layout:
JSON import and export
emhcl import and emhcl export convert between .em.hcl and slice-based Event Modeling JSON. JSON conversion is a tool feature, not part of the language specification.
- Both commands check the JSON against the published schema. An error names the JSON path of the fault.
- The conversion is not lossless. Export drops chapters, hotspots, teams, systems, and read-model questions. Import drops original canvas IDs and field-name spellings. Each command writes warnings for each detail the other format cannot hold.
- Both commands fail when a workflow or slice has two or more actors. They do not choose an actor for you.
- If the imported model has validation errors,
importstill writes the source for repair and exits with code 1.
Diagram views
| View | Shows |
|---|---|
Model | Left-to-right Event Model with screen, processor, model, and event swimlanes and typed flow arrows |
Compact | Same slices and cards as Model, with one events row. Dashed colored boxes show bounded contexts (pink shows external contexts). The aggregate sticky note sits on top of its event. |
Storming | Event Model in Event Storming style: one row per workflow with sticky notes for screens, commands, aggregates, events, automations or translations, and read models |
Context Map (experimental) | Bounded-context map from cross-context event consumption, with upstream and downstream relationships |
One generated file carries all four views. Switch between them from the canvas masthead. The Model and Storming views support zoom. Zoom with the toolbar, Ctrl/⌘ + scroll, or the +, -, 0, and F keys.