Workflows
Workflow Structure
Workflows in Machina Sports are defined in YAML format with the following key sections:
workflow:
name: "workflow-name" # Unique identifier (alphanumeric + hyphens)
title: "Workflow Title" # Human-readable title — required
description: "Workflow description" # Brief description of purpose
context-variables: # Credentials and per-connector config
variable-name:
key: "value"
inputs: # Input parameters
input-name: "$.get('parameter')"
outputs: # Output parameters — required
output-name: "$.get('result')"
workflow-status: "$.get('result') is not None and 'executed' or 'skipped'"
tasks: # Tasks to execute — required, non-empty
- type: "task-type" # connector, document, prompt, or mapping
name: "task-name" # Unique name for the task
description: "Task description" # Brief description
# Task-specific configurationname, title, outputs, and tasks are all required, and outputs must contain a workflow-status key — the platform rejects the workflow with a 400 otherwise.
Expressions are Python, not JSONPath
The $ in "$.get('messages')" looks like JSONPath but isn't. Every expression in a workflow — inputs, outputs, and condition — is a Python expression evaluated against the run context, where $ is a plain dict. So you use dict methods and normal Python syntax, not JSONPath syntax:
# Correct — Python
team: "$.get('event', {}).get('competitors', [])[0].get('name')"
count: "len($.get('documents', []))"
label: "$.get('market') + ' ' + $.get('name')"
# Wrong — JSONPath syntax doesn't work here
team: "$.event.competitors[0].name"$.get('key', default) is the idiom for a value that might be missing — a bare $.get('key') returns None and a chained .get() on it will fail the task. List comprehensions work too (see the flagship example below).
Task Types
Workflows support several task types to handle different operations:
Connector Tasks
Connect to external APIs and services to fetch or send data.
- type: "connector"
name: "fetch-team-data"
connector:
name: "sportradar-nba"
command: "get-teams/{team_id}/{data_type}"
command_attribute:
team_id: "$.get('team_id')"
data_type: "'profile.json'"
inputs:
api_key: "$.get('api_key')"
outputs:
team-profile: "$"Document Tasks
Perform operations on documents in the Machina database (search, update, bulk-save).
- type: "document"
name: "load-similar-documents"
config:
action: "search"
threshold-docs: 5
search-vector: true
connector:
name: "google-genai"
command: "invoke_embedding"
model: "text-embedding-004"
location: "global"
provider: "vertex_ai"
inputs:
name: "'content-snippet'"
search-query: "$.get('messages')"
outputs:
documents: "$.get('documents')"Prompt Tasks
Execute AI prompts to generate content or analyze data.
- type: "prompt"
name: "chat-completions-prompt"
connector:
name: "google-genai"
command: "invoke_prompt"
model: "gemini-2.5-pro"
location: "global"
provider: "vertex_ai"
inputs:
documents: "$.get('documents')"
messages: "$.get('messages')"
outputs:
message: "$.get('choices')[0].get('message').get('content')"Mapping Tasks
Transform data between different formats using predefined mappings.
- type: "mapping"
name: "sportradar-nba-team-mapping"
inputs:
team_profile: "$.get('team-profile')"
outputs:
team_id: "$.get('team_id')"
team_name: "$.get('team_name')"
# Additional mapped fieldsConditional Logic
Tasks can include conditions to control execution flow. A task whose condition evaluates falsy is skipped, and the run continues:
- type: "document"
name: "update-thread-document"
condition: "$.get('document_id') is not None"
# Task configurationError handling
A failing task aborts the run by default. continue_on_error: true lets the workflow carry on — pair it with a condition downstream so the next task doesn't act on a missing result:
- type: "connector"
name: "load-odds"
continue_on_error: true
connector:
name: "bwin"
command: "get-fixtures"
outputs:
odds: "$"
- type: "prompt"
name: "summarize-odds"
condition: "len($.get('odds', [])) > 0"
# ...There is no declarative retry, backoff, or timeout key — see Connectors → Best Practices for the patterns templates use instead.
Iterating with foreach
foreach runs a task once per item of a list. It takes three keys — value (the list), name (what each item is bound to in the task's context), and expr (the expression applied to each item, usually just $). The bound name is then read like any other context value inside inputs:
- type: "connector"
name: "download-each-image"
foreach:
name: image-item # each item is bound to this name
expr: $ # the item itself
value: "$.get('image_urls', [])"
concurrent: true # optional — run iterations in parallel
connector:
name: "temp-downloader"
command: "invoke_save_to_tmp"
inputs:
image_base64: "$.get('image-item', {}).get('image', '')"
outputs:
reference_images: "$"Outputs from a foreach task collect into a list, one entry per iteration.
Real-World Example: Chat Completions Workflow
This example from our samples shows a workflow that processes chat messages and generates AI responses:
workflow:
name: "chat-completions"
title: "Chat Completions"
description: "Workflow to execute a chat completion."
context-variables:
google-genai:
credential: "$TEMP_CONTEXT_VARIABLE_VERTEX_AI_CREDENTIAL"
project_id: "$TEMP_CONTEXT_VARIABLE_VERTEX_AI_PROJECT_ID"
machina-ai-fast:
api_key: "$TEMP_CONTEXT_VARIABLE_SDK_GROQ_API_KEY"
inputs:
messages: "$.get('messages', [])"
outputs:
message: "$.get('message')"
workflow-status: "$.get('message') is not None and 'executed' or 'skipped'"
tasks:
# Load similar documents for context
- type: "document"
name: "load-similar-documents"
description: "Load similar documents"
config:
action: "search"
threshold-docs: 5
threshold-similarity: 0.01
search-limit: 1000
search-vector: true
connector:
name: "google-genai"
command: "invoke_embedding"
model: "text-embedding-004"
location: "global"
provider: "vertex_ai"
inputs:
name: "'content-snippet'"
search-query: "$.get('messages')"
outputs:
parsed_documents: |
[
{ **d.get('value', {}) }
for d in $.get('documents', [])
]
# chat-completions-prompt
- type: "prompt"
name: "chat-completions-prompt"
description: "Chat Completions."
connector:
name: "google-genai"
command: "invoke_prompt"
model: "gemini-2.5-pro"
location: "global"
provider: "vertex_ai"
inputs:
documents: "$.get('parsed_documents', [])"
messages: "$.get('messages')"
outputs:
message: "$.get('choices')[0].get('message').get('content')"The real template also keeps commented-out alternative models (Groq/Llama variants, gemini-2.5-flash) on the prompt task, ready to swap in — the connector isn't hardcoded to one model in practice.
Common Workflow Patterns
Data Synchronization
Fetch data from external sources and store it in your Machina database.
Content Generation
Create AI-generated content based on sports data and user context.
Chat Processing
Handle user messages and generate contextually relevant responses.
Scheduled Tasks
Execute workflows at regular intervals using scheduler agents.
Next Steps
- Explore Agents to understand how to schedule workflows
- Learn about Connectors to integrate data sources
- Review Mappings to transform data between formats
- See Prompts to optimize AI outputs

