@talosjs/workflow component is a transition-based workflow engine. A workflow is an ordered list of transitions: small, focused steps that each decide whether they run, do their work, and know how to undo it. When you run a workflow, the active transitions execute in order. If any step throws, the engine rolls back the ones that already succeeded, in reverse, and raises a typed WorkflowException.
The transition model
A workflow breaks a process into small, focused steps rather than one monolithic function. Each transition’sisActive(data, context?) decides whether it runs for the current data, so the active set can vary from one run to the next. When a step fails, the transitions that already executed roll back in reverse order before the error propagates. You can react around every step with the onStart, onFinish, and onFail hooks. Workflows and transitions are registered with a decorator and resolved from @talosjs/container, and generic Data and Output types thread through the workflow and its transitions.
How it works
A workflow extends the abstractWorkflow<Data, Output> class and implements getName, getDescription, and getTransitions. Each transition implements the ITransition<Data, Output> interface. Calling run(data, context?) does the following:
- Every transition’s
isActive(data, context?)is evaluated to build the list of active transitions. - Active transitions run in order. For each one:
onStartfires, thenhandler(data, context?)produces an output, thenonFinishfires with that output. - The output of the last executed transition is returned.
- If a step throws, that transition’s
onFailfires, the transitions executed so far are rolled back in reverse order, and aWorkflowExceptionis thrown.
Every member may be synchronous or asynchronous. The optional
context passed to run is forwarded to every member, so request-scoped values such as the current user or a request id reach each step.
Rollback is precise. Only transitions whose handler completed are rolled back; the transition that threw is not, since its work never finished. The rollbacks are awaited before the WorkflowException is rethrown.
Decorator and usage
@decorator.transition()
Registers a transition class with the container. It accepts an optional scope (defaults to EContainerScope.Singleton).
@decorator.workflow()
Registers a workflow class with the container. It also accepts an optional scope (defaults to EContainerScope.Singleton). List the transition classes in getTransitions() in the order they should run, returning the class references only, never instances, since they are resolved from the container.
run it. The output is whatever the last executed transition returns:
Exceptions
A failed run throws aWorkflowException. It carries a machine-readable key, a human-readable message, an HTTP status, and a data object.
The
message reads Workflow "<name>" failed at transition "<name>"., the status is 500 (Internal Server Error), and data is { workflow, transition, error }, where error is the original message (non-Error throwables are stringified).
Composing workflows that recover
Keep each transition on a single, nameable action so it stays easy to test and roll back. Makerollback the true inverse of handler: whatever side effect a handler creates, whether a charge, a reservation, or a record, its rollback should undo it. Guard with isActive to skip steps that don’t apply to the current data instead of branching inside the handler.
Order transitions deliberately. They run in the order getTransitions() returns and roll back in reverse, so put the reversible, cheap steps first where you can. List the transition classes in getTransitions(), never instances, since the container resolves them. Pass request-scoped values like the current user or a request id through the second run argument as context rather than threading them into Data. And catch WorkflowException at the boundary, reading its stable key and data to report the failing workflow and transition.
CLI command
Scaffold a workflow withworkflow:create and each of its steps with workflow:transition:create. The generators write the class and a matching test under the target module and install @talosjs/workflow if it is missing.
workflow:create writes the class under modules/<module>/src/workflows/<Name>Workflow.ts as a Workflow subclass with an empty transition list, ready for you to fill in:
workflow:transition:create writes the class under modules/<module>/src/workflows/transitions/<Name>Transition.ts as an ITransition stub with every member ready to implement:
Use with Claude and Codex
The generators ship matchingworkflow:create and workflow:transition:create skills. They run the scaffold, then guide your AI agent through completing the workflow: defining the Data type, listing the transitions in order, and implementing each transition’s isActive, handler, and rollback. Initialize the skills once for your agent.
- Claude
- Codex
Prompt
workflow:create --name=Order, then a workflow:transition:create for each step, wiring the transitions into getTransitions() in order.