YAML Configuration Reference

Complete reference for agents.yaml and workflow.yaml configuration options

Complete reference for all configuration options in agents.yaml and workflow.yaml files.

Quick Start

  1. Load an agent from YAML
    python
    from praisonaiagents import Agent
    
    agent = Agent(name="yaml-runner", instructions="Behaviour defined in agents.yaml")
    agent.start("Run the workflow defined in YAML")
  2. Run the YAML workflow
    bash
    praisonai start agents.yaml

    The user maintains YAML config; the agent loads it and executes the requested workflow.

Diagram

Execution

Shared Features

Configuration Files

📄 agents.yaml

📄 workflow.yaml

👤 Agents

📋 Steps

📦 Variables

🔧 Tools

⚡ Execute

How It Works

Diagram
YamlConfigurationReferenceAgentUserYamlConfigurationReferenceAgentUserRequestProcessResultResponse

Quick Comparison

agents.yaml Style

yaml
framework: praisonai
topic: "Research AI trends"

roles:
  researcher:
    role: Research Analyst
    backstory: "Expert researcher"
    goal: Research topics
    tools:
      - tavily_search

  researcher:
    tasks:
      research_task:
        description: "Research {{topic}}"
        expected_output: "Research report"

workflow.yaml Style (Canonical)

yaml
name: Research Workflow
input: "Research AI trends"

agents:
  researcher:
    role: Research Analyst
    instructions: "Expert researcher"
    goal: Research topics
    tools:
      - tavily_search

steps:
  - agent: researcher
    action: "Research {{input}}"
    expected_output: "Research report"

Field Name Mapping

PraisonAI accepts both old and new field names. Use canonical names for new projects.

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

List vs. Dict Shape

PraisonAI auto-normalises list-form agents, roles, and tasks into dict form on load — you don’t need to convert legacy configs by hand.

List form (e.g. imported from CrewAI-style YAML)

yaml
agents:
  - name: researcher
    role: Research Analyst
    instructions: "Expert researcher"

tasks:
  - name: research_task
    agent: researcher
    description: "Research {{topic}}"

Dict form (canonical — recommended for new projects)

yaml
agents:
  researcher:
    role: Research Analyst
    instructions: "Expert researcher"
    tasks:
      research_task:
        description: "Research {{topic}}"

Empty roles: {} Is Treated as Missing

A YAML that carries an empty roles: {} alongside a populated agents: block (dict or list) and a list-form tasks: promotes the agents into roles and grafts the tasks — it does not run with zero agents.

This YAML now yields one role per agent with its tasks attached:

yaml
framework: praisonai
topic: research renewable energy
roles: {}
agents:
  researcher:
    role: Renewable Energy Researcher
    goal: Find the latest solar breakthroughs
    backstory: A materials-science PhD.
tasks:
  - name: summarise
    agent: researcher
    description: Summarise the top 3 breakthroughs of 2026.
    expected_output: A 3-bullet summary.

Shorthand: agents: gets promoted to roles:

agents.yaml accepts two spellings of the same idea. The shorthand agents: bucket is merged into roles: before the workflow runs, so both forms produce the same result.

Canonical (roles:)

yaml
framework: praisonai
roles:
  writer:
    role: "Writer"
    goal: "Draft clear content"
    tasks:
      draft:
        description: "Draft an intro for {{topic}}"

Shorthand (agents:) — same result

yaml
framework: praisonai
agents:
  writer:
    role: "Writer"
    goal: "Draft clear content"
    tasks:
      draft:
        description: "Draft an intro for {{topic}}"

As of PraisonAI PR #5307 the merge is authoritative — _prepare_for_run promotes the shorthand and then drops it so validators and the executor read a single source of truth:

  • agents: is deleted after promotion, so downstream validators and the executor read the same map.
  • When both spellings define the same key, the canonical roles: entry wins.
  • instructions: inside an agent block is renamed to backstory: during promotion (existing behaviour, unchanged).
Diagram

YAML normalization

📄 agents.yaml

⚙️ _prepare_for_run

🔀 Merge agents: into roles:

🗑️ Delete agents:

