YAML Workflows

Define and execute complex workflows using YAML configuration files

python
from praisonaiagents import Agent

agent = Agent(name="pipeline-runner", instructions="Execute multi-step YAML workflows.")
agent.start("Run my workflow.yaml with sequential and parallel steps.")

The user authors YAML once; PraisonAI loads steps, routing, and parallel blocks at runtime.

Define complex multi-agent workflows in YAML files with support for advanced patterns like routing, parallel execution, loops, and more.

Diagram
AgentsYAML Parserpraisonai CLI👤 UserAgentsYAML Parserpraisonai CLI👤 Userpraisonai workflow run research.yamlparse YAMLcreate agents & stepsexecute sequentially / parallelresult output
Diagram

Execution

Patterns

YAML Definition

📄 workflow.yaml

Sequential

Parallel

Routing

Loop

📋 Planning

⚡ Execute

✅ Output

Minimum Required Fields

The absolute minimum to run a workflow:

yaml
agents:
  my_agent:
    role: Assistant        # Required: Agent's job title

steps:
  - agent: my_agent        # Required: Which agent executes

Practical minimum (recommended):

yaml
name: My Workflow
input: "Your input here"   # The data passed INTO the workflow (accessed via {{input}})

agents:
  my_agent:
    role: Assistant
    goal: Help with the task
    instructions: "You are a helpful assistant"

steps:
  - agent: my_agent
    action: "Process this: {{input}}"
FieldRequiredDefaultDescription
agents✅–At least one agent definition
agents.*.role✅–Agent’s job title
steps✅–At least one step
steps.*.agent✅–Agent to execute the step
name❌“Workflow”Workflow identifier
input❌“”Data passed INTO the workflow (accessed via {{input}}). See Workflow Input Resolution for CLI and programmatic precedence.
run_on❌NoneA shared remote sandbox used by every step’s shell / file tools — maps directly to the Python AgentFlow(run_on=…) kwarg. Accepts: docker, e2b, modal, daytona, flyio, tenki, local. Validated at load time. See Shared Sandbox and Placement.
goal❌“Complete the task”Agent’s objective
instructions❌GenericAgent behavior/persona
action❌{{input}}What the step does

Workflow Input Resolution

The value that fills {{input}} is resolved with this precedence, highest first.

Diagram
graph TB
    A["Where does {{input}} come from?"] --> B{"--var input= set?"}
    B -->|Yes| C["Use --var input value<br/>(even if empty)"]
    B -->|No|  D{"start(...) / run(input=...) called?"}
    D -->|Yes| E["Use programmatic value"]
    D -->|No|  F{"YAML top-level input: set?"}
    F -->|Yes| G["Use YAML input:<br/>(workflow.default_input)"]
    F -->|No|  H["{{input}} = empty string"]

    classDef q    fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef dec  fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef ans  fill:#10B981,stroke:#7C90A0,color:#fff
    classDef warn fill:#F59E0B,stroke:#7C90A0,color:#fff
    class A q
    class B,D,F dec
    class C,E,G ans
    class H warn
SourceWins overNotes
--var input=<value> (CLI)EverythingAn explicit empty (--var input=) is respected — it is not replaced by the YAML default.
workflow.start(<value>) / workflow.run(input=<value>)YAML input:Any non-empty explicit argument wins.
YAML top-level input:Empty stringStored on the parsed workflow as default_input. Used when no explicit input is supplied.
Empty string ""—The final fallback. Prints a CLI warning.

CLI input examples

bash
# 1. Uses the YAML `input:` value
praisonai workflow run research.yaml

# 2. Overrides the YAML value
praisonai workflow run research.yaml --var input="AI trends"

# 3. Force empty (does NOT fall back to the YAML default)
praisonai workflow run research.yaml --var input=

# Other --var keys do not affect input precedence
praisonai workflow run research.yaml --var topic="AI trends"

Programmatic input examples

python
from praisonaiagents import YAMLWorkflowParser

workflow = YAMLWorkflowParser().parse_file("research.yaml")

# Uses the YAML `input:` field if set
workflow.start()            # or workflow.start("")

# Explicit input wins over the YAML default
workflow.start("AI trends")

