Skip to content

Workflows ​

Workflow Structure ​

Workflows in Machina Sports are defined in YAML format with the following key sections:

yaml
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 configuration

name, 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:

yaml
# 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.

yaml
- 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).

yaml
- 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.

yaml
- 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.

yaml
- 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 fields

Conditional Logic ​

Tasks can include conditions to control execution flow. A task whose condition evaluates falsy is skipped, and the run continues:

yaml
- type: "document"
  name: "update-thread-document"
  condition: "$.get('document_id') is not None"
  # Task configuration

Error 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:

yaml
- 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:

yaml
- 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:

yaml
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