Context variables
Context variables are the data you can reference inside Liquid expressions in a workflow. Every execution gets the same core set. Some variables are only populated in certain contexts (for example, foreach.item exists only inside a foreach loop).
This page is the canonical reference. For the mental model and the {{ }} vs. ${{ }} distinction, refer to Templating engine.
Values provided at workflow invocation time. Declared in the workflow's top-level inputs block.
inputs:
- name: service_name
type: string
required: true
steps:
- name: search
type: elasticsearch.esql.query
with:
query: "FROM logs-* | WHERE service.name == \"{{ inputs.service_name }}\""
Constants declared at the top of the workflow. Evaluated once at workflow load. They can't reference other context (no inputs, no steps).
consts:
threshold: 70
slack_channel: "#soc-oncall"
steps:
- name: notify
type: slack.postMessage
with:
channel: "{{ consts.slack_channel }}"
text: "Threshold {{ consts.threshold }} exceeded."
The output produced by a previous step. Shape depends on the step type. Refer to each step's reference for what it returns.
steps:
- name: search
type: elasticsearch.search
with: { index: "logs-*", size: 1 }
- name: summarize
type: console
with:
message: "First hit: {{ steps.search.output.hits.hits[0]._id }}"
Error details if the step failed and its on-failure: continue caught the error. null if the step succeeded. Refer to Pass data and handle errors for the continue strategy.
- name: flaky_call
type: http
on-failure:
continue: true
with: { url: "https://flaky.example" }
- name: handle
type: if
condition: "steps.flaky_call.error : null"
steps: [ ... ]
else: [ ... ]
- success path
- failure path (steps.flaky_call.error has detail)
The trigger payload. Shape depends on the trigger type:
| Trigger | event.* structure |
|---|---|
manual |
{} (empty — use inputs.* instead) |
scheduled |
{} (empty) |
alert |
event.alerts (array of alert documents), event.rule (rule metadata), event.spaceId, event.params.* (params from the rule's action configuration) |
workflows.failed |
event.spaceId, event.timestamp, event.workflow.{id, name, spaceId, isErrorHandler}, event.execution.{id, startedAt, failedAt}, event.error.{message, stepId, stepName, stepExecutionId} |
For the full workflows.failed payload, refer to Event-driven triggers.
Alert trigger example:
- name: log
type: console
with:
message: |
Got {{ event.alerts | size }} alerts from rule "{{ event.rule.name }}".
First host: {{ event.alerts[0].host.name }}
Metadata about the current workflow execution.
| Field | Contains |
|---|---|
execution.id |
Execution ID. |
execution.startedAt |
ISO timestamp of start. |
execution.isTestRun |
true if run from the editor's Test button. |
execution.executedBy |
UID of the user or system that invoked the workflow. |
execution.triggeredBy |
Which trigger initiated this execution (manual, scheduled, alert, workflows.failed). |
execution.url |
Deep link to the execution view in Kibana. |
execution.compositionDepth |
0 for a top-level invocation. Increments by 1 for each workflow.execute level. |
execution.parentWorkflowId |
ID of the parent workflow, if this is a composed child execution. |
- name: link
type: console
with:
message: "View this execution: {{ execution.url }}"
Metadata about the workflow itself, not the execution.
| Field | Contains |
|---|---|
workflow.id |
Workflow ID. |
workflow.name |
Workflow name. |
workflow.enabled |
true or false. |
workflow.spaceId |
The Kibana space ID. |
- name: audit
type: elasticsearch.index
with:
index: "workflow-audit"
document:
workflow_id: "{{ workflow.id }}"
workflow_name: "{{ workflow.name }}"
space_id: "{{ workflow.spaceId }}"
execution_id: "{{ execution.id }}"
Available inside a foreach loop body.
| Field | Contains |
|---|---|
foreach.item |
Current iteration's element. |
foreach.index |
Zero-based iteration index. |
foreach.total |
Total items in the array. |
foreach.items |
The full array being iterated. |
- name: process
foreach: "${{ event.alerts }}"
steps:
- name: log
type: console
with:
message: "[{{ foreach.index }}/{{ foreach.total }}] {{ foreach.item._id }}"
Available inside a while loop body. Zero-based iteration counter.
- name: poll
type: while
condition: "steps.check.output.status : 'pending'"
max-iterations: 30
steps:
- name: log
type: console
with: { message: "Attempt {{ while.iteration }}" }
- name: check
type: elasticsearch.search
with: { index: "jobs", size: 1 }
- name: wait
type: wait
with: { duration: "2s" }
Variables set by one or more data.set steps. Global within the workflow execution. Later data.set steps can overwrite earlier values.
- name: init
type: data.set
with:
service: "checkout"
region: "us-east"
- name: query
type: elasticsearch.esql.query
with:
query: "FROM logs-{{ variables.region }}-* | WHERE service.name == \"{{ variables.service }}\""
Current timestamp as an ISO 8601 string. Evaluated per reference, so repeated uses in the same expression will match.
- name: index_row
type: elasticsearch.index
with:
index: "events"
document:
at: "{{ now }}"
formatted: "{{ now | date: '%Y-%m-%d %H:%M' }}"
Base URL of the Kibana instance. Useful for building deep links in notifications.
- name: notify
type: slack.postMessage
with:
channel: "#soc"
text: |
Case created: <{{ kibanaUrl }}/app/security/cases/{{ steps.create_case.output.id }}|Open in {{kib}}>
- Templating engine: How Liquid expressions evaluate these variables.
- Liquid filters: Transformations you can apply to any variable.
- Cheat sheet: The condensed version of this table.
- Steps overview: Each step's reference documents what its
outputcontains.