# run() also honors the YAML default when called with no argument
workflow.run()

Field Names Reference (A-I-G-S)

PraisonAI accepts both old (agents.yaml) and new (workflow.yaml) field names. Use the canonical names for new projects:

Canonical (Recommended)Alias (Also Works)Purpose
agentsrolesDefine agent personas
instructionsbackstoryAgent behavior/persona
actiondescriptionWhat the step does
stepstasks (nested)Define work items
name–Workflow identifier
inputtopicData passed INTO the workflow

A-I-G-S Mnemonic – Easy to remember:

  • Agents – Who does the work
  • Instructions – How they behave
  • Goal – What they achieve
  • Steps – What they do
yaml
# Quick Reference - Canonical Format
name: My Workflow              # Workflow name
input: What to process         # Data going INTO the workflow (not 'topic')
agents:                        # Define agents (not 'roles')
  my_agent:
    role: Job Title            # Agent's role
    goal: What to achieve      # Agent's goal
    instructions: How to act   # Agent's behavior (not 'backstory')

steps:                         # Define steps (not 'tasks')
  - agent: my_agent
    action: "Process: {{input}}"  # Step action (not 'description')

What workflow validate Guarantees

praisonai workflow validate <file.yaml> validates against the schema and cross-references every agent reference. It now guarantees:

  • Every workflow under examples/yaml/workflows/ passes (enforced by a regression test).
  • Agent-existence checks traverse nested route:, parallel:, loop:, repeat:, and if: payloads — an undefined agent in any of them is flagged with a clear error and non-zero exit.
  • loop: {over: <variable_name>} is treated as a variable, not an agent reference, so it is never flagged.

Sample output — pass:

text
$ praisonai workflow validate research.yaml
✓ research.yaml is valid

Sample output — undefined agent:

text
$ praisonai workflow validate broken.yaml
✗ broken.yaml is invalid
  Step 'route' references undefined agent 'reviewer'

Supported Step Forms

The validator accepts two dialects:

1. Explicit typed steps — name and type set:

yaml
steps:
  - name: research
    type: task
    agent: researcher
    task: "Research {{input}}"

2. Bare runtime forms — no name/type required:

yaml
steps:
  - agent: researcher
    action: "Research {{input}}"
  - route: {approved: [publish], rejected: [edit]}
  - if: {condition: "{{score}} > 80", then: [premium], else: [standard]}
  - loop: {over: items, agent: worker}
  - repeat: {times: 3, agent: worker}
  - parallel: [research, summarize]
  - include: shared/common.yaml

Feature Parity

Both agents.yaml and workflow.yaml now support the same features:

Featureagents.yamlworkflow.yaml
Workflow patterns (route, parallel, loop, repeat)✅✅
All agent fields✅✅
All step/task fields✅✅
Framework support (praisonai, crewai, autogen)✅✅
Process types (sequential, hierarchical, workflow)✅✅
Planning & Reasoning✅✅

Quick Start

  1. Run and validate a workflow
    CLI
    # Run a YAML workflow
    praisonai workflow run research.yaml
    
    # Run with variables
    praisonai workflow run research.yaml --var topic="AI trends"
    
    # Override the top-level `input:` field (see Workflow Input Resolution)
    praisonai workflow run research.yaml --var input="AI trends"
    
    # Validate a workflow
    praisonai workflow validate research.yaml
    
    # Create from template
    praisonai workflow template routing --output my_workflow.yaml
    
    # Auto-generate a workflow
    praisonai workflow auto "Research AI trends" --pattern parallel
    Python
    from praisonaiagents import YAMLWorkflowParser, WorkflowManager
    
    # Option 1: Parse and execute
    parser = YAMLWorkflowParser()
    workflow = parser.parse_file("research.yaml")
    result = workflow.start("Research AI trends")
    
    # Option 2: Use WorkflowManager
    manager = WorkflowManager()
    result = manager.execute_yaml(
        "research.yaml",
        input_data="Research AI trends",
        variables={"topic": "Machine Learning"}
    )
    Programmatic Usage
    # Option 3: AgentsGenerator (auto-detects workflow YAML)
    from praisonai.agents_generator import AgentsGenerator
    
    # Sync path
    gen = AgentsGenerator(agent_file="research.yaml")
    result = gen.generate_crew_and_kickoff()
    
    # Async path (works the same as sync)
    import asyncio
    async def main():
        gen = AgentsGenerator(agent_file="research.yaml")
        return await gen.agenerate_crew_and_kickoff()
    
    result = asyncio.run(main())