▶️ Executor reads roles:

Precedence on conflict — the canonical roles: entry wins and the agents: duplicate is ignored:

yaml
framework: praisonai
roles:
  writer:
    role: "Senior Writer"          # ← wins
agents:
  writer:
    role: "Junior Writer"          # ← ignored (canonical roles: wins)

Task Ordering in Roles-File YAML

Tasks in a roles-file YAML run in the order they are declared under each role and, across roles, in the order the roles appear.

Diagram

writer

researcher

research_task

summary_task

The loader walks roles: top-to-bottom, and each role’s tasks: top-to-bottom, appending every task to a single run list in that order.

yaml
framework: praisonai
topic: "Latest AI research"

roles:
  researcher:
    role: Research Analyst
    goal: Gather findings on the topic
    backstory: Expert researcher.
    tasks:
      research_task:
        description: "Research {{topic}}"
        expected_output: "A list of key findings"

  writer:
    role: Technical Writer
    goal: Summarise the findings
    backstory: Clear, concise writer.
    tasks:
      summary_task:
        description: "Summarise the research findings"
        expected_output: "A short summary"

# documentary only — the roles-file loader does NOT read this block
dependencies:
  summary_task:
    - research_task

research_task runs first because researcher is declared before writer; summary_task runs second. The dependencies: block reflects that intent for readers but does not drive it.

Copy-paste starter: examples/yaml/teams/research-writer/.


Running a Roles-File YAML

A roles-file YAML runs as a positional argument to praisonai; from Python the equivalent is praisonai.run(<path>).

CLI

bash
export OPENAI_API_KEY=sk-...
praisonai agents.yaml

Python

python
import praisonai

praisonai.run("agents.yaml")

See CLI Reference for the full flag surface of the positional form, and praisonai run for the per-prompt entry point.


Automatic Field Validation

PraisonAI validates every field name in your agents.yaml before execution begins — unknown fields produce warnings and invalid configs abort immediately.

Diagram

📄 agents.yaml

🔍 Schema Check

🔗 Cross-Ref Check

🔧 Tool Check

✅ Run Workflow

❌ Abort (ValueError)

Diagram
YAML Configuration ReferenceAgentUserYAML Configuration ReferenceAgentUserRequestProcess requestResultResponse
  1. Create YAML with typo
    yaml
    # agents.yaml
    framework: praisonai
    topic: "Summarize Python history"
    agents:
      researcher:
        role: Research Analyst
        goal: Provide a historical summary
        instrutions: "Focus ONLY on years 1989–2000."   # typo — warning
        backstory: Expert researcher.
  2. Run workflow and see warning
    bash
    praisonai start agents.yaml

    Output (unknown field → warning, workflow still runs):

    WARNING: Unknown agent field 'instrutions' in agent 'researcher'. This field will be ignored.
  3. Validate before running
    bash
    praisonai validate agents.yaml

    Catch all errors upfront without running the workflow.

Fail-Fast Errors

These conditions abort the run immediately with an aggregated error message.

Missing required field:

yaml
agents:
  researcher:
    role: Research Analyst
    # goal is required but missing
    backstory: Expert researcher.

Result:

Configuration validation failed with 1 error(s):
  1. Agent 'researcher': missing required field 'goal'

Bad cross-reference (task references undefined agent):

yaml
agents:
  researcher:
    role: Research Analyst
    goal: Research topics
    backstory: Expert researcher.

tasks:
  write_report:
    description: Write a report
    agent: writer      # 'writer' is not defined!

Result:

Configuration validation failed with 1 error(s):
  1. Task 'write_report': references unknown agent 'writer' (not defined in agents/roles)

Unknown tool:

yaml
agents:
  researcher:
    role: Research Analyst
    goal: Research topics
    backstory: Expert researcher.
    tools:
      - nonexistent_tool

Result:

Configuration validation failed with 1 error(s):
  1. Unknown tool 'nonexistent_tool'. Ensure it's properly installed or defined in your configuration.

Optional tools with extra dependencies produce a warning instead:

WARNING: Tool 'BrowserTool' requires additional dependencies. Install with: pip install 'praisonai[tools]'

