Flow 5 process semantics for ProcessEngine.
Validates, prepares and executes flow definitions. Manages process state transitions according to the Flow 5 model.
PROCESS/DATA — synchronous data processing via dataflow artifact
CONTROL/ROUTE — routing by any scalar value from state
EFFECT — external async call (COMMAND, CALL, SUBFLOW)
WAIT/MESSAGE — waiting for async response
TERMINAL — COMPLETE or FAIL
Removed from Flow 5: PROCESS/RULES, PROCESS/MAPPINGS, PROCESS/DECISIONS, CONTROL/SWITCH.
npm install @processengine/semanticsimport { validateFlow, prepareFlow, createProcessState, plan, reduce } from '@processengine/semantics';
const flowDef = {
id: 'flow.example',
version: '1.0.0',
title: 'Example flow',
description: 'Minimal Flow 5 process.',
entryStepId: 'evaluate',
steps: {
evaluate: {
id: 'evaluate', type: 'PROCESS', subtype: 'DATA',
title: 'Evaluate', description: 'Runs a dataflow artifact.',
artefactId: 'dataflow.example.evaluate',
nextStepId: 'finish',
},
finish: {
id: 'finish', type: 'TERMINAL', subtype: 'COMPLETE',
title: 'Finish', description: 'Process complete.',
result: { status: 'COMPLETE', outcome: 'DONE' },
},
},
};
// 1. Validate
const v = validateFlow(flowDef);
if (!v.ok) throw new Error(JSON.stringify(v.issues));
// 2. Prepare once
const flow = prepareFlow(flowDef);
// 3. Create process state
const state = createProcessState({ flow, processId: 'proc-001', input: { x: 1 } });
// state.context.data.{facts,decisions,checks,payloads,results} are all available
// 4. Orchestrator loop
const dataStep = plan(flow, state);
// dataStep.artefactId → pass to @processengine/dataflows
// dataStep contains NO input — orchestrator does not know about dataflow internals
const nextState = reduce(dataStep, state, {
// DataflowOutput from @processengine/dataflows
writes: [
{ ref: '$.context.data.decisions.x', value: { outcome: 'DONE' }, itemId: 'decide' },
],
});
// nextState.currentStepId === 'finish', status === 'COMPLETE'orchestrator:
step = plan(flow, state) // get current step description
output = executeStep(step, state) // call appropriate runtime (dataflows, etc.)
state = reduce(step, state, output)// apply output, advance to next step
persist(state)
context.input — process input
context.data.payloads.* — intermediate payloads
context.data.facts.* — decision-ready facts
context.data.decisions.* — decision outcomes
context.data.checks.* — rule check results
context.data.results.* — terminal results (read by TERMINAL.resultRef)
context.effects.* — effect responses
ROUTE reads a scalar from state by ref path:
- String/number/boolean/null: matched against
caseskeys - Missing ref: runtime error
FLOW_ROUTE_REF_NOT_RESOLVED(missing ref is a broken dataflow contract, not a business "no match") - Object/array: runtime error
FLOW_ROUTE_REF_NOT_SCALAR - No matching case:
defaultNextStepId
Must point into $.context.data.results.*. Written there by a PROCESS/DATA step before the terminal transition.
@processengine/dataflows— executes dataflow artifacts for PROCESS/DATA stepsexamples/— canonical Flow 5 flow examples