tool_timeout on workflow YAML

Setting an explicit tool_timeout on a process: workflow YAML fails fast — the run raises rather than silently ignoring it. Per-tool timeouts apply to process: sequential and process: hierarchical runs only; the native workflow orchestrator resolves its own tools by name and doesn’t host the per-tool timeout wrapper.

Diagram

tool_timeout on process: workflow?

No tool_timeout / bare CLI default

Explicit YAML value or changed –tool-timeout

✅ Workflow runs

🛑 Run raises fail-fast

Historical: PR #3252 added warning diagnostics; PR #3963 upgraded them to fail-fast so a silent no-op can’t hide a mis-configured production YAML. The follow-up commit refined the check so the bare CLI --tool-timeout default is still ignored — only an explicit request raises.

Run on a Shared Remote Sandbox

Add run_on: at the top level and every step’s shell and file tools bind to one shared remote sandbox — no Python needed.

yaml
name: remote-sandbox-demo
run_on: docker            # every step shares ONE sandbox

agents:
  writer:
    role: File Writer
    goal: Write files into the shared workspace
    instructions: "Use write_file and execute_command on the remote sandbox."
  reader:
    role: File Reader
    goal: Read files back out of the shared workspace
    instructions: "Use read_file on the same remote sandbox the writer used."

steps:
  - agent: writer
    action: "Use write_file to put 'hello from step 1' in /workspace/note.txt"
  - agent: reader
    action: "Use read_file on /workspace/note.txt and report its contents"

Accepted providers: docker, e2b, modal, daytona, flyio, tenki, local. Omit run_on: for the default local execution. An unknown provider name fails at load time with the list of valid names, so a typo never reaches the first tool call:

ValueError: Unknown run_on provider 'dokcer'. Available: docker, e2b, modal, daytona, flyio, tenki, local
Shared Sandbox

Full behaviour, the choose-a-provider decision diagram, and Python-API equivalents.

Complete workflow.yaml Reference

yaml
# workflow.yaml - Full feature reference
name: Complete Workflow
description: Demonstrates all workflow.yaml features
framework: praisonai  # workflow YAML only supports praisonai
process: workflow     # sequential, hierarchical, workflow
input: "Your input data here"  # Data passed into workflow (accessed via {{input}})
run_on: docker        # optional — share one sandbox across every step. See Shared Sandbox.

# ============================================================================
# WORKFLOW SETTINGS
# ============================================================================
workflow:
  planning: true                      # Enable planning mode
  planning_llm: gpt-4o                # LLM for planning
  reasoning: true                     # Enable reasoning mode
  verbose: true                       # Verbose output
  router: true                        # Enable model routing
  routing_strategy: cost-optimized    # auto, cost-optimized, performance-optimized
  memory_config:
    provider: chroma
    persist: true

# ============================================================================
# CONTEXT MANAGEMENT (Prevent Token Overflow)
# ============================================================================
context: true  # Enable auto-compaction (recommended for workflows with tools)

# ============================================================================
# CUSTOM MODELS (Optional - for model routing)
# ============================================================================
models:
  cheap-fast:
    provider: openai
    complexity: [simple]              # simple, moderate, complex, very_complex
    cost_per_1k: 0.0001
    capabilities: [text]
    context_window: 16000

  balanced:
    provider: openai
    complexity: [moderate]
    cost_per_1k: 0.001
    capabilities: [text, function-calling]
    context_window: 128000

  premium:
    provider: anthropic
    complexity: [complex, very_complex]
    cost_per_1k: 0.015
    capabilities: [text, vision, function-calling]
    context_window: 200000
    supports_tools: true
    supports_streaming: true
    strengths: [reasoning, analysis, code-generation]

# ============================================================================
# VARIABLES
# ============================================================================
variables:
  topic: AI trends
  items: [ML, NLP, Vision]

