Workflow Structure
Workflows are defined in YAML files with the following structure:
name: workflow-name
description: What this workflow does
# Optional: Trigger that starts the workflow
trigger:
type: trigger.type
with:
key: value
# Required: Steps to execute
steps:
- id: step-id
action: action.name
with:
key: value
Fields
| Field | Required | Description |
|---|---|---|
| name | Yes | Unique identifier for the workflow |
| description | No | Human-readable description |
| trigger | No | Event that starts the workflow automatically |
| steps | Yes | Array of steps to execute |
Triggers
Triggers define events that automatically start a workflow.
Available Triggers
| Trigger | Description |
|---|---|
| cron.schedule | Run on a schedule (cron expression) |
| http.webhook | Run when a webhook is received |
| github.push | Run on GitHub push events |
| github.pull_request | Run on GitHub PR events |
| github.issue.opened | Run when a GitHub issue is opened |
| telegram.message | Run on incoming Telegram messages |
See Integrations for detailed trigger configuration.
Steps
Steps are the individual units of work in a workflow.
steps:
- id: unique-step-id # Required: Unique identifier
action: plugin.action # Required: Action to execute
needs: [other-step-id] # Optional: Dependencies
if: "{{ condition }}" # Optional: Conditional execution
with: # Optional: Action parameters
key: value
retry: # Optional: Retry configuration
attempts: 3
delay: 1000
Step Fields
| Field | Description |
|---|---|
| id | Unique identifier for referencing in other steps |
| action | The action to execute (plugin.action format) |
| needs | Array of step IDs that must complete first |
| if | Condition that must be true to run this step |
| with | Parameters passed to the action |
| retry | Retry configuration for failed steps |
Built-in Actions
transform
Create a value from a template string.
- id: message
action: transform
with:
template: "Hello, {{ input.name }}!"
log
Log a message to the workflow output.
- id: log-result
action: log
with:
message: "Processing complete: {{ steps.process.result }}"
http.request
Make an HTTP request.
- id: fetch-data
action: http.request
with:
url: "https://api.example.com/data"
method: GET
headers:
Authorization: "Bearer {{ env.API_TOKEN }}"
ai.agent
Execute an AI agent task. See AI Agents for details.
- id: analyze
action: ai.agent
with:
task: "Analyze this data and provide insights"
json.parse
Parse a JSON string into an object.
- id: parse-response
action: json.parse
with:
input: "{{ steps.fetch.body }}"
json.stringify
Convert an object to a JSON string.
- id: serialize
action: json.stringify
with:
input: "{{ steps.data }}"
pretty: true
Dependencies
Use needs to control step execution order.
steps:
- id: fetch
action: http.request
with:
url: "https://api.example.com/data"
- id: parse
action: json.parse
needs: [fetch] # Runs after 'fetch' completes
with:
input: "{{ steps.fetch.body }}"
- id: process
action: ai.agent
needs: [parse] # Runs after 'parse' completes
with:
task: "Analyze: {{ steps.parse }}"
- id: notify
action: slack.post
needs: [process] # Runs after 'process' completes
with:
channel: "#results"
text: "{{ steps.process.response }}"
Parallel Execution
Steps without dependencies or with the same dependencies run in parallel.
steps:
- id: fetch-users
action: http.request
with:
url: "/api/users"
- id: fetch-orders
action: http.request
with:
url: "/api/orders"
# Both fetch steps run in parallel
# This step waits for both
- id: combine
action: transform
needs: [fetch-users, fetch-orders]
with:
template: "Users: {{ steps.fetch-users.body }}, Orders: {{ steps.fetch-orders.body }}"
Variable Interpolation
Use {{ }} syntax to reference dynamic values.
Available Variables
| Variable | Description |
|---|---|
| {{ trigger.* }} | Data from the trigger event |
| {{ steps.stepId }} | Output from a previous step |
| {{ steps.stepId.field }} | Specific field from step output |
| {{ input.* }} | Input data passed to the workflow |
| {{ env.VAR_NAME }} | Environment variable |
| {{ currentISODate }} | Current timestamp in ISO format |
Examples
# Access trigger data
message: "New PR: {{ trigger.pullRequest.title }}"
# Access step output
body: "{{ steps.analyze.response }}"
# Access nested fields
author: "{{ trigger.issue.user.login }}"
# Environment variables
token: "{{ env.GITHUB_TOKEN }}"
# Combine values
url: "https://api.example.com/{{ trigger.repo }}/issues/{{ trigger.number }}"
Conditional Execution
Use if to conditionally execute steps.
steps:
- id: check-label
action: transform
with:
template: "{{ trigger.action }}"
# Only run if PR was opened
- id: review
action: ai.agent
if: "{{ trigger.action == 'opened' }}"
with:
task: "Review this PR"
# Only run if labeled with 'urgent'
- id: alert
action: slack.post
if: "{{ 'urgent' in trigger.issue.labels }}"
with:
channel: "#urgent"
text: "Urgent issue: {{ trigger.issue.title }}"