Expressions

RWX supports expressions for referencing values and defining boolean logic in task definitions.

Syntax

Expressions are denoted using ${{ }} in supported places within task definitions. For example:

tasks:
  - key: greeting
    run: echo hello ${{ init.name }}!

Usage

You can use expressions to reference values when defining:

And to implement boolean logic for:

Expressions are also used for configuring after conditions

Referencing Values

Reference init parameters:

${{ init.commit-sha }}

Reference vault secrets and OIDC tokens:

${{ secrets.SOME_API_TOKEN }}
${{ vaults.custom_vault.secrets.SOME_CREDENTIALS }}

Reference task output values:

${{ tasks.some-task.values.some-value }}

Boolean Logic

You can use (), &&, ||, ==, !=,=~, and !~ inside expressions for implementing boolean logic. When using =~ or !~, the right-hand side must evaluate to a string that can be parsed as a regular expression.

if: ${{ init.branch == 'main' }}
if: ${{ init.branch != 'main' }}
if: ${{ init.branch == 'main' || init.branch == 'production' }}
if: ${{ event.git.ref =~ '^refs/tags/v.+$' }}

Functions

RWX supports a small number of utility functions to make your expressions more powerful and flexible. Functions are called with parentheses and can be passed valid expressions as arguments. Currently, these functions are supported:

date

Signature: date(format: string): string

Formats the current UTC date and time using strftime specifiers.

FormatExample OutputDescription
%Y-%m-%d2026-03-06Date in ISO 8601 format
%Y-%m-%dT%H:%M:%SZ2026-03-06T14:30:45ZDate and time in ISO 8601 format
%s1772977845Seconds since Unix epoch
%Y%m%d%H%M%S20260306143045Compact timestamp
tasks:
  - key: build
    run: echo "Built at $BUILD_DATE"
    env:
      BUILD_DATE: ${{ date('%Y-%m-%dT%H:%M:%SZ') }}

If you don't want the date to affect the cache key, use cache-key: excluded.

tasks:
  - key: build
    run: echo "Built at $BUILD_DATE"
    env:
      BUILD_DATE:
        value: ${{ date('%Y-%m-%dT%H:%M:%SZ') }}
        cache-key: excluded

ends-with

Signature: ends-with(str: string, suffix: string): boolean

Usage: ${{ ends-with("hello", "lo") }}

Returns true if str ends with suffix, false otherwise.

starts-with

Signature: starts-with(str: string, prefix: string): boolean

Usage: ${{ starts-with("hello", "he") }}

Returns true if str starts with prefix, false otherwise.

contains

Signature: contains(str: string, substr: string): boolean

Usage: ${{ contains("hello", "el") }}

Returns true if str contains substr, false otherwise.

lower

Signature: lower(str: string): string

Usage: ${{ lower("HELLO") == "hello" }}

Returns lowercased str.

upper

Signature: upper(str: string): string

Usage: ${{ upper("hello") == "HELLO" }}

Returns uppercased str.

trim

Signature: trim(str: string): string

Usage: ${{ trim(" hello ") == "hello" }}

Returns str with leading and trailing whitespace and newlines removed.

Dynamic Access

Some contexts permit dynamic access (vaults, secrets, and vars). For those contexts, you can use an expression inside of square brackets like so: if: ${{ vaults[init.vault-name].vars[init.var-name] == "some-value" }}.