# ============================================================================
# AGENTS
# ============================================================================
agents:
  researcher:
    name: Researcher                  # Display name
    role: Research Analyst            # Required: Agent's job title
    goal: Research topics thoroughly  # Agent's objective
    instructions: "Provide detailed research findings"  # Agent behavior/persona

    # LLM Configuration
    llm: gpt-4o-mini                  # Model to use
    llm_routing: auto                 # Enable auto model selection
    llm_models: [balanced, premium]   # Models for auto-routing
    function_calling_llm: gpt-4o      # Model for tool calls
    reflect_llm: gpt-4o               # Model for self-reflection

    # Rate Limiting & Timeouts
    max_rpm: 10                       # Wires a live RateLimiter (throttles at 10 rpm); must be > 0
    max_execution_time: 300           # Timeout in seconds

    # Self-Reflection
    min_iterations: 1                    # Minimum reflection iterations
    max_iterations: 3                    # Maximum reflection iterations

    # System Prompt
    system_template: "You are a helpful assistant"

    # Tools
    tools:
      - tavily_search
      - wikipedia_search

  writer:
    name: Writer
    role: Content Writer
    goal: Write clear content
    instructions: "Write engaging content"
    llm: premium                      # Use premium model for quality

# ============================================================================
# STEPS
# ============================================================================
steps:
  # Basic step
  - name: research_step
    agent: researcher
    action: "Research {{input}}"      # Use {{input}} for workflow input
    expected_output: "Comprehensive research report"
    output_file: "output/research.md"
    create_directory: true

  # Step with context dependency
  - name: writing_step
    agent: writer
    action: "Write article based on: {{previous_output}}"
    context:                          # Task dependencies
      - research_step
    output_json:                      # Structured output
      type: object
      properties:
        title: { type: string }
        content: { type: string }

  # Parallel step
  - name: parallel_research
    parallel:
      - agent: researcher
        action: "Research market trends"
      - agent: researcher
        action: "Research competitors"

  # Routing step
  - name: routing
    route:
      technical: [tech_agent]
      creative: [creative_agent]
      default: [researcher]

  # Loop step
  - agent: researcher
    action: "Research {{item}}"
    loop:
      over: items                     # Variable to iterate

  # Repeat step (evaluator-optimizer)
  - agent: writer
    action: "Write and improve"
    repeat:
      until: "approved"
      max_iterations: 3

# ============================================================================
# CALLBACKS (Optional)
# ============================================================================
callbacks:
  on_workflow_start: log_start
  on_step_complete: log_step
  on_workflow_complete: log_complete

Agent Fields Reference

FieldRequiredDefaultDescription
role✅–Agent’s job title
name❌Agent IDDisplay name
goal❌“Complete the task”Agent’s objective
instructions❌GenericAgent behavior/persona (alias: backstory)
llm❌gpt-4o-miniModel to use
llm_routing❌–Enable auto model selection (auto)
llm_models❌–Models for auto-routing
function_calling_llm❌Same as llmModel for tool calls
reflect_llm❌Same as llmModel for self-reflection
max_rpm❌UnlimitedMax requests per minute. A positive int wires a live RateLimiter(requests_per_minute=max_rpm) when the agent has no limiter set, so YAML max_rpm actually throttles requests. max_rpm <= 0 raises ValueError.
max_execution_time❌300Timeout in seconds
min_iterations❌0Minimum reflection iterations
max_iterations❌3Maximum reflection iterations
system_template❌–Custom system prompt
tools❌[]List of tools

Step Fields Reference

FieldRequiredDefaultDescription
agent✅*–Agent to execute (*not needed for parallel/route/include)
action❌{{input}}What the step does
name❌Auto-generatedStep identifier
expected_output❌–Description of expected output
output_file❌–Save output to file
create_directory❌falseCreate output directory
context❌–List of dependent step names
output_json❌–JSON schema for structured output (inline schema)
output_pydantic❌–Pydantic model name from tools.py for structured output
output_variable❌–Store output in named variable for use in subsequent steps
parallel❌–List of parallel sub-steps
context (on parallel/loop)❌fullUpstream-output pass-through for parallel/loop(parallel: true) steps: full (default, lossless), truncate, or summarize (parallel only). Distinct from the step-dependency context: list above. See Context pass-through to branches.
route❌–Routing configuration
loop❌–Loop configuration (over: variable)
repeat❌–Repeat configuration (until, max_iterations)
include❌–Include another recipe (recipe, input, variables)

