Loading

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:  [ ... ]
		
  1. success path
  2. 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}}>