Skip to main content

Templating

Bosun workflows use a templating system to create dynamic, repeatable, and flexible tasks. Templating allows you to inject values, manipulate data, and generate instructions or configurations on the fly, making your workflows adaptable to various scenarios without hardcoding every detail.

Templates are typically enclosed in double curly braces {{ ... }} and can be used in any field that accepts a string value. Under the hood, Bosun leverages the Tera templating engine (inspired by Jinja2 and Django templates).

Templates can include:

  • References to outputs of previous steps: Accessing data generated by earlier parts of the workflow.
  • Loop variables: Using the current item when iterating over a list.
  • Built-in functions and filters: Performing operations like splitting strings, slicing lists, or encoding data.

Accessing Step Outputs (outputs)

Each step in a Bosun workflow can produce an output. You can reference these outputs in subsequent steps using either:

  • outputs.<index> where <index> is the zero-based position of the step.
  • outputs.<id> where <id> is the optional id you assigned to the step.

Example 1: Processing Files with for_each

Consider this workflow snippet that finds configuration files and processes each one:

  - id: scan_configs
name: Get configuration files
run: find . -name "*.config.json"

- name: Process each configuration
for_each:
from: '{{ outputs.scan_configs | split(pat="\n") | slice(end=inputs.maxFiles) | json_encode() }}'
agent:
extends: Coding
instructions: "Validate and standardize the configuration in file {{ for_each.value }}"
role: "You are an expert in configuration management."
constraints:
- "Ensure all configuration values are valid JSON"
- "Apply standard formatting to the file"
- "Report any invalid configurations without modifying them"
- "Focus solely on the specified file"

In this example:

  1. scan_configs step: Runs find to list .config.json files and stores the results under the ID scan_configs.
  2. for_each step: Reads the output via outputs.scan_configs, splits it into a list, slices it using an input value (see below), and iterates over each path.
  3. Agent instructions: {{ for_each.value }} inserts the current file path so the agent edits the correct file.

Example 2: Accepting Numeric Inputs

Task inputs can be typed as numbers. Use the Number type in your manifest and reference the value directly inside templates:

inputs:
maxFiles:
type: Number
required: false
description: Limit how many files to process (defaults to 3).
default: 3

Inside templates the numeric input behaves like any other value. In the snippet above it controls how many files are processed: slice(end=inputs.maxFiles).

Example 3: Dynamic run Commands

Templating can also be used directly within run commands to create dynamic shell scripts or file operations:

  - name: Get current date
run: date +%Y-%m-%d

- name: Create a dated report file
run: echo "Report generated on {{ outputs.0 }}" > report-{{ outputs.0 }}.txt

Here:

  1. The first run step (index 0) captures the current date.
  2. The second run step uses {{ outputs.0 }} twice: once to include the date in the file content and again to dynamically name the report file (e.g., report-2023-10-27.txt).