Skip to main content

Overview

Each step in a Jinba Flow can be configured with advanced options that control how and when it executes. These options allow you to create sophisticated workflows with conditional logic, loops, and complex dependencies.

Step Dependencies (needs)

The needs option specifies which steps must complete before the current step can run. This creates an execution order and ensures data is available when needed.

Basic Usage

- id: analyze_data
  tool: PYTHON_SANDBOX_RUN
  needs:
    - fetch_data
    - validate_input
  input:
    - name: code
      value: "process({{steps.fetch_data.result}})"

Key Points

  • Execution Order: Steps with needs wait for all specified dependencies to complete
  • Parallel Execution: Steps without dependencies run in parallel automatically
  • Failure Handling: If a dependency fails or is skipped, dependent steps are also skipped
  • Diamond Patterns: Complex dependency graphs are supported (A→B, A→C, B→D, C→D)

Example: Multi-Branch Workflow

- id: input_data
  tool: INPUT_JSON
  input:
    - name: value
      value: "[1, 2, 3, 4, 5]"

- id: process_even
  tool: PYTHON_SANDBOX_RUN
  needs:
    - input_data
  input:
    - name: code
      value: |
        data = {{steps.input_data.result}}
        result = [x for x in data if x % 2 == 0]

- id: process_odd
  tool: PYTHON_SANDBOX_RUN
  needs:
    - input_data
  input:
    - name: code
      value: |
        data = {{steps.input_data.result}}
        result = [x for x in data if x % 2 != 0]

- id: combine_results
  tool: PYTHON_SANDBOX_RUN
  needs:
    - process_even
    - process_odd
  input:
    - name: code
      value: |
        even = {{steps.process_even.result}}
        odd = {{steps.process_odd.result}}
        result = {"even": even, "odd": odd}

Conditional Execution (when)

The when option allows a step to execute only if a specified condition is true. This enables dynamic workflow behavior based on previous step results.

Basic Syntax

- id: conditional_step
  tool: TOOL_NAME
  when: "<condition_expression>"
  input:
    - name: param
      value: "value"

Condition Expressions

Conditions support:
  • String Comparison: "{{steps.check.result.status}}" == "success"
  • Numeric Comparison: {{steps.count.result}} > 5
  • Boolean Evaluation: {{steps.validate.result.isValid}} == true

Example: Conditional Branching

- id: check_type
  tool: PYTHON_SANDBOX_RUN
  input:
    - name: code
      value: |
        result = {"type": "premium"}

- id: premium_processing
  tool: PYTHON_SANDBOX_RUN
  when: "'{{steps.check_type.result.type}}' == 'premium'"
  needs:
    - check_type
  input:
    - name: code
      value: |
        result = "Processing premium user..."

- id: standard_processing
  tool: PYTHON_SANDBOX_RUN
  when: "'{{steps.check_type.result.type}}' == 'standard'"
  needs:
    - check_type
  input:
    - name: code
      value: |
        result = "Processing standard user..."

Important Notes

  • Conditions are evaluated before step execution
  • If the condition is false, the step status becomes skipped
  • Skipped steps don’t affect downstream steps that depend on them (they will also be skipped)
  • Use single quotes around template variables in string comparisons

Loop Execution (forEach)

The forEach option executes a step multiple times, once for each item in a collection. This is useful for batch processing lists of data.

Basic Syntax

- id: process_items
  tool: TOOL_NAME
  forEach: "{{steps.get_list.result}}"
  input:
    - name: item
      value: "{{item}}"

How It Works

  1. The forEach value is evaluated to get a list/array
  2. The step executes once for each item in the list
  3. Inside the step, {{item}} refers to the current item
  4. Results are collected as an array

Example: Processing Multiple Items

- id: get_users
  tool: INPUT_JSON
  input:
    - name: value
      value: |
        [
          {"id": 1, "name": "Alice"},
          {"id": 2, "name": "Bob"},
          {"id": 3, "name": "Charlie"}
        ]

- id: greet_users
  tool: PYTHON_SANDBOX_RUN
  forEach: "{{steps.get_users.result}}"
  needs:
    - get_users
  input:
    - name: code
      value: |
        user = {{item}}
        result = f"Hello, {user['name']}!"

- id: combine_greetings
  tool: PYTHON_SANDBOX_RUN
  needs:
    - greet_users
  input:
    - name: code
      value: |
        greetings = {{steps.greet_users.result}}
        result = "\n".join([g['result'] for g in greetings])

Accessing Item Properties

forEach: "{{steps.items.result}}"
input:
  - name: id
    value: "{{item.id}}"
  - name: name
    value: "{{item.name}}"

forEach with Index

If you need the index of the current item, you can use Jinja2 loops in the input:
- id: process_with_index
  tool: PYTHON_SANDBOX_RUN
  input:
    - name: code
      value: |
        items = {{steps.get_items.result}}
        results = []
        {%- for item in items %}
        results.append({"index": {{loop.index}}, "value": "{{item}}"})
        {%- endfor %}
        result = results

Combining Options

You can combine needs, when, and forEach in a single step:
- id: process_active_items
  tool: PYTHON_SANDBOX_RUN
  needs:
    - get_items
    - check_enabled
  when: "{{steps.check_enabled.result.active}} == true"
  forEach: "{{steps.get_items.result}}"
  input:
    - name: code
      value: |
        item = {{item}}
        result = f"Processed: {item}"
Evaluation Order:
  1. Wait for all needs dependencies to complete
  2. Check if when condition is true
  3. If true, execute forEach loop (or single execution if no forEach)

Best Practices

Dependencies

  • Keep dependency chains shallow when possible
  • Use parallel execution to improve performance
  • Clearly name steps to make dependencies readable

Conditions

  • Use meaningful condition expressions
  • Consider all possible outcomes (success, failure, edge cases)
  • Test conditions with various input values

Loops

  • Limit loop iterations to avoid long execution times
  • Handle empty arrays gracefully
  • Consider memory usage for large datasets