MachineSpec v2 Reference
Complete reference for the MachineSpec v2 JSON format used by the Process Editor.
Table of contents
- Overview
- Schema Structure
- Complete Example
- Validation Rules
- Import/Export Behavior
- Integration with Applications
- Best Practices
Overview
MachineSpec v2 is a JSON format that describes finite state machines for insurance processes. The Process Editor generates this format from BPMN diagrams and can import it back to recreate the visual representation.
Schema Structure
Root Object
1
2
3
4
5
6
7
{
"id": "string",
"version": 1,
"initial": "string",
"metadata": { ... },
"states": { ... }
}
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | Yes | Unique process identifier |
version |
number | Yes | Schema version (always 1) |
initial |
string | Yes | Name of the initial state |
metadata |
object | No | Process metadata and documentation |
states |
object | Yes | State definitions |
Metadata Object
1
2
3
4
5
6
7
8
{
"metadata": {
"documentation": "string",
"lanes": {
"LaneName": ["state1", "state2"]
}
}
}
| Field | Type | Required | Description |
|---|---|---|---|
documentation |
string | No | Process description |
lanes |
object | No | Lane assignments for states |
State Object
1
2
3
4
5
6
7
8
9
10
{
"states": {
"state_name": {
"id": "string",
"type": "task" | "end",
"on": { ... },
"timers": [ ... ]
}
}
}
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | Yes | Stable element identifier |
type |
string | No | State type (task or end) |
on |
object | No | Event transitions |
timers |
array | No | Timer definitions |
Transition Object
1
2
3
4
5
6
7
8
9
10
{
"on": {
"EVENT_NAME": {
"id": "string",
"target": "string",
"guard": "string",
"actions": ["string"]
}
}
}
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | Yes | Stable flow identifier |
target |
string | Yes | Target state name |
guard |
string | No | Guard function name |
actions |
array | No | Action function names |
Timer Object
1
2
3
4
5
6
7
8
9
10
11
{
"timers": [
{
"id": "string",
"type": "DURATION" | "DATE",
"iso": "string",
"at": "string",
"event": "string"
}
]
}
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | Yes | Unique timer identifier |
type |
string | Yes | Timer type (DURATION or DATE) |
iso |
string | Conditional | ISO 8601 duration (for DURATION type) |
at |
string | Conditional | ISO 8601 datetime (for DATE type) |
event |
string | Yes | Event to trigger when timer expires |
Complete Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
{
"id": "insurance_quote",
"version": 1,
"initial": "created",
"metadata": {
"documentation": "Insurance quote lifecycle process",
"lanes": {
"Customer": ["created", "submitted"],
"Reviewer": ["under_review", "approved", "rejected"],
"Finance": ["payment_pending", "paid_full"]
}
},
"states": {
"created": {
"id": "task_created",
"type": "task",
"on": {
"SUBMIT": {
"id": "flow_submit",
"target": "submitted",
"actions": ["validateSubmission"]
}
}
},
"submitted": {
"id": "task_submitted",
"type": "task",
"on": {
"START_REVIEW": {
"id": "flow_start_review",
"target": "under_review",
"guard": "hasRequiredDocuments"
}
}
},
"under_review": {
"id": "task_under_review",
"type": "task",
"on": {
"APPROVE": {
"id": "flow_approve",
"target": "approved",
"guard": "isReviewer",
"actions": ["recordApproval", "sendNotification"]
},
"REJECT": {
"id": "flow_reject",
"target": "rejected",
"guard": "isReviewer",
"actions": ["recordRejection", "sendRejectionNotice"]
},
"REVIEW_TIMEOUT": {
"id": "flow_timeout",
"target": "rejected",
"actions": ["recordTimeout"]
}
},
"timers": [
{
"id": "timer_review_deadline",
"type": "DURATION",
"iso": "P7D",
"event": "REVIEW_TIMEOUT"
}
]
},
"approved": {
"id": "task_approved",
"type": "task",
"on": {
"REQUEST_PAYMENT": {
"id": "flow_request_payment",
"target": "payment_pending",
"actions": ["generateInvoice", "sendPaymentRequest"]
}
}
},
"rejected": {
"id": "end_rejected",
"type": "end"
},
"payment_pending": {
"id": "task_payment_pending",
"type": "task",
"on": {
"PAY_FULL": {
"id": "flow_pay_full",
"target": "paid_full",
"actions": ["recordPayment", "activatePolicy"]
},
"PAYMENT_EXPIRED": {
"id": "flow_payment_expired",
"target": "payment_expired"
}
},
"timers": [
{
"id": "timer_payment_deadline",
"type": "DURATION",
"iso": "P30D",
"event": "PAYMENT_EXPIRED"
}
]
},
"paid_full": {
"id": "end_paid_full",
"type": "end"
},
"payment_expired": {
"id": "end_payment_expired",
"type": "end"
}
}
}
Validation Rules
Schema Validation
- Required Fields: All required fields must be present
- Type Validation: Fields must match expected types
- Version: Must be exactly
1
Semantic Validation
- Initial State: Must reference an existing state
- Target States: All transition targets must exist
- Unique IDs: All element, flow, and timer IDs must be unique
- Deterministic: No duplicate events from the same state
- Reachability: All states must be reachable from initial state
Timer Validation
- Duration Format: ISO 8601 duration (e.g.,
P14D,PT2H30M) - Date Format: ISO 8601 datetime with timezone (e.g.,
2024-12-31T23:59:59Z) - Event Names: Must follow UPPER_SNAKE_CASE convention
Naming Conventions
- State Names: snake_case (e.g.,
waiting_approval) - Event Names: UPPER_SNAKE_CASE (e.g.,
APPROVE) - IDs: Descriptive with prefixes (e.g.,
task_approval,flow_submit)
Import/Export Behavior
BPMN to MachineSpec
- Initial State: Task with no incoming flows becomes
initial - States: Tasks and End Events become state objects
- Transitions: Sequence Flows become
onevents - Timers: Boundary Timers become timer objects
- Lanes: Lane assignments become
metadata.lanes
MachineSpec to BPMN
- Start Event: Automatically created, connects to initial state
- Tasks: Created for each non-end state
- End Events: Created for each end-type state
- Flows: Created for each transition
- Timers: Attached as boundary events to tasks
- Lanes: States grouped by lane assignments
Round-Trip Compatibility
The Process Editor ensures round-trip compatibility:
- Export BPMN → Generate MachineSpec → Import → Recreate identical BPMN
- All metadata, IDs, and structure preserved
- Visual layout may change but semantic meaning remains
Integration with Applications
Loading MachineSpec
1
2
3
4
5
6
7
8
9
10
11
12
import { MachineSpec } from './types/machine-spec';
// Load from JSON file
const spec: MachineSpec = JSON.parse(jsonString);
// Validate schema
if (spec.version !== 1) {
throw new Error('Unsupported MachineSpec version');
}
// Use in your application
const stateMachine = createMachine(spec);
Generating Events
1
2
3
4
5
// Event names from MachineSpec
const events = Object.keys(spec.states[currentState].on || {});
// Trigger transition
stateMachine.send('APPROVE');
Implementing Guards
1
2
3
4
5
6
7
8
const guards = {
isReviewer: (context, event) => {
return context.user.role === 'reviewer';
},
hasRequiredDocuments: (context, event) => {
return context.documents.length > 0;
}
};
Implementing Actions
1
2
3
4
5
6
7
8
9
10
const actions = {
recordApproval: (context, event) => {
console.log('Recording approval:', event);
// Implementation here
},
sendNotification: (context, event) => {
console.log('Sending notification');
// Implementation here
}
};
Best Practices
Design Principles
- Keep States Focused: Each state should represent a clear business condition
- Use Meaningful Names: State and event names should be self-documenting
- Minimize Complexity: Avoid deeply nested or overly complex flows
- Document Intent: Use descriptions and lane assignments for clarity
Performance Considerations
- State Count: Keep under 50 states for optimal performance
- Timer Count: Limit timers per state (recommended: max 3)
- Action Count: Keep action lists short and focused
Maintenance
- Version Control: Track changes to MachineSpec files
- Testing: Validate round-trip compatibility regularly
- Documentation: Maintain external documentation for complex processes
- Backup: Keep both BPMN and JSON versions for redundancy