Skip to main content

Workflow Chaining

Replay lets you compose workflows across files. You can inject steps at parse time with include, or call a separate workflow file at runtime with call. This enables reusable workflow fragments and pipeline patterns.

Include — Compile-Time Injection

The include directive loads steps from another file and injects them into the current workflow before execution. Included steps run as if they were written inline in the original file.
Included steps are prepended to the workflow’s own steps in the order they appear.

Passing Parameters to Includes

Parameters in the with block are substituted using {{ var }} syntax in the included file:
The include directive applies these substitutions at parse time, before any execution starts.

Call — Runtime Composition

The call step loads and executes steps from another workflow file at runtime, mid-execution. Unlike include, the called file is loaded when the step runs, and it can return values back to the caller.

Basic Call

Passing Parameters

Parameters are available as {{ email }} and {{ role }} inside the called file’s steps.

Calling a Specific Step

Use target to execute only one named step from the called file:
This is useful when a file contains multiple operations and you only need one.

Isolating State with Returns

By default, called workflows share the caller’s state bag — variables set inside the call are visible after the call returns. Use returns to control which variables leak back:
When returns is specified, Replay:
  1. Snapshots the caller’s state before the call
  2. Executes the called steps
  3. Saves only the listed variables from the called state
  4. Restores the caller’s state to the snapshot
  5. Copies the saved variables back into the caller’s state
This prevents the called workflow from polluting the caller’s state with temporary or internal variables.

Example: Reusable Auth Workflow

Only token leaks back — expires_in stays contained inside the call.

Safeguards — Cycle Detection and Depth Limits

Workflow chaining is powerful, but recursive calls can cause infinite loops. Replay provides two safeguards.

Cycle Detection

The engine tracks every file:step pair during execution using an internal call stack. If the same pair is encountered twice in a single chain, execution stops immediately.
replay validate catches direct self-calls statically:
It also finds cycles nested inside if/then/else and loop blocks. Cross-file cycles (e.g., a.yaml → b.yaml → a.yaml) are detected at runtime by the engine.

Call Depth Limit

Even without cycles, deeply nested calls can exhaust resources. Use --max-call-depth to cap the call chain:
Default is 100. When exceeded, you see:
The call stack resets between workflows, so parallel runs do not interfere with each other.

Include vs Call

Pipeline Patterns

Setup → Test → Teardown

Auth → Action → Verify

Conditional Chaining

Combine if with call to branch between different workflows:

What’s Next?