Reference for .em.hcl v0.4.0

The cheat sheet

Blocks, attributes, values, and commands in one page. Specification v0.4.0 defines the language.

Top-level blocks

BlockCategoryPurpose
bounded_contextCatalogOwns aggregates, field types, and Events
actorCatalogA reusable human or system actor
teamCatalogA reusable owning team
systemCatalogA reusable external or internal system
state_changeWorkflowScreen/API → Command → Event
state_viewWorkflowEvent → Read Model → Screen
automationWorkflowInternal Event → Processor → Command → Event
translationWorkflowExternal Event → Processor → Command → internal Event
chapterWorkshop notationGroups workflows. In a one-file model the list is a contiguous range. With two or more member files, chapter lists set the board order.
hotspotWorkshop notationAn unresolved question or blocker

Inside a bounded_context

BlockPurpose
aggregateA context-owned consistency boundary
field_typeA reusable field from the ubiquitous language
eventA canonical past-tense fact with field children

Inside a workflow

BlockUsed byPurpose
screenState Change, State ViewA human-facing interaction surface
screen_imageAny workflowA presentation-only rough wireframe or mockup with a url
commandState Change, Automation, TranslationAn intent that can succeed or fail. Needs a reason (to-flow, api_endpoint, or external_trigger).
readmodelState View, Automation, TranslationRequires question
processorAutomation, TranslationA machine reaction (the "gear")
tableAny workflowPresentation-only illustrative tabular or example data
scenarioAny workflowPattern-specific Given/When/Then (see below)

Scenario grammar

WorkflowGivenWhenThen
State ChangeEvent, zero or moreone CommandEvent or Error, one or more
State ViewEvent, one or morenoneRead Model or Error, one or more
Automation / TranslationEvent or Read Modelone Processor or CommandEvent or Error, one or more

Reference forms

TargetForm
Bounded contextbounded_context.clinic
Actor / Team / Systemactor.clinic_staff / team.clinic_team / system.partner
Workflowworkflow.add_pet
Eventevent.pet_management.pet_added
Aggregateaggregate.pet_management.pet (or aggregate.pet inside its own context)
Field typefield_type.pet_management.pet_id (or field_type.pet_id inside its own context)
Local workflow elementcommand.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.

AttributeMeaning
id_attribute = trueThis field identifies the record
optional = trueThe field can be absent (fields are required by default)
pii = truePersonally 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

ProfileJudgment diagnostics (EM404, EM406, EM407, the four smells)
workshopInformational
valid (default)Warnings
strictEM404 / EM406 / EM407 become errors. The four smells stay non-blocking.

Diagnostic families

PrefixCategory
EM0xxStructural
EM1xxReferences
EM2xxFlow
EM3xxScenarios
EM4xxModeling 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

CommandDoes
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 versionPrints 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.hcl and 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 as file:line:column. Workflow children and fields keep their local scopes.
  • Each file must parse on its own. A block cannot span files. A bounded_context with all its events, aggregates, and field types is in one file.
  • With two or more member files, all chapter blocks are in one file. Splitting them produces EM013. A workflow in two chapters produces EM014. Chapter source order, then each workflows list, sets board order. The contiguous-range rule EM006 does not apply.
  • With two or more member files, a workflow in no chapter produces EM407. It is information in workshop, a warning in valid, and an error in strict. 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:

pet-clinic/ 00-catalog.em.hcl # bounded_context, actor, team, system 01-chapters.em.hcl # every chapter block 10-register-pet.em.hcl # one workflow per file 11-pet-directory.em.hcl 12-notify-owner.em.hcl 13-import-partner-pet.em.hcl 90-hotspots.em.hcl

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, import still writes the source for repair and exits with code 1.

Diagram views

ViewShows
ModelLeft-to-right Event Model with screen, processor, model, and event swimlanes and typed flow arrows
CompactSame 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.
StormingEvent 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.