Data Passing Between Steps
Workflows become powerful when steps pass data to each other. This page covers CEL expressions, conditional execution, and step chaining.
Chaining Step Outputs
Look at examples/chained-requests.yaml:
name: chained-requests
description: >
Fetch a user from a public API, then fetch their posts using the user's ID.
Demonstrates CEL data passing between steps via steps.<name>.output.
steps:
- name: get-user
action: http/request
params:
method: GET
url: "https://jsonplaceholder.typicode.com/users/1"
- name: get-user-posts
action: http/request
params:
method: GET
url: "https://jsonplaceholder.typicode.com/posts?userId={{ steps['get-user'].output.json.id }}"
The key line is the second step’s URL. The expression {{ steps['get-user'].output.json.id }} reads the JSON response from the get-user step and extracts the id field.
Apply and run it:
mantle apply examples/chained-requests.yaml
mantle run chained-requests
Running chained-requests (version 1)...
Execution b2c3d4e5-f6a7-8901-bcde-f12345678901: completed
get-user: completed
get-user-posts: completed
CEL Expression Syntax
Mantle uses CEL (Common Expression Language) for data passing and conditional logic. The essentials:
- Access step output:
steps['step-name'].output.json.field - Access inputs:
inputs.field_name - Bracket notation is required when step names contain hyphens:
steps['get-user'](notsteps.get-user) - Dot notation works for step names without hyphens:
steps.summarize.output.json.summary - Template strings use
{{ }}delimiters insideparamsvalues
Conditional Execution
Steps can run conditionally based on the output of previous steps. Look at examples/conditional-workflow.yaml:
name: conditional-workflow
description: >
Fetch todos for a user, then conditionally post a summary only if there are
incomplete todos. Demonstrates conditional execution with if: and retry policies.
inputs:
user_id:
type: string
description: JSONPlaceholder user ID (1-10)
steps:
- name: get-todos
action: http/request
timeout: "10s"
retry:
max_attempts: 3
backoff: exponential
params:
method: GET
url: "https://jsonplaceholder.typicode.com/todos?userId={{ inputs.user_id }}"
- name: post-summary
action: http/request
if: "steps['get-todos'].output.status == 200"
params:
method: POST
url: "https://jsonplaceholder.typicode.com/posts"
headers:
Content-Type: "application/json"
body:
title: "Todo summary"
body: "Fetched todos for user {{ inputs.user_id }}"
userId: "{{ inputs.user_id }}"
This workflow introduces three features:
inputs— the workflow declares auser_idinput, passed at runtime with--inputif— thepost-summarystep only runs when the CEL expression evaluates to trueretryandtimeout— theget-todosstep retries up to 3 times with exponential backoff and times out after 10 seconds
Apply and run it:
mantle apply examples/conditional-workflow.yaml
mantle run conditional-workflow --input user_id=3
Running conditional-workflow (version 1)...
Execution c3d4e5f6-a7b8-9012-cdef-123456789012: completed
get-todos: completed
post-summary: completed
You can pass multiple inputs by repeating the --input flag:
mantle run my-workflow --input key1=value1 --input key2=value2