.cmmn
Case management
Cases, plans and sentry criteria
consumed byphero-backend-cmmn
CMMN 1.1 case models: case files, discretionary and required plan items, sentries, and decision tasks that invoke sibling decision services.
Why it exists
What .cmmn is for
A .cmmn file declares a case: the adaptive, event-and-condition-driven work coordinated around a domain — the CMMN 1.1 notion of case management, not a workflow and not a state machine. The plan declares the work that is available (tasks, service tasks, milestones, grouped into stages) and the criteria under which each item activates, without prescribing a sequence.
The division of responsibility is explicit: the domain owns the data and its invariants, the domain lifecycle (.ddd machines) owns an aggregate’s valid transitions, the case owns the work, and the engine executes. Sibling tasks are concurrent by default; ordering exists only where a criterion imposes it.
Vocabulary
What it models
The concepts .cmmn declares, and what each one means to the compiler.
- case
- The declaration. Plan items and case-file items share one namespace per case.
- roles
role <name> as <Actor>: the.actorprincipals who fill the work.- case_file
- Typed case-file items (
Ticket[1..1] ticket), resolved against the imported domain. - stage
- A grouping of plan items.
- task
- A human task. A
discretionary taskis available but not required; a plaintaskis required once activated. - service item
execute <service>.<operation>: automation bound to an operation the imported design declares.- decision item
invokes <DecisionModel>.<service>withinputsandoutputs: the sibling.dmndecision service as case work.- milestone
- A reachable goal state.
- entry / exit criteria
on <item>.<event> when (<expr>): the sentries that activate or terminate an item.
Source
A working example
Quoted from the example this page's artifact was compiled from — not a snippet written for the website.
Lines 42–57 of examples/support/support.cmmn, reproduced byte for byte, read from the file at build time:
service AssessRefund {
execute support.TicketService.raiseRefund;
entry on ReviewTicket.complete when (decision == null);
required;
}
/// The desk's decision layer: the sibling decision model
/// (support.dmn) assesses the ticket once the service has run, and
/// its assessment lands in the `decision` case-file item the case
/// coordinates around.
decision AssessAuthority {
invokes RefundDecisions.AssessRefund;
inputs { ticket }
outputs { decision }
entry on AssessRefund.complete when (decision == null);
required;
}The automated half of the assessment stage: a `service` item bound to a designed operation, a `decision` item invoking the sibling decision model’s `AssessRefund` service, and the discretionary finance approval.
The whole file is CI-tested: pherolang check examples/ checks every surface in the tree, and the example harness compiles each one on every run. What you see above is the input to the artifact below.
Neighbours
How it relates to the other surfaces
A case coordinates work over the other surfaces: .mox types the case file, .actor names the role principals, .ddd supplies the operations a service item executes, .dmn supplies the decision service a decision item invokes, and .evt stays the wider integration vocabulary — the case reacts to case-file transitions, not to events. The CMMN backend lowers the artifact to the engine’s CaseDefinition JSON.
Commands
How to compile and validate
Three commands, one file. They run from the repository root against the example on this page.
pherolang check examples/support/support.cmmn
pherolang ir examples/support/support.cmmn -o site/data/artifacts/cmmn.json
pherolang artifact check site/data/artifacts/cmmn.jsoncheck parses, resolves, validates and type-checks the file and printsOK examples/support/support.cmmn. ir writes the artifact and prints nothing on success. artifact check then validates the serialized JSON on its own — no model, no import resolution, no compiler — and prints OK site/data/artifacts/cmmn.json.
Directories work too: pherolang check examples/ enters project mode and checks every supported surface under the tree, each file's imports resolving from the snapshot.
Artifact
What it produces
One versioned JSON artifact, emitted by the compiler and consumed by whatever reads this surface.
One CmmnModel: cases with their roles, case file, plan items and sentries — the shape the CMMN backend lowers into a CaseDefinition.
The artifact is site/data/artifacts/cmmn.json, and it is committed here exactly as the released pherolang binary emits it. Its top-level shape:
cases1 entry
Provenance
- formatVersion = 2
- The compatibility gate. A reader accepts this number or refuses the file.
- pheroVersion — not present
- This standalone surface artifact is versioned on its own
formatVersion; only the domain model artifact carries the compiler-version stamp. - 6,526 bytes
- 255 lines, two-space indented, in the file's own key order.
The compiled artifact
The first 56 of 255 lines, verbatim — the exact bytes pherolang ir writes, not a hand-written sample. The slice stops at a JSON boundary; the ellipsis marker is outside the JSON, and the full file is site/data/artifacts/cmmn.json.
artifacts/cmmn.json · lines 1–56
{
"formatVersion": 2,
"cases": [
{
"name": "RefundDesk",
"description": "A refund-desk case: the work coordinated around one support ticket\nthat needs money back.",
"roles": [
{
"name": "triage",
"actor": "Agent"
},
{
"name": "finance",
"actor": "Finance"
},
{
"name": "escalation",
"actor": "Manager"
}
],
"caseFile": [
{
"name": "ticket",
"description": "The ticket under triage.",
"type": {
"type": "class",
"value": {
"package": "nz.example.support",
"name": "Ticket"
}
},
"multiplicity": {
"lower": 1,
"upper": {
"finite": 1
}
}
},
{
"name": "decision",
"description": "The refund decision, once assessed.",
"type": {
"type": "class",
"value": {
"package": "nz.example.support",
"name": "RefundDecision"
}
},
"multiplicity": {
"lower": 0,
"upper": {
"finite": 1
}
}
}
],… 199 more lines in site/data/artifacts/cmmn.json
Regenerate it from the repository root — the second command validates the serialized bytes with no compiler in the loop:
pherolang ir examples/support/support.cmmn -o site/data/artifacts/cmmn.json
pherolang artifact check site/data/artifacts/cmmn.jsonThe whole data directory is regenerated by node scripts/sync-model.mjs (run from site/) with the released binary; CI fails on a one-byte difference.
Reference
Documentation
The normative reference for this surface, rendered from the repository's own documentation.
docs.pherolang.com
Case management reference
Generated from docs/CMMN.md in the repository. The page above summarises it; the reference is normative.