Process Model
The Primmel process model provides BPMN-style primitives for describing flows of work. Processes are bound to roles, may read and write data registries, and may carry compliance requirements.
Primitives
role
role Roaster {
name "Roaster"
}
A role has an ID and a human-readable name. Roles are bound to
processes via the actor clause.
start_event, end_event
start_event Start1 { }
end_event End1 { }
The boundaries of a flow. A model with multiple canvas diagrams
typically has multiple start_events — one per diagram. There
can be more end_events than start_events — a flow can
terminate in multiple outcomes.
timer_event
timer_event PaymentWindow {
type WAIT
para "72 hours after order placed"
}
timer_event RestockTimer {
type REPEAT
para "First of every month"
}
type |
Meaning |
|---|---|
WAIT |
Pause the flow until the specified time elapses. |
REPEAT |
Fire on a recurring schedule, regardless of flow position. |
REPEAT timers are typically wired in a loop to model recurring
processes (see timer loop pattern).
exclusive_gateway
exclusive_gateway StockCheck {
label "Is the item in stock?"
}
A decision point. Its outgoing edges are labelled with mutually
exclusive descriptions; exactly one is taken. One edge should be
marked description "default" as the fallback.
process
process Greet {
name "Greet the world"
actor Greeter
}
A unit of work. The actor clause binds it to a role. A real-world
process also carries:
modality SHALL/SHOULD/MAY— the compliance weight.validate_provision { ... }— the provisions it must satisfy. See compliance.validate_measurement { ... }— the measurement expressions that must hold.reference_data_registry { ... }— registries it reads from.output { ... }— registries it writes to.canvas <Name>— binds the process to a named diagram.
Nested processes
A process can contain child processes, forming a hierarchy. This is useful for decomposing a high-level activity into its sub-steps:
process Manufacturing {
name "Manufacture product"
actor Factory
process Assembly {
name "Assemble components"
actor AssemblyLine
}
process QualityControl {
name "Inspect quality"
actor QA
}
}
Child processes are defined inside the parent’s body. The parser sets
each child’s parent field automatically to the parent’s ID.
On the parsed model:
process.parent— the ID of the parent process (empty string for top-level processes)process.children— an array of child process IDs
Nesting is additive — existing flat models still work. A
model with no nesting simply has empty children arrays and empty
parent strings.
The dumper preserves nesting: dump(load(content)) emits child
processes inside their parent, indented for readability.
approval
approval ApproveNewRoast {
name "Approve a new roast profile"
actor HeadRoaster
modality SHALL
approve_by OperationsManager
approval_record { RoastProfileApprovalRegistry }
}
A specialised process that requires sign-off. Distinct from process
because it carries an approve_by clause and an approval_record
registry. See approval workflow.
canvas
canvas OrderFlow {
elements {
OrderStart { x 0 y 0 }
StockCheck { x 0 y 100 }
/* ... */
}
process_flow {
Edge1 { from OrderStart to StockCheck description "Item is in stock" }
Edge2 { from OrderStart to CancelOrder description "default" }
}
data { }
}
A container that lays out a flow on one diagram. Has three blocks:
| Block | Purpose |
|---|---|
elements { ... } |
Nodes on this diagram, each with x/y layout coordinates. |
process_flow { ... } |
Directed edges between nodes. Each edge has from, to, optional description and condition. |
data { ... } |
Data registries visible on this diagram, with coordinates. |
The header’s root <Name> declaration names the top-level canvas.
A model with multiple canvases names them like pages.
Where to see it in action
- Example 01: Minimal model — the smallest valid canvas.
- Example 03: Process flow — gateways, timers, multi-page canvases.
- Example 05: Approval workflow —
the
approvalprimitive. - Implementation package — four canvases on one model, with a recurring timer loop.