Required Agent Fields

The editor schema (used for autocomplete) does not require these three fields — the runtime auto-fills role/goal from the agent key and maps instructions → backstory. The strict validator behind praisonai validate still requires them, so run validate before shipping even if your editor shows no errors.

Recognized Fields

All recognized field names for agents in both agents: and roles: sections:

FieldTypePurpose
rolestringAgent’s job title
goalstringAgent’s objective
instructionsstringBehavior instructions
backstorystringPersonality/background context
toolsarrayList of tool names
tasksobjectNested task definitions (legacy)
llmstring \dictModel to use
function_calling_llmstring \dictModel for tool calls
allow_delegationboolAllow task delegation
max_iterintMaximum iterations
max_rpmintMax requests per minute — auto-builds a RateLimiter when set; max_rpm <= 0 raises ValueError
max_execution_timeintTimeout in seconds
executionobjectAgent-level ExecutionConfig mapping (max_budget, on_budget_exceeded, durable, journal_path, resume_run_id, …). Workflow YAMLs only. Flat max_iter / max_execution_time win when both are set. See execution: block
verboseboolVerbose output
cacheboolEnable response caching
system_templatestringCustom system prompt
prompt_templatestringCustom prompt template
response_templatestringCustom response template
tool_timeoutintPer-call tool execution timeout in seconds. Enforced at two layers when running framework: praisonai: (1) the wrapper wraps every tool callable in a timeout-enforcing shim that raises ToolTimeoutError (a TimeoutError subclass) on timeout — framework adapters translate it per framework — and (2) the SDK Agent’s executor pool also honours the same value. Sync tools run in an instance-owned ThreadPoolExecutor on the wrapper layer; async tools use asyncio.wait_for. When agents declare different tool_timeout values, each agent’s tools carry its own budget (per-agent wrap; shared tool objects). The shared-wrap fast path is used only when every agent declares tool_timeout and every declared value is identical. If any agent omits the field, the shared wrap is skipped and undeclared agents run with no imposed timeout (they do not inherit another agent’s declared value). CLI --tool-timeout overrides all agents. See Tool Timeouts for the precedence table. YAML bool values (tool_timeout: yes) are ignored. See Concurrency → Effective Timeout Precedence and Tool Configuration for the full contract. In Python this maps to tool_config=ToolConfig(timeout=…) — the standalone tool_timeout= kwarg on Agent(...) was removed. On process: workflow YAMLs an explicit tool_timeout (per-agent/role, or --tool-timeout different from the default 60) now raises ValueError — PR #3963. Use process: sequential/hierarchical if you need it enforced. When a tool call exceeds the timeout the executor pool is recycled — the next call gets a fresh worker so a hung tool cannot progressively degrade throughput. See PR #3960.
tool_retry_policyobjectTool retry configuration with exponential backoff. See example below.
planning_toolsarrayTools for planning
planningboolEnable planning
autonomyint (0-10)Autonomy level. Mapped to core preset: 0=off, 1-3=suggest, 4-7=auto_edit, 8-10=full_auto. Also accepts bool / str preset / dict / AutonomyConfig (passed through unchanged).
guardrailsarrayGuardrail functions
streamingboolEnable streaming
streamboolAlias for streaming
approvalboolRequire human approval
skillsarraySkill definitions
runtimestring / dictPer-agent runtime override. Requires framework: praisonai. See Runtime Selection.
cli_backendstring / dictDeprecated — use runtime or models.<name>.runtime instead. Still works through 2.0.0 with DeprecationWarning. Run praisonai doctor fix --execute (or praisonai doctor runtime --fix --execute) to migrate. See Runtime Selection.
reflectionbool/objectReflection configuration

Agent Behaviour Flags

Six per-agent keys map directly onto the matching Agent(...) kwargs. See Agent Behaviour Flags in YAML for the full mapping and Autonomy for the level presets.

yaml
roles:
  writer:
    role: "Writer"
    goal: "Draft and refine content"
    backstory: "Senior technical writer"
    planning: true          # enable planning
    reflection: true        # enable self-reflection
    guardrails: ["safe_output"]
    web: true               # enable web tools
    skills: ["research", "editing"]
    autonomy: 3             # -> suggest preset

