Tasks
Tasks are the units of work in a process. The engine supports the standard BPMN task types — service, user, script, business-rule, send, receive, manual, and generic — and adds runtime metadata via the quantum: extension namespace.
Common attributes
| Attribute | Notes |
|---|---|
id | Required; unique within the process |
name | Optional display name |
default | ID of an outgoing flow to take when every other outgoing flow's condition evaluates false. See Sequence Flow → Default flows for the full evaluation model |
isForCompensation | true marks the task as a compensation handler — it never runs on a normal sequence flow and must be linked to a compensation boundary event by an <association>. The validator rejects any isForCompensation="true" activity that has incoming sequence flows |
Most tasks accept these extensions:
| Extension | Purpose |
|---|---|
quantum:taskDefinition | type (worker type string) and optional retries |
quantum:ioMapping | Variable mappings — see Common extensions |
quantum:taskHeaders | Static headers passed to the worker — see Common extensions |
Standard loop and multi-instance loop characteristics can be attached to most tasks — see Structure → Loops.
Service task
Delegates work to an external worker identified by a task type string. The engine creates a job for the configured type, hands it to a polling worker, and waits for the worker to complete or fail it.
Required configuration
| Attribute | Notes |
|---|---|
quantum:taskDefinition type | Worker type string. Required — without it, deployment fails |
quantum:taskDefinition retries | Optional retry attempts on failure (e.g. "3") |
Example
<bpmn:serviceTask id="charge-card" name="Charge Credit Card">
<bpmn:extensionElements>
<quantum:taskDefinition type="payment-worker" retries="3" />
<quantum:ioMapping>
<quantum:input source="=orderId" target="order_id" />
<quantum:input source="=totalAmount" target="amount" />
<quantum:output source="=result.transactionId" target="transactionId" />
</quantum:ioMapping>
<quantum:taskHeaders>
<quantum:header key="currency" value="USD" />
</quantum:taskHeaders>
</bpmn:extensionElements>
<bpmn:incoming>f1</bpmn:incoming>
<bpmn:outgoing>f2</bpmn:outgoing>
</bpmn:serviceTask>
For details on writing workers, see External workers.
Validation
| Check | Severity |
|---|---|
quantum:taskDefinition type is missing or empty | Error |
User task
Requires a human to complete the work. The engine evaluates the assignment fields, registers the task with the platform's user-task system, and waits for an external completion signal.
Configuration
| Extension | Notes |
|---|---|
quantum:assignmentDefinition assignee="..." | Single assigned user |
quantum:assignmentDefinition candidateGroups="..." | Comma-separated list of groups who can claim the task |
quantum:assignmentDefinition candidateUsers="..." | Comma-separated list of candidate users |
quantum:formDefinition formKey="..." | Form key used by the UI to render the task |
quantum:formDefinition formId="..." | Form definition ID |
quantum:taskDefinition type="..." | Optional; only relevant for custom user-task backends |
A user task can carry an error boundary event. Completing the task with an error code routes the token through the boundary instead of the normal outgoing flow.
Example
<bpmn:userTask id="approve-request" name="Approve Request">
<bpmn:extensionElements>
<quantum:assignmentDefinition assignee="manager" candidateGroups="approvers, leads" />
<quantum:formDefinition formKey="approve-form" />
<quantum:ioMapping>
<quantum:input source="=requestId" target="request_id" />
<quantum:output source="=approved" target="isApproved" />
</quantum:ioMapping>
</bpmn:extensionElements>
<bpmn:incoming>f1</bpmn:incoming>
<bpmn:outgoing>f2</bpmn:outgoing>
</bpmn:userTask>
Script task
Executes an inline script in the engine. FEEL is the supported script language.
Attributes
| Attribute | Notes |
|---|---|
scriptFormat | Set to "feel" |
The script body goes inside a <script> child element. Output mappings can pull values out of the script's local scope and write them to the parent scope.
Example
<bpmn:scriptTask id="calculate-total" name="Calculate Total" scriptFormat="feel">
<bpmn:extensionElements>
<quantum:ioMapping>
<quantum:output source="=total" target="orderTotal" />
</quantum:ioMapping>
</bpmn:extensionElements>
<bpmn:incoming>f1</bpmn:incoming>
<bpmn:outgoing>f2</bpmn:outgoing>
<bpmn:script>{ total: sum(items.price) }</bpmn:script>
</bpmn:scriptTask>
Business rule task
Invokes a decision and stores the result in a process variable. Two modes are supported, mirroring the send-task shape: embedded DMN evaluation (the engine runs the rule) or external worker dispatch (a worker performs the evaluation, e.g. against a remote rules engine).
Execution modes
| Mode | When active | Behavior |
|---|---|---|
| Embedded DMN | quantum:calledDecision decisionId="..." is set | Engine evaluates the named DMN decision synchronously and stores the result in resultVariable |
| External worker | quantum:taskDefinition type="..." is set, no calledDecision | Engine creates a job — same semantics as a service task (retries, headers, boundary events, I/O mappings). The worker performs the rule evaluation and returns the result |
At least one mode must be configured. Setting both is a warning: the external-worker dispatch wins and calledDecision is ignored.
Required configuration — embedded DMN
| Extension | Notes |
|---|---|
quantum:calledDecision decisionId="..." | Required. ID of the DMN decision to evaluate |
quantum:calledDecision resultVariable="..." | Required. Variable name to store the decision output |
quantum:calledDecision bindingType="..." | Optional; how to select the decision version (e.g. "versionTag") |
quantum:calledDecision versionTag="..." | Used when bindingType="versionTag" |
Input mappings prepare the input data the decision expects; output mappings extract fields from the decision result for downstream use.
Example
<bpmn:businessRuleTask id="check-eligibility" name="Check Eligibility">
<bpmn:extensionElements>
<quantum:calledDecision decisionId="eligibility-rules" resultVariable="eligibilityResult" />
<quantum:ioMapping>
<quantum:input source="=customerAge" target="age" />
<quantum:input source="=annualIncome" target="income" />
<quantum:output source="=eligibilityResult.eligible" target="isEligible" />
</quantum:ioMapping>
</bpmn:extensionElements>
<bpmn:incoming>f1</bpmn:incoming>
<bpmn:outgoing>f2</bpmn:outgoing>
</bpmn:businessRuleTask>
Example — external worker
<bpmn:businessRuleTask id="check-eligibility-remote" name="Check Eligibility (remote)">
<bpmn:extensionElements>
<quantum:taskDefinition type="rules-worker" retries="2" />
<quantum:ioMapping>
<quantum:input source="=customerAge" target="age" />
<quantum:input source="=annualIncome" target="income" />
<quantum:output source="=result.eligible" target="isEligible" />
</quantum:ioMapping>
</bpmn:extensionElements>
<bpmn:incoming>f1</bpmn:incoming>
<bpmn:outgoing>f2</bpmn:outgoing>
</bpmn:businessRuleTask>
Validation
| Check | Severity |
|---|---|
Neither quantum:calledDecision nor quantum:taskDefinition is set | Error |
quantum:calledDecision is set but resultVariable is missing | Error |
Both quantum:calledDecision and quantum:taskDefinition are set | Warning (taskDefinition wins; calledDecision is ignored) |
Send task
Emits a message and advances. Operates in one of two modes depending on what extensions are present.
Execution modes
| Mode | When active | Behavior |
|---|---|---|
| Direct publish | messageRef is set, no quantum:taskDefinition | Resolves the message name from the global declaration, publishes the message with the current scope variables, advances immediately |
| External job | quantum:taskDefinition type="..." is set | Creates a job for a worker — same semantics as a service task (retries, headers, boundary events, I/O mappings). Waits for worker completion |
If neither is set, the task is a no-op pass-through. If both are set, the worker mode wins.
Examples
<!-- Direct publish -->
<bpmn:sendTask id="send-order" name="Notify Order Placed" messageRef="Msg_OrderPlaced">
<bpmn:incoming>f1</bpmn:incoming>
<bpmn:outgoing>f2</bpmn:outgoing>
</bpmn:sendTask>
<!-- Worker mode (e.g. SMTP, SMS) -->
<bpmn:sendTask id="notify-customer" name="Send Confirmation Email">
<bpmn:extensionElements>
<quantum:taskDefinition type="email-sender" retries="2" />
<quantum:ioMapping>
<quantum:input source="=customerEmail" target="to" />
<quantum:input source="=orderId" target="order_id" />
</quantum:ioMapping>
<quantum:taskHeaders>
<quantum:header key="template" value="order-confirmation" />
</quantum:taskHeaders>
</bpmn:extensionElements>
<bpmn:incoming>f1</bpmn:incoming>
<bpmn:outgoing>f2</bpmn:outgoing>
</bpmn:sendTask>
Receive task
Blocks until a correlated message arrives. The message is referenced by messageRef. If a buffered message is already available it fires immediately; otherwise the task waits.
messageRef is required. The runtime subscribes to the Temporal signal "message:" + <resolved name>; an empty name produces a subscription that no publish can ever match, leaving the task waiting forever. The validator rejects receive tasks without a messageRef.
Example
<bpmn:receiveTask id="wait-for-payment" name="Wait for Payment" messageRef="Msg_Payment">
<bpmn:extensionElements>
<quantum:ioMapping>
<quantum:output source="=amount" target="paidAmount" />
</quantum:ioMapping>
</bpmn:extensionElements>
<bpmn:incoming>f1</bpmn:incoming>
<bpmn:outgoing>f2</bpmn:outgoing>
</bpmn:receiveTask>
Validation
| Check | Severity |
|---|---|
messageRef is missing or empty | Error |
messageRef references an unknown <message> definition | Error |
Manual task
Represents work performed entirely outside the engine, with no automated execution. The engine treats it like a service task: it creates a job and waits for an external system to complete it.
Example
<bpmn:manualTask id="physical-review" name="Physical Document Review">
<bpmn:extensionElements>
<quantum:taskDefinition type="manual-review-handler" />
</bpmn:extensionElements>
<bpmn:incoming>f1</bpmn:incoming>
<bpmn:outgoing>f2</bpmn:outgoing>
</bpmn:manualTask>
Generic task
<task> with no specific type. Treated as a service task — same extensions, same validation. Use it when the task category isn't relevant to the model.
Example
<bpmn:task id="generic-step" name="Generic Step">
<bpmn:extensionElements>
<quantum:taskDefinition type="generic-handler" />
</bpmn:extensionElements>
<bpmn:incoming>f1</bpmn:incoming>
<bpmn:outgoing>f2</bpmn:outgoing>
</bpmn:task>