Workflow Specification¶
Status¶
Current specification for Workflow DSL v2.
Workflow definitions are governed data. They are stored in namespace registry
processes and are deployed through signed process_event events. TypeScript and
frontend code render workflows only; workflow parsing, validation, graph building,
canonicalization, and execution semantics live in Rust/WASM.
Workflow identity¶
Every non-bootstrap workflow declares a canonical $path:
json
{
"$version": "2.0",
"$path": "customer/retail/retail-customer",
"$description": "Retail customer onboarding"
}
Rules:
$pathis the workflow identity.namespace = dirname($path).workflow = basename($path).- File/workspace path is
$path + ".json". - No
$categoryor other active organization metadata. - No basename version suffixes like
-V1.
Bootstrap exception:
system/bootstrapis the only visible bootstrap workflow.- Non-system registries are governed by the hardcoded Rust bootstrap workflow
internally, but do not store or list
*/bootstrapdefinitions.
Workflow shape¶
Workflow DSL v2 is graph-first. States and actions are explicit top-level maps.
json
{
"$version": "2.0",
"$path": "customer/retail/retail-customer",
"$description": "Retail customer onboarding",
"initial": "intake",
"states": {
"intake": { "label": "Intake" },
"review": { "label": "Review" },
"approved": { "label": "Approved", "terminal": true }
},
"actions": {
"create": {
"role": "admin,analyst",
"from": "intake",
"to": "review",
"mutate": { "$set": { "state": "review" } }
},
"approve": {
"role": "manager",
"from": "review",
"to": "approved",
"when": "risk_score < 70",
"mutate": { "$set": { "state": "approved" } }
}
}
}
Metadata fields¶
| Field | Required | Meaning |
|---|---|---|
$version |
yes | Workflow schema version, currently "2.0" for active workflows |
$path |
yes for non-bootstrap | Canonical identity and organization path |
$description |
no | Human-readable summary |
initial |
yes | Initial state key for new processes |
states |
yes | Map of state keys to state definitions |
actions |
yes | Map of action keys to action definitions |
State fields¶
| Field | Required | Meaning |
|---|---|---|
label |
no | Human-readable state label |
terminal |
no | true if no further business action should advance the process |
description |
no | State context/help text |
State keys must be unique. Terminal status is derived from the active workflow state definition, not a separate process flag.
Action fields¶
| Field | Required | Meaning |
|---|---|---|
role |
no | Comma-separated actor roles. * or absent means any actor. |
from |
no | Source state. Required for transition actions. |
to |
no | Target state. Optional for self-effect actions. |
when |
no | Pre-condition expression evaluated against current process data and canonical action input. |
mutate |
no | Mutation operators applied to process data. |
then |
no | Post-condition expression evaluated after mutation. |
spawn |
no | Child-process spawn definitions using canonical workflow paths. |
schedule |
no | Scheduled/system action definitions. |
Actions are looked up from workflow.actions.get(action.name). There are no
hardcoded business action lists.
Roles¶
Roles are comma-separated strings:
json
"role": "admin,manager,analyst"
Matching is case-insensitive. * or missing role means any verified actor may
perform the action.
Expressions¶
when and then expressions are parsed and evaluated by Rust, not SQL.
| Category | Operators | Example |
|---|---|---|
| Equality | =, != |
state = 'review' |
| Comparison | >=, <=, >, < |
risk_score < 70 |
| List | IN |
state IN ('intake', 'review') |
| Null | IS NULL, IS NOT NULL |
reviewer IS NULL |
| JSON key test | ? |
input.note ? 'content' |
| Logic | AND, OR, NOT, () |
state = 'review' AND score > 0 |
| Unary minus | - |
score > -1 |
Unsupported: SQL, subqueries, function calls, arbitrary JavaScript, and binary arithmetic.
Mutation operators¶
Mutations are deterministic JSON transformations.
| Operator | Effect |
|---|---|
$set |
Set top-level keys. |
$append |
Append to an array. |
$merge |
Shallow-merge an object. |
$remove |
Remove a top-level key. |
$increment |
Increment a numeric field. |
$spawn / spawn |
Create child process using canonical workflow path. |
$schedule / schedule |
Register future/system action. |
$unschedule |
Cancel scheduled action. |
Special values:
"input.fields.x","input.refs.x", and otherinput.*paths resolve from the signed event input."$timestamp"resolves to the single timestamp captured for the event.
State authority¶
For active v2 workflows:
process.data.stateis authoritative.data.phaseexists only as legacy/migration fallback where needed.get_process_flowexposescurrent_state.- terminal status is read from
states[current_state].terminal.
Deployment¶
Workflow definitions are stored in namespace registry processes:
text
registry process id = namespace with / replaced by - + "-registry"
Examples:
| Namespace | Registry process |
|---|---|
customer/retail |
customer-retail-registry |
case/review |
case-review-registry |
system |
system-registry |
Deployment rules:
- Business/demo workflows are deployed through signed
add_workfloworupdate_workflowevents. - Event
action.workflowuses the target registry governance path, e.g.customer/retail/bootstrapinternally for the registry process. - Non-system registries do not store
bootstrap; runtime loads the hardcoded bootstrap workflow for registry actions. - Deployment target namespace/key must match
$path. - No raw
UPDATE processes,jsonb_set, or direct registry mutation.
Spawn references¶
Spawn references are full canonical paths:
json
{
"spawn": [
{
"workflow": "case/review/kyc-review",
"from": "review",
"to": "open"
}
]
}
Rules:
- No relative spawn references.
- Runtime validates the target workflow exists.
- Child process namespace/workflow are derived from the target path.
Validation requirements¶
Validation must reject:
- missing
$pathfor non-bootstrap workflows, - invalid path shape,
- duplicate state/action keys,
- duplicate workflow paths in a workspace/export/import set,
$categoryin active definitions,- legacy
$version: "1.0"in active definitions, - basename suffixes like
-V1, - unresolved
spawn.workflowreferences, - deployment target/path mismatches.
Warnings may be shown for non-fatal authoring guidance, but errors block import, deployment, or execution.