The autonomy integer maps onto a core preset before it reaches Agent(autonomy=…):

YAML autonomy: valueCore Agent(autonomy=…) receives
0 / omittedoff — nothing forwarded
1 – 3"suggest"
4 – 7"auto_edit"
8 – 10"full_auto"
bool / str / dict / AutonomyConfigpassed through unchanged
yaml
framework: praisonai
roles:
  coder:
    role: "Autonomous Coder"
    goal: "Complete coding tasks with minimal supervision"
    backstory: "Senior engineer"
    autonomy: 6            # -> "auto_edit" preset in core
    planning: true         # forwarded as-is
    reflection: true       # forwarded as-is
    web: true              # forwarded as-is
    skills: ["python", "testing"]
    guardrails: ["no_prod_writes"]
    tasks:
      write_tests:
        description: "Write pytest tests for {{topic}}"
        expected_output: "A file with pytest test cases"

Deep dives: Planning, Reflection, Guardrails, Web, Skills, Autonomy.

execution: block

An agent’s execution: mapping passes straight through to ExecutionConfig, so budget caps and durable runs can be set from YAML.

yaml
process: workflow
roles:
  researcher:
    role: Researcher
    goal: Produce a clean summary
    backstory: You research topics thoroughly
    execution:
      max_budget: 1.50           # USD cap for the whole run
      on_budget_exceeded: stop   # stop (default) or warn
      durable: true              # journal this turn's tool calls
      journal_path: .praisonai/journal.sqlite
      resume_run_id: run-123     # replay finished tool calls from this run
    tasks:
      t1:
        description: Summarise the topic
        expected_output: One paragraph
KeyTypeDefaultDescription
max_budgetfloatNoneUSD cap for the whole agent run (cumulative, not per iteration). See Agent Max Budget
on_budget_exceeded"stop" \"warn""stop""stop" raises BudgetExceededError; "warn" logs and continues
durableboolfalseJournal tool calls so they can be replayed on resume. See Durable Tool Runs
journal_pathstringSDK defaultWhere to write the durable journal
resume_run_idstringNoneReplay finished tool calls from this run id instead of re-running them. See Run State Journal
max_iter, max_execution_time, max_rpm, preset, enabled——See Execution

Unknown-Field Warnings

Unknown keys at the top level or in agent/role definitions produce warnings:

WARNING: Unknown agent field 'instrutions' in agent 'researcher'. This field will be ignored.
WARNING: Unknown agent field 'xyz_random_field' in agent 'test_agent'. This field will be ignored.

Warnings are non-blocking — the unrecognised field is ignored and the workflow continues. Only use --strict, PRAISONAI_VALIDATE_STRICT=true, or the per-run strict_validation=True override on AgentsGenerator (or cli_config={"strict_validation": True}) to promote them to errors.

Both Sections Covered

The validator inspects both agents: and roles: sections. The warning text changes from agent 'X' to role 'X' accordingly.

Strict Mode

Promote all warnings to errors globally:

bash
export PRAISONAI_VALIDATE_STRICT=true
praisonai start agents.yaml