Models Fields Reference

FieldRequiredDefaultDescription
provider✅–Provider: openai, anthropic, google, openrouter
complexity✅–List: simple, moderate, complex, very_complex
cost_per_1k✅–Cost per 1,000 tokens in USD
capabilities❌[text]List: text, vision, function-calling, streaming
context_window❌128000Max context window in tokens
supports_tools❌trueSupports tool/function calling
supports_streaming❌trueSupports streaming responses
strengths❌–List: reasoning, code-generation, analysis, etc.

YAML Callbacks

The callbacks: block wires workflow lifecycle functions into the Workflow engine (PR #5338). YAML cannot import Python by name, so each func_name must be registered on the parser before parsing.

  1. Register the callbacks
    python
    from praisonaiagents.workflows import YAMLWorkflowParser
    
    def log_start(*args, **kwargs):
        print("workflow started")
    
    def log_step(*args, **kwargs):
        print("step complete")
    
    parser = YAMLWorkflowParser()
    parser.register_callback("log_start", log_start)
    parser.register_callback("log_step", log_step)
    workflow = parser.parse_file("workflow.yaml")
  2. Reference them in YAML
    yaml
    callbacks:
      on_workflow_start: log_start
      on_step_complete: log_step

Supported lifecycle names. Only these five names map to WorkflowHooksConfig and reach the Workflow engine:

Lifecycle nameFires
on_workflow_startBefore the workflow runs
on_workflow_completeAfter the workflow finishes
on_step_startBefore each step
on_step_completeAfter each step
on_step_errorWhen a step raises

Any other name resolves but is not wired to the Workflow engine.

Context Management (Token Overflow Prevention)

Enable automatic context optimization to prevent “context length exceeded” errors:

yaml
# Simple: Enable with defaults
context: true

# Or detailed configuration
context:
  auto_compact: true       # Automatically compact when threshold reached
  compact_threshold: 0.8   # Trigger at 80% of context window
  strategy: smart          # smart | truncate | sliding_window | summarize | prune_tools
  tool_output_max: 10000   # Max tokens per tool output (e.g., search results)

What Context Management Does

When context: true is enabled:

  1. Auto-compaction: Automatically compresses history when approaching token limits
  2. Tool Output Truncation: Limits large tool results (e.g., full web page content)
  3. Smart Strategy: Prioritizes recent/important messages, prunes tool outputs first
  4. Overflow Prevention: Prevents “context_length_exceeded” errors

Best Practices

yaml
# Recommended for workflows with search/crawl tools
name: Research Workflow
context: true  # ← Enable this!

agents:
  researcher:
    role: Researcher
    tools:
      - tavily_search
      - crawl_url

steps:
  - agent: researcher
    action: "Search for {{topic}}"

Context Strategies

StrategyDescriptionBest For
smartAdaptive strategy (default)General use
truncateRemove oldest messagesSpeed-critical
sliding_windowKeep last N turnsConversation agents
summarizeLLM summarizes old contextQuality preservation
prune_toolsTruncate tool outputs firstTool-heavy workflows

Remote execution (run_on:)

Add run_on: at the top of a workflow and every step’s shell and file tools share one remote sandbox — the file one step writes to /workspace is there for the next step to read.

yaml
name: remote-sandbox-demo
run_on: docker            # every step shares one sandbox

agents:
  writer:
    role: File Writer
    goal: Write files into the shared workspace
  reader:
    role: File Reader
    goal: Read files back from the shared workspace

steps:
  - agent: writer
    action: "Write 'hello from step 1' to /workspace/note.txt"
  - agent: reader
    action: "Read /workspace/note.txt and report its exact contents"
Diagram

🐳 One shared sandbox — run_on: docker

✍️ Writer step

📄 /workspace/note.txt

👀 Reader step

Omit run_on: and nothing changes — the workflow runs locally as before. A typo is caught at load time, not mid-run. See Shared Sandbox for providers, validation, and the Python AgentFlow(run_on=…) equivalent.

Workflow Patterns

Diagram

Which pattern?

Run agents one by one

Run agents simultaneously

Route to specialist based on input

Process a list of items

Retry until quality threshold

Reuse another workflow

steps: sequential

parallel: [step1, step2]

route: {label: [agent]}

loop: {over: variable}

repeat: {until: condition}

include: recipe-name

Sequential (Default)

Agents execute one after another, passing context.

yaml
name: Sequential Workflow
agents:
  researcher:
    name: Researcher
    role: Research Analyst
    goal: Research topics
    instructions: "Provide research findings"
  writer:
    name: Writer
    role: Content Writer
    goal: Write content
    instructions: "Write based on research"

steps:
  - agent: researcher
    action: "Research {{topic}}"
  - agent: writer
    action: "Write summary based on: {{previous_output}}"

Parallel

Multiple agents work concurrently.

yaml
name: Parallel Workflow
agents:
  market_analyst:
    name: MarketAnalyst
    role: Market Researcher
    goal: Research market trends
    instructions: "Provide market insights"
  tech_analyst:
    name: TechAnalyst
    role: Technology Researcher
    goal: Research technology
    instructions: "Provide tech insights"
  aggregator:
    name: Aggregator
    role: Synthesizer
    goal: Combine findings
    instructions: "Synthesize all research"

steps:
  - name: parallel_research
    parallel:
      - agent: market_analyst
        action: "Research market trends for {{topic}}"
      - agent: tech_analyst
        action: "Research technology trends for {{topic}}"
    context: full          # optional; default "full". "truncate"/"summarize" opt in to token savings
  - agent: aggregator
    action: "Combine all findings into a report"

The context: key maps to the Python parallel(..., context=...) parameter — full (default, lossless), truncate, or summarize. See Context pass-through to branches for the semantics.

yaml
# Parallel step — opt in to the head+tail excerpt (and warn on drop)
parallel:
  - step_a
  - step_b
context: truncate        # optional; default "full"
on_failure: fail_fast    # optional; default "partial_ok"

# Loop step — same opt-in for parallel iterations (no "summarize" on loop)
loop:
  over: items
  parallel: true
  context: truncate      # optional; default "full"
  step: processor

Routing

Classifier routes to specialized agents.

yaml
name: Routing Workflow
agents:
  classifier:
    name: Classifier
    role: Request Classifier
    goal: Classify requests
    instructions: "Respond with ONLY: 'technical', 'creative', or 'general'"
  tech_expert:
    name: TechExpert
    role: Technical Expert
    goal: Handle technical questions
    instructions: "Provide technical answers"
  creative_expert:
    name: CreativeExpert
    role: Creative Expert
    goal: Handle creative requests
    instructions: "Provide creative responses"

steps:
  - agent: classifier
    action: "Classify: {{input}}"
  - name: routing
    route:
      technical: [tech_expert]
      creative: [creative_expert]
      default: [tech_expert]

Loop

Iterate over a list of items.

yaml
name: Loop Workflow
variables:
  topics:
    - Machine Learning
    - Natural Language Processing
    - Computer Vision

agents:
  researcher:
    name: Researcher
    role: Research Analyst
    goal: Research topics
    instructions: "Provide brief research on each topic"

steps:
  - agent: researcher
    action: "Research {{item}}"
    loop:
      over: topics
      parallel: true
      context: full        # optional; default "full". "truncate" opts in to token savings (parallel only)

Multi-Step Loop

Execute multiple steps sequentially for each item in the loop. This is perfect for pipelines where each item needs to go through several processing stages (e.g., research → write → publish).

yaml
name: Multi-Step Loop Workflow
variables:
  topics:
    - Machine Learning
    - Natural Language Processing
    - Computer Vision

agents:
  researcher:
    role: Research Analyst
    goal: Research topics thoroughly
    instructions: "Provide comprehensive research"
    tools:
      - tavily_search

  writer:
    role: Content Writer
    goal: Write engaging articles
    instructions: "Write in British English, include code examples"

  publisher:
    role: WordPress Publisher
    goal: Publish content to WordPress
    instructions: "Validate content before publishing"
    tools:
      - create_wp_post

steps:
  # Multi-step loop: research → write → publish for EACH topic
  - loop:
      over: topics
      parallel: true      # Process topics in parallel
      max_workers: 4      # Limit concurrent executions
    steps:
      - agent: researcher
        action: "Research {{item}} thoroughly"
      - agent: writer
        action: "Write article based on: {{previous_output}}"
      - agent: publisher
        action: "Publish: {{previous_output}}"

# Enable context management to prevent token overflow
context:
  enabled: true
  max_tool_output_tokens: 5000

Multi-Step Loop Features

FeatureDescription
steps:Array of steps to execute for each item
{{item}}Access current loop item in first step
{{previous_output}}Chain outputs between steps in iteration
parallel: trueExecute iterations concurrently
max_workers: NLimit parallel workers
output_variableStore final outputs in variable

Structured Output

Get structured JSON responses from agents using output_json (inline schema) or output_pydantic (reference to Pydantic model in tools.py).

Inline JSON Schema (Option A)

yaml
name: Structured Output Workflow
agents:
  topic_finder:
    role: Topic Finder
    goal: Find AI topics
    instructions: "Return topics as structured JSON"

steps:
  - agent: topic_finder
    action: "Find 3 AI topics"
    output_json:
      type: array
      items:
        type: object
        properties:
          title:
            type: string
          url:
            type: string
        required:
          - title
          - url
    output_variable: topics

  # Loop over the structured output
  - agent: researcher
    action: "Research: {{item.title}}"
    loop:
      over: topics

Pydantic Reference (Option B)

yaml
# agents.yaml
name: Structured Output Workflow
agents:
  topic_finder:
    role: Topic Finder
    goal: Find AI topics
    instructions: "Return topics as structured JSON"

steps:
  - agent: topic_finder
    action: "Find 3 AI topics"
    output_pydantic: TopicList  # Reference to class in tools.py
    output_variable: topics
python
# tools.py (in same directory)
from pydantic import BaseModel
from typing import List

class Topic(BaseModel):
    title: str
    url: str

class TopicList(BaseModel):
    items: List[Topic]

Repeat (Evaluator-Optimizer)

Repeat until a condition is met.

yaml
name: Repeat Workflow
agents:
  writer:
    name: Writer
    role: Content Writer
    goal: Write high-quality content
    instructions: "Write and improve content"
  evaluator:
    name: Evaluator
    role: Quality Checker
    goal: Evaluate content quality
    instructions: "Rate content 1-10. Say 'approved' if >= 8"

steps:
  - agent: writer
    action: "Write article about {{topic}}"
    repeat:
      until: "approved"
      max_iterations: 3

Include (Modular Recipes)

Include reusable recipe files in your workflow.

yaml
name: Parent Workflow
topic: "AI Code & Tools 2026"

variables:
  today: "January 2026"

agents:
  writer:
    role: Content Writer
    goal: Write content
    instructions: "Write engaging content"

steps:
  # Include a modular recipe - it receives parent's variables
  - include: ai-topic-gatherer

  # Or with explicit configuration
  - include:
      recipe: ai-research-pipeline
      input: "{{previous_output}}"

  # Continue with local steps
  - agent: writer
    action: "Write blog post about: {{previous_output}}"

Variables

Define reusable variables for use throughout your workflow.

yaml
name: Variables Workflow
topic: "AI Development Tools"  # Automatically added to variables

variables:
  today: "January 2026"
  max_results: 5
  categories:
    - "Coding Assistants"
    - "Testing Tools"
    - "Documentation"

agents:
  researcher:
    role: Research Analyst
    goal: Research topics
    instructions: "Research AI development tools"

steps:
  # Use topic variable (from topic: field)
  - agent: researcher
    action: |
      Today is: {{today}}
      Research: {{topic}}
      Find up to {{max_results}} results

  # Loop over variable list
  - agent: researcher
    action: "Research {{item}}"
    loop:
      over: categories

Variable Substitution Examples:

PatternDescriptionExample
{{input}}Workflow input"Process: {{input}}"
{{topic}}Topic field value"Research {{topic}}"
{{previous_output}}Previous step result"Expand on: {{previous_output}}"
{{variable_name}}Custom variable"Date: {{today}}"
{{item}}Current loop item"Process {{item}}"
{{item.field}}Field in loop item"Title: {{item.title}}"

Extended agents.yaml

Use workflow patterns in agents.yaml with process: workflow:

yaml
# agents.yaml with workflow patterns
framework: praisonai
process: workflow  # Enables workflow mode
topic: "Research AI trends"

workflow:
  planning: true
  reasoning: true
  verbose: true

agents:  # Canonical: use 'agents' instead of 'roles'
  classifier:
    role: Request Classifier
    instructions:  # Canonical: use 'instructions' instead of 'backstory' "Classify requests into categories"
    goal: Classify requests

  researcher:
    role: Research Analyst
    instructions:  # Canonical: use 'instructions' instead of 'backstory' "Expert researcher"
    goal: Research topics
    tools:
      - tavily_search

steps:
  - agent: classifier
    action: "Classify: {{topic}}"

  - name: routing
    route:
      technical: [tech_expert]
      default: [researcher]

  - name: parallel_research
    parallel:
      - agent: researcher
        action: "Research market trends"
      - agent: researcher
        action: "Research competitors"

Run with:

bash
praisonai agents.yaml

Auto-Generate Workflows

Generate workflows automatically from a topic description:

bash
# Sequential workflow (default)
praisonai workflow auto "Research AI trends"

# Parallel workflow
praisonai workflow auto "Research AI trends" --pattern parallel

# Routing workflow
praisonai workflow auto "Build a chatbot" --pattern routing

# Specify output file
praisonai workflow auto "Research AI" --output my_workflow.yaml

CLI Commands

CommandDescription
praisonai workflow run <file.yaml>Run a YAML workflow
praisonai workflow run <file.yaml> --var key=valueRun with variables
praisonai workflow validate <file.yaml>Validate a workflow (checks nested route:/parallel:/loop:/repeat:/if: agent references)
praisonai workflow template <name>Create from template
praisonai workflow auto "topic"Auto-generate workflow
praisonai workflow listList workflows
praisonai workflow helpShow help

CLI Options

FlagDescription
--var key=valueSet variable for YAML workflows
--var input=<value>Reserved key. Overrides the YAML top-level input: field. An explicit empty --var input= is respected and does not fall back to the YAML default. See Workflow Input Resolution.
--pattern <pattern>Pattern for auto-generation (sequential, parallel, routing, loop)
--output <file>Output file for auto-generation
--planningEnable planning mode
--reasoningEnable reasoning mode
--verboseEnable verbose output
--saveSave output to file

Progress Indicators

When running workflows, you’ll see clear progress indicators:

Running YAML workflow: research.yaml
Workflow input: Research the latest AI development tools...
 Workflow: Research Workflow  
┏━━━━━━━━━━━┳━━━━━━━┓
┃ Property  ┃ Value ┃
┡━━━━━━━━━━━╇━━━━━━━┩
│ Steps     │ 3     │
│ Planning  │ True  │
│ Reasoning │ False │
└───────────┴───────┘

Executing workflow...

📋 Execution Plan: [plan description]
⚡ Running 2 steps in parallel...
✅ Parallel complete: 2 results
🔀 Routing to: technical
✅ AgentName: [output preview]

✅ Workflow completed successfully!

When no input is resolved (no YAML input:, no --var input, no argument), the CLI prints a warning instead of the preview line:

Warning: no workflow input — {{input}} will be empty unless --var input=... is set

Debug Mode

Enable debug logging to see detailed execution:

bash
LOGLEVEL=debug praisonai workflow run research.yaml

This shows:

  • Agent parameters (prompt, temperature, tools)
  • Messages sent to LLM
  • HTTP requests to API
  • Full agent/role/goal context

Best Practices

Validate YAML before deploy

Run workflows locally with LOGLEVEL=debug to catch missing agents or tools early.

Use variable substitution for secrets

Reference env vars in YAML instead of hard-coding API keys in workflow files.

Keep workflows focused

Split large YAML files into modular recipes rather than one monolithic definition.

Version control workflow files

Treat YAML workflows like code — review changes and test in CI before production.

Related