The for_each Step
The for_each step in Bosun allows you to iterate over a list of items, executing a sub-step (which can contain agent or run steps) for each item. This is effective for automating repetitive tasks across multiple files, configurations, or data entries.
for_each steps are executed in parallel batches. If you need to run them sequentially, you can set parallel: false within the for_each definition.
Key properties of a for_each step include:
from: A templated expression that defines the list of items to iterate over. This can be any JSON array. If needed you can use templating functions likesplit(),slice(), andjson_encode()to transform outputs from previous steps into the required format.for_each.value: Inside thefor_eachloop, this variable holds the current item being processed in the iteration.
Example from Workflow
Consider the for_each step from an example workflow, which processes multiple source files:
- name: Get source files
run: find src -name "*.js"
- name: Apply linting fixes
for_each:
from: '{{ outputs.1 | split(pat="\n") | slice(end=5) | json_encode() }}'
agent:
extends: Coding
instructions: "Apply automatic linting fixes to the file {{ for_each.value }}"
role: "You are a meticulous code formatter."
constraints:
- "Use the project's ESLint configuration"
- "Only apply fixes that do not change code logic"
- "Ensure the file remains syntactically correct"
- "Focus only on the specified file"
In this example:
run: find src -name "*.js": This step (which would beoutputs.1in this snippet) finds all.jsfiles in thesrc/directory and outputs their paths, one per line.from: '{{ outputs.1 | split(pat="\n") | slice(end=5) | json_encode() }}':outputs.1: Retrieves the output (list of file paths) from the "Get source files" step.split(pat="\n"): Splits the string output into an array of file paths.slice(end=5): Takes only the first 5 file paths from the array (for demonstration purposes).json_encode(): Converts the array into a JSON string, which thefor_eachstep can then iterate over.
instructions: "Apply automatic linting fixes to the file {{ for_each.value }}": Inside thefor_eachloop, anagentstep is defined. The{{ for_each.value }}template dynamically inserts the current file path from the iteration into the agent's instructions, allowing the agent to process each file individually.
Error handling
Every iteration runs as its own sub-task. With the default settings a single failure stops the step, but continue_on_error: true lets the loop finish and collects each failure under errors.<step> along with the failed iteration index and input. See Error handling for strategies.