Strict mode also raises on duplicate agent/task name keys and unknown task→agent references. Without strict mode both are surfaced as loud warnings, and the second entry is preserved with a __dup_i suffix instead of being silently collapsed (as of PR #3176).

Or per-command:

bash
praisonai validate agents.yaml --strict
Run once after editing YAML

Start the workflow once and grep logs for Unknown field to catch all typos at once.

Don't disable the warning

Instead of disabling warnings, fix the typo or add a comment explaining the custom field. The validator helps catch configuration mistakes.

Custom fields are ignored, not preserved

If you intentionally use a non-standard key, the parser will not pass it through to the agent. Only recognized fields are used.


Root-Level Options

All options available at the root level of your YAML file.

Workflow Metadata
FieldTypeDefaultDescription
namestring“Workflow”Workflow identifier
descriptionstring“”Workflow description
inputstring“”Data passed INTO workflow (use {{input}} in steps)
topicstring“”Alias for input (legacy)
frameworkstring“praisonai”Framework: praisonai, crewai, autogen, langgraph, openai_agents, google_adk
processstring“sequential”Process type: sequential, hierarchical, workflow
manager_llmstring–LLM for hierarchical process manager
run_onstringNoneA shared remote sandbox that every step’s shell/file tools bind to — maps directly to the Python AgentFlow(run_on=…) kwarg. One of: docker, e2b, modal, daytona, flyio, tenki, local. Omit for default local execution. Validated at load time — a typo fails immediately with the list of valid names. See Shared Sandbox and Placement.
typestringnullConfiguration type discriminator. Accepted at the top level and ignored by the runner; declared on the schema so it never warns as an unknown field.
deployobjectnullDeployment configuration block. See Deploy.
dependenciesobject / arraynullTask dependency declarations. Honoured on the workflow YAML path (process: workflow); documentary-only on the roles-file loader (see Task Ordering in Roles-File YAML).
Workflow Settings
yaml
workflow:
  planning: true                    # Enable planning mode
  planning_llm: gpt-4o              # LLM for planning
  reasoning: true                   # Enable reasoning mode
  verbose: true                     # Verbose output
  default_llm: gpt-4o-mini          # Default LLM for all agents
  output: verbose                   # Output mode: silent, minimal, normal, verbose, debug
  memory_config:
    provider: chroma
    persist: true
FieldTypeDefaultDescription
planningboolfalseEnable planning mode
planning_llmstring–LLM for planning
reasoningboolfalseEnable reasoning mode
verboseboolfalseVerbose output
default_llmstring“gpt-4o-mini”Default LLM for agents
outputstring“normal”Output mode preset
memory_configobject–Memory configuration
Context Management

Prevent token overflow errors with automatic context compaction.

yaml
# Simple enable
context: true

# Detailed configuration
context:
  auto_compact: true           # Enable auto-compaction
  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
FieldTypeDefaultDescription
auto_compact / enabledboolfalseEnable auto-compaction
compact_threshold / thresholdfloat0.8Trigger threshold (0-1)
strategystring“smart”Compaction strategy
tool_output_max / max_tool_output_tokensint10000Max tokens per tool
Tool Retry Policy

Configure automatic retry for failed tool calls with exponential backoff:

yaml
agents:
  api_researcher:
    role: API Researcher
    instructions: "Research using external APIs"
    tools: [web_search, api_tool]
    tool_retry_policy:
      max_attempts: 4
      retry_on: [timeout, rate_limit, connection_error]
      backoff_factor: 2.0
      initial_delay_ms: 1000
      jitter: true
FieldTypeDefaultDescription
max_attemptsint3Total attempts including the first try
retry_onarray[“timeout”, “rate_limit”, “connection_error”]Error types that trigger retry
backoff_factorfloat2.0Multiplier for delay between attempts
initial_delay_msint1000Initial delay before first retry (ms)
jitterboolfalseAdd randomized jitter to delays

For detailed configuration options, see Tool Retry Policy.

Variables
yaml
variables:
  topic: AI trends
  max_results: 5
  categories:
    - Machine Learning
    - NLP
    - Computer Vision

Use variables in steps with {{variable_name}} syntax. Substitutions are applied in this order:

PlaceholderResolves toNotes
{{your_variable}}Value from variables: or an earlier step’s output_variableSubstituted first
{{previous_output}}Output of the immediately previous stepAuto-appended as "Context from previous step:" if omitted and a previous output exists
{{step_name_output}}Output of a specific named step (set via output_variable)Resolved in the same pass as {{your_variable}}
{{input}}Value of the top-level input: fieldSubstituted last; available in every step
{{item}}Current loop itemSet by loop_over steps
{{item.field}}Field in loop itemSet by loop_over steps

For date/time/UUID placeholders ({{today}}, {{now}}, {{uuid}}), see Dynamic Variables — that is a separate mechanism.

Runtime Selection

Model-scoped runtime configuration. Requires framework: praisonai. See Runtime Selection.

yaml
providers:
  anthropic:
    runtime_default: claude-code
  openai:
    runtime_default: codex-cli

models:
  claude-3-sonnet:
    runtime: claude-code
  gpt-4o:
    runtime: praisonai
FieldTypeDescription
providers.<name>.runtime_defaultstringProvider-wide default runtime for all models from that provider
models.<name>.runtimestringPer-model runtime override (wins over provider default)
runtime (agent-level)string / dictPer-agent override (wins over model and provider)
Custom Models

Define custom models for model routing.

yaml
models:
  cheap-fast:
    provider: openai
    complexity: [simple]
    cost_per_1k: 0.0001
    capabilities: [text]
    context_window: 16000

  premium:
    provider: anthropic
    complexity: [complex, very_complex]
    cost_per_1k: 0.015
    capabilities: [text, vision, function-calling]
    context_window: 200000
    supports_tools: true
    strengths: [reasoning, analysis]
FieldRequiredDescription
provider✅openai, anthropic, google, openrouter
complexity✅List: simple, moderate, complex, very_complex
cost_per_1k✅Cost per 1,000 tokens in USD
capabilities❌List: text, vision, function-calling
context_window❌Max context window in tokens
supports_tools❌Supports tool/function calling
strengths❌List: reasoning, code-generation, etc.
Callbacks
yaml
callbacks:
  on_workflow_start: log_start
  on_step_start: log_step_start
  on_step_complete: log_step_complete
  on_step_error: handle_error
  on_workflow_complete: log_complete

On the workflow.yaml / YAMLWorkflowParser path, only these five lifecycle names reach the Workflow engine via WorkflowHooksConfig: on_workflow_start, on_workflow_complete, on_step_start, on_step_complete, on_step_error. Each referenced func_name must be registered on the parser before parse_file(...):

python
from praisonaiagents.workflows import YAMLWorkflowParser

def log_start(*args, **kwargs):
    print("workflow started")

parser = YAMLWorkflowParser()
parser.register_callback("log_start", log_start)
workflow = parser.parse_file("workflow.yaml")

An unregistered name logs a warning and leaves the workflow with its default (no hooks). See YAML Callbacks.


Agent Options

All options available for agent definitions.

Diagram

Configuration

Core Fields

Agent Definition

👤 Agent

role

goal

instructions

llm

tools

memory

Core Fields
FieldRequiredDefaultDescription
role✅–Agent’s job title
name❌Agent IDDisplay name
goal❌“Complete the task”Agent’s objective
instructions❌GenericDirect behavior instructions (simple agents)
backstory❌–Personality/background context (advanced)
LLM Configuration
FieldTypeDefaultDescription
llmstring \dictgpt-4o-miniModel to use
function_calling_llmstring \dictSame as llmModel for tool calls
reflect_llmstring \dictSame as llmModel for self-reflection
system_templatestring–Custom system prompt
prompt_templatestring–Custom prompt template
response_templatestring–Custom response template

Both llm and function_calling_llm accept a model name as a string, or a dict when you also need to override base_url / api_key.

Frameworkllmfunction_calling_llm
praisonai✅✅
crewai✅✅
autogen, autogen_v2, autogen_v4, ag2✅⚠️ Not supported — logs an unsupported-field warning

String form (simplest)

yaml
agents:
  writer:
    role: Writer
    llm: gpt-4o-mini
    function_calling_llm: gpt-4o-mini

Dict form (when overriding endpoint / key)

yaml
agents:
  writer:
    role: Writer
    llm:
      model: gpt-4o-mini
      base_url: https://my-proxy.example.com/v1
      api_key: sk-...
    function_calling_llm:
      model: gpt-4o-mini
Rate Limiting & Execution
FieldDefaultDescription
max_rpmUnlimitedMax requests per minute — auto-builds a RateLimiter when set; max_rpm <= 0 raises ValueError
max_execution_time300Timeout in seconds
max_iter3Maximum iterations
min_reflect0Minimum reflection iterations
max_reflect3Maximum reflection iterations
cachetrueEnable response caching
Advanced Features
FieldDefaultDescription
planningfalseEnable agent-level planning
reasoningfalseEnable reasoning mode
allow_delegationfalseAllow task delegation
verbosefalseVerbose output
tools[]List of tool names
webfalseEnable web search capabilities
web_fetchfalseEnable web content fetching
handoff–Handoff configuration (see below)
Handoff Configuration

Configure agent handoff with nested options:

yaml
agents:
  coordinator:
    role: Coordinator
    handoff:
      to: [writer, reviewer]      # List of target agents
      policy: summary             # Handoff policy: full, summary, none, last_n
      timeout: 60                 # Handoff timeout in seconds
      max_depth: 5                # Maximum handoff chain depth
      max_concurrent: 3           # Maximum concurrent handoffs
      detect_cycles: true         # Enable cycle detection
FieldDefaultDescription
to[]List of agent names to handoff to
policy“full”Handoff policy: full, summary, none, last_n
timeout30Timeout for handoff in seconds
max_depth10Maximum depth of handoff chain
max_concurrent5Maximum concurrent handoffs
detect_cyclesfalseEnable handoff cycle detection
Specialized Agent Types

Use the agent: field to specify specialized agent types:

yaml
agents:
  image_creator:
    agent: ImageAgent          # Specialized type
    role: Image Generator
    llm: dall-e-3
    style: natural             # optional — omit to let the provider pick

  narrator:
    agent: AudioAgent
    role: Audio Narrator
    llm: tts-1
    voice: alloy

  video_maker:
    agent: VideoAgent
    role: Video Creator
    llm: openai/sora-2

  document_reader:
    agent: OCRAgent
    role: Document Reader
    llm: mistral/mistral-ocr-latest

  researcher:
    agent: DeepResearchAgent
    role: Deep Researcher
    llm: o3-deep-research
Agent TypePurposeKey Options
ImageAgentImage generationstyle, llm (dall-e-3)
AudioAgentTTS/STTvoice, audio config
VideoAgentVideo generationvideo config
OCRAgentText extractionocr config
DeepResearchAgentAutomated researchinstructions

For ImageAgent, style: is optional — when omitted, no default is injected and the provider picks one.


Step Options

All options available for step definitions.

Diagram

Execution

Step Types

Basic Step

Parallel Step

Route Step

Loop Step

Repeat Step

Include Step

⚡ Execute

Basic Step Fields
FieldRequiredDefaultDescription
agent✅*–Agent to execute (*not needed for patterns)
action❌{{input}}What the step does
~~description~~❌–Deprecated – use action
name❌Auto-generatedStep identifier
expected_output❌–Description of expected output
Output Options
FieldDescription
output_fileSave output to file path
create_directoryCreate output directory if needed (set automatically for framework: praisonai tasks whose output_file has a parent directory)
output_jsonJSON schema for structured output
output_pydanticPydantic model name from tools.py
output_variableStore output in named variable
yaml
steps:
  - agent: researcher
    action: "Find topics"
    output_json:
      type: array
      items:
        type: object
        properties:
          title: { type: string }
          url: { type: string }
    output_variable: topics
Context & Dependencies
FieldDescription
contextList of dependent step names
yaml
steps:
  - name: research_step
    agent: researcher
    action: "Research {{input}}"

  - name: writing_step
    agent: writer
    action: "Write based on: {{previous_output}}"
    context:
      - research_step    # Explicit dependency
Execution Control
FieldDefaultDescription
async_executionfalseRun asynchronously
max_retries3Maximum retry attempts
guardrail–Guardrail function name
callback–Callback function name

Workflow Patterns

Advanced workflow patterns available in both agents.yaml and workflow.yaml.

Parallel

yaml
steps:
  - name: parallel_research
    parallel:
      - agent: market_analyst
        action: "Research market trends"
      - agent: tech_analyst
        action: "Research technology"

  - agent: aggregator
    action: "Combine findings: {{previous_output}}"

Route

yaml
steps:
  - agent: classifier
    action: "Classify: {{input}}"

  - name: routing
    route:
      technical: [tech_expert]
      creative: [creative_expert]
      default: [general_agent]

Loop

yaml
variables:
  topics:
    - Machine Learning
    - NLP
    - Computer Vision

steps:
  - agent: researcher
    action: "Research {{item}}"
    loop:
      over: topics
      parallel: true      # Optional: run in parallel
      max_workers: 4      # Optional: limit workers

Multi-Step Loop

yaml
steps:
  - loop:
      over: topics
      parallel: true
    steps:
      - agent: researcher
        action: "Research {{item}}"
      - agent: writer
        action: "Write about: {{previous_output}}"
      - agent: publisher
        action: "Publish: {{previous_output}}"

Repeat

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

Include

yaml
steps:
  - include: ai-topic-gatherer

  - include:
      recipe: wordpress-publisher
      input: "{{previous_output}}"

  - agent: writer
    action: "Summarize: {{previous_output}}"

Loop Options

FieldRequiredDefaultDescription
over✅*–Variable name to iterate
from_csv❌–CSV file path to iterate
from_file❌–File path to iterate lines
var_name❌“item”Variable name for current item
parallel❌falseExecute iterations in parallel
max_workers❌–Limit parallel workers
output_variable❌–Store all outputs in variable

Repeat Options

FieldRequiredDefaultDescription
until✅–Condition string to match in output
max_iterations❌5Maximum iterations

Include Options

FieldRequiredDefaultDescription
recipe✅–Recipe name or path
input❌{{previous_output}}Input for included recipe

Feature Compatibility Matrix

What works where:

Featureagents.yamlworkflow.yamlNotes
Agent Definition✅✅Use agents: (canonical) or roles:
Steps/Tasks✅✅Use steps: (canonical)
Workflow Patterns✅✅parallel, route, loop, repeat
Include Recipes✅✅include: in steps
Variables✅✅variables: section
Context Management✅✅context: section
Planning Mode✅✅workflow.planning: true
Reasoning Mode✅✅workflow.reasoning: true
Memory Config✅✅workflow.memory_config:
Custom Models✅✅models: section
Callbacks✅✅callbacks: section
Specialized Agents✅✅agent: ImageAgent, etc.
Handoff Configuration✅✅handoff: in agent definition
Web Search✅✅web: true in agent definition
Web Content Fetching✅✅web_fetch: true in agent definition
Structured Output✅✅output_json, output_pydantic

What’s NOT Possible

LimitationWorkaround
Nested loopsUse multi-step loop with sequential steps
Conditional branching mid-stepUse route: pattern instead
Dynamic agent creationPre-define all agents in agents: section
Cross-workflow stateUse include: with explicit input passing
Real-time streaming in loopsStreaming works per-step, not across loop

Migration Guide

From agents.yaml to workflow.yaml

  1. Rename container

    roles: → agents:

  2. Rename agent fields

    backstory: → instructions:

  3. Extract tasks to steps

    Move nested tasks: to top-level steps:

  4. Rename step fields

    description: → action:

  5. Update input reference

    topic: → input: (optional but recommended)

Before (agents.yaml style)
framework: praisonai
topic: "Research AI"

roles:
  researcher:
    role: Analyst
    backstory: "Expert researcher"
    goal: Research
    tasks:
      research_task:
        description: "Research {{topic}}"
After (workflow.yaml style)
name: Research Workflow
input: "Research AI"

agents:
  researcher:
    role: Analyst
    instructions: "Expert researcher"
    goal: Research

steps:
  - agent: researcher
    action: "Research {{input}}"

Validation

Validate your YAML configuration before running:

bash
praisonai validate agents.yaml

Output shows:

  • ✅ Valid configuration
  • ⚠️ Non-blocking warnings (unknown fields, optional tool deps)
  • ❌ Errors that would abort execution

Scan an entire directory:

bash
praisonai validate check . --strict --json

See the Validate CLI page for all flags, JSON output format, and CI integration examples.

praisonai workflow validate is the workflow-specific variant and remains available for backwards compatibility.


Best Practices

Use Canonical Names

agents, instructions, action, steps, input

Enable Context Management

context: true for tool-heavy workflows

Define Expected Output

Always specify expected_output for clarity

Use Variables

Centralize reusable values in variables:

Related