Workflow Descriptor
WorkflowDescriptor is the registration bundle for executable workflow behavior.
Stored workflow definitions refer to executable logic by schemaType. Descriptors map those schema types to factories.
Contract
class WorkflowDescriptor {
const WorkflowDescriptor({
this.tasks = const [],
this.userTasks = const [],
this.conditions = const [],
this.nodeProcessors = const [],
this.lifecycleHooks = const {},
this.title,
this.description,
});
final List<TypeDescriptor<TaskExecutor>> tasks;
final List<TypeDescriptor<UserTaskExecutor>> userTasks;
final List<TypeDescriptor<ConditionExecutor>> conditions;
final List<NodeProcessor> nodeProcessors;
final Map<String, WorkflowLifecycleHooks> lifecycleHooks;
final String? title;
final String? description;
}Basic Usage
final descriptor = WorkflowDescriptor(
title: 'Document executors',
tasks: [
ValidateDocumentExecutor.typeDescriptor,
ApplyDocumentOutcomeExecutor.typeDescriptor,
],
userTasks: [
ApprovalUserTaskExecutor.typeDescriptor,
],
conditions: [
RequiresManagerCondition.typeDescriptor,
],
);
final context = RegistryTypeResolver(
descriptors: [
DefaultWorkflowDescriptor(),
descriptor,
],
);
final engine = WorkflowEngine(
context: context,
storage: InMemoryStorage(),
executionMode: ExecutionMode.production,
);
await engine.initialize();DefaultWorkflowDescriptor
Include DefaultWorkflowDescriptor() unless you are deliberately replacing all built-in behavior. It registers the engine's default processors and built-in condition types.
Built-in processors include:
StartEventNodeProcessorEndEventNodeProcessorTaskNodeProcessorUserTaskNodeProcessor- gateway processors
- signal, timer, subflow, and loop processors
TypeDescriptor
Task, user-task, and condition descriptors use TypeDescriptor<T>:
static final typeDescriptor = TypeDescriptor<TaskExecutor>(
schemaType: 'task.document.validate',
fromJson: (_) => ValidateDocumentExecutor(),
title: 'Validate Document',
description: 'Validates document input before approval.',
);The schemaType must match the node configuration or condition JSON.
Lifecycle Hooks
Descriptors can also register lifecycle hooks keyed by workflow code:
final descriptor = WorkflowDescriptor(
lifecycleHooks: {
'approval': WorkflowLifecycleHooks(
onCancel: (instance, reason) async {
await draftService.release(instance.correlationId);
},
),
},
);The engine looks up hooks during administrative lifecycle operations such as cancellation.
Descriptor Order
Descriptors are processed in order by RegistryTypeResolver. Keep defaults first:
final context = RegistryTypeResolver(
descriptors: [
DefaultWorkflowDescriptor(),
sharedDescriptor,
appDescriptor,
],
);Avoid duplicate schema types unless overriding is intentional.
Template Descriptors
Workflow templates expose descriptors too:
final template = ApprovalTemplate(domains: [approvalDomain]);
final context = RegistryTypeResolver(
descriptors: [
DefaultWorkflowDescriptor(),
template.buildDescriptor(),
],
);For the canonical approval template, this descriptor registers approval loop executors, outcome dispatchers, approval user tasks, and revision user tasks.
What Descriptors Do Not Own
Descriptors do not:
- Persist workflows.
- Load workflow definitions.
- Create storage tables.
- Register node configuration classes. Current node configuration resolution is based on node type.