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
- 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") - Run the YAML workflow
bash praisonai start agents.yamlThe user maintains YAML config; the agent loads it and executes the requested workflow.
How It Works
Quick Comparison
agents.yaml Style
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)
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 |
|---|---|---|
agents | roles | Define agent personas |
instructions | backstory | Agent behavior/persona |
action | description | What the step does |
steps | tasks (nested in roles) | Define work items |
name | – | Workflow identifier |
input | topic | Data 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)
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)
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:
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:)
framework: praisonai
roles:
writer:
role: "Writer"
goal: "Draft clear content"
tasks:
draft:
description: "Draft an intro for {{topic}}"Shorthand (agents:) — same result
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 tobackstory:during promotion (existing behaviour, unchanged).
Precedence on conflict — the canonical roles: entry wins and the agents: duplicate is ignored:
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.
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.
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_taskresearch_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
export OPENAI_API_KEY=sk-...
praisonai agents.yamlPython
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.
- 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. - Run workflow and see warning
bash praisonai start agents.yamlOutput (unknown field → warning, workflow still runs):
WARNING: Unknown agent field 'instrutions' in agent 'researcher'. This field will be ignored. - Validate before running
bash praisonai validate agents.yamlCatch all errors upfront without running the workflow.
Fail-Fast Errors
These conditions abort the run immediately with an aggregated error message.
Missing required field:
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):
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:
agents:
researcher:
role: Research Analyst
goal: Research topics
backstory: Expert researcher.
tools:
- nonexistent_toolResult:
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:
| Field | Type | Purpose | |
|---|---|---|---|
role | string | Agent’s job title | |
goal | string | Agent’s objective | |
instructions | string | Behavior instructions | |
backstory | string | Personality/background context | |
tools | array | List of tool names | |
tasks | object | Nested task definitions (legacy) | |
llm | string \ | dict | Model to use |
function_calling_llm | string \ | dict | Model for tool calls |
allow_delegation | bool | Allow task delegation | |
max_iter | int | Maximum iterations | |
max_rpm | int | Max requests per minute — auto-builds a RateLimiter when set; max_rpm <= 0 raises ValueError | |
max_execution_time | int | Timeout in seconds | |
execution | object | Agent-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 | |
verbose | bool | Verbose output | |
cache | bool | Enable response caching | |
system_template | string | Custom system prompt | |
prompt_template | string | Custom prompt template | |
response_template | string | Custom response template | |
tool_timeout | int | Per-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_policy | object | Tool retry configuration with exponential backoff. See example below. | |
planning_tools | array | Tools for planning | |
planning | bool | Enable planning | |
autonomy | int (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). | |
guardrails | array | Guardrail functions | |
streaming | bool | Enable streaming | |
stream | bool | Alias for streaming | |
approval | bool | Require human approval | |
skills | array | Skill definitions | |
runtime | string / dict | Per-agent runtime override. Requires framework: praisonai. See Runtime Selection. | |
cli_backend | string / dict | Deprecated — 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. | |
reflection | bool/object | Reflection 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.
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 presetThe autonomy integer maps onto a core preset before it reaches Agent(autonomy=…):
YAML autonomy: value | Core Agent(autonomy=…) receives |
|---|---|
0 / omitted | off — nothing forwarded |
1 – 3 | "suggest" |
4 – 7 | "auto_edit" |
8 – 10 | "full_auto" |
bool / str / dict / AutonomyConfig | passed through unchanged |
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.
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| Key | Type | Default | Description | |
|---|---|---|---|---|
max_budget | float | None | USD 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 |
durable | bool | false | Journal tool calls so they can be replayed on resume. See Durable Tool Runs | |
journal_path | string | SDK default | Where to write the durable journal | |
resume_run_id | string | None | Replay 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:
export PRAISONAI_VALIDATE_STRICT=true
praisonai start agents.yamlStrict 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:
praisonai validate agents.yaml --strictRun 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
| Field | Type | Default | Description |
|---|---|---|---|
name | string | “Workflow” | Workflow identifier |
description | string | “” | Workflow description |
input | string | “” | Data passed INTO workflow (use {{input}} in steps) |
topic | string | “” | Alias for input (legacy) |
framework | string | “praisonai” | Framework: praisonai, crewai, autogen, langgraph, openai_agents, google_adk |
process | string | “sequential” | Process type: sequential, hierarchical, workflow |
manager_llm | string | – | LLM for hierarchical process manager |
run_on | string | None | A 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. |
type | string | null | Configuration type discriminator. Accepted at the top level and ignored by the runner; declared on the schema so it never warns as an unknown field. |
deploy | object | null | Deployment configuration block. See Deploy. |
dependencies | object / array | null | Task 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
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| Field | Type | Default | Description |
|---|---|---|---|
planning | bool | false | Enable planning mode |
planning_llm | string | – | LLM for planning |
reasoning | bool | false | Enable reasoning mode |
verbose | bool | false | Verbose output |
default_llm | string | “gpt-4o-mini” | Default LLM for agents |
output | string | “normal” | Output mode preset |
memory_config | object | – | Memory configuration |
Context Management
Prevent token overflow errors with automatic context compaction.
# 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| Field | Type | Default | Description |
|---|---|---|---|
auto_compact / enabled | bool | false | Enable auto-compaction |
compact_threshold / threshold | float | 0.8 | Trigger threshold (0-1) |
strategy | string | “smart” | Compaction strategy |
tool_output_max / max_tool_output_tokens | int | 10000 | Max tokens per tool |
Tool Retry Policy
Configure automatic retry for failed tool calls with exponential backoff:
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| Field | Type | Default | Description |
|---|---|---|---|
max_attempts | int | 3 | Total attempts including the first try |
retry_on | array | [“timeout”, “rate_limit”, “connection_error”] | Error types that trigger retry |
backoff_factor | float | 2.0 | Multiplier for delay between attempts |
initial_delay_ms | int | 1000 | Initial delay before first retry (ms) |
jitter | bool | false | Add randomized jitter to delays |
For detailed configuration options, see Tool Retry Policy.
Variables
variables:
topic: AI trends
max_results: 5
categories:
- Machine Learning
- NLP
- Computer VisionUse variables in steps with {{variable_name}} syntax. Substitutions are applied in this order:
| Placeholder | Resolves to | Notes |
|---|---|---|
{{your_variable}} | Value from variables: or an earlier step’s output_variable | Substituted first |
{{previous_output}} | Output of the immediately previous step | Auto-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: field | Substituted last; available in every step |
{{item}} | Current loop item | Set by loop_over steps |
{{item.field}} | Field in loop item | Set 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.
providers:
anthropic:
runtime_default: claude-code
openai:
runtime_default: codex-cli
models:
claude-3-sonnet:
runtime: claude-code
gpt-4o:
runtime: praisonai| Field | Type | Description |
|---|---|---|
providers.<name>.runtime_default | string | Provider-wide default runtime for all models from that provider |
models.<name>.runtime | string | Per-model runtime override (wins over provider default) |
runtime (agent-level) | string / dict | Per-agent override (wins over model and provider) |
Custom Models
Define custom models for model routing.
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]| Field | Required | Description |
|---|---|---|
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
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_completeOn 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(...):
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.
Core Fields
| Field | Required | Default | Description |
|---|---|---|---|
role | ✅ | – | Agent’s job title |
name | ❌ | Agent ID | Display name |
goal | ❌ | “Complete the task” | Agent’s objective |
instructions | ❌ | Generic | Direct behavior instructions (simple agents) |
backstory | ❌ | – | Personality/background context (advanced) |
LLM Configuration
| Field | Type | Default | Description | |
|---|---|---|---|---|
llm | string \ | dict | gpt-4o-mini | Model to use |
function_calling_llm | string \ | dict | Same as llm | Model for tool calls |
reflect_llm | string \ | dict | Same as llm | Model for self-reflection |
system_template | string | – | Custom system prompt | |
prompt_template | string | – | Custom prompt template | |
response_template | string | – | 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.
| Framework | llm | function_calling_llm |
|---|---|---|
praisonai | ✅ | ✅ |
crewai | ✅ | ✅ |
autogen, autogen_v2, autogen_v4, ag2 | ✅ | ⚠️ Not supported — logs an unsupported-field warning |
String form (simplest)
agents:
writer:
role: Writer
llm: gpt-4o-mini
function_calling_llm: gpt-4o-miniDict form (when overriding endpoint / key)
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-miniRate Limiting & Execution
| Field | Default | Description |
|---|---|---|
max_rpm | Unlimited | Max requests per minute — auto-builds a RateLimiter when set; max_rpm <= 0 raises ValueError |
max_execution_time | 300 | Timeout in seconds |
max_iter | 3 | Maximum iterations |
min_reflect | 0 | Minimum reflection iterations |
max_reflect | 3 | Maximum reflection iterations |
cache | true | Enable response caching |
Advanced Features
| Field | Default | Description |
|---|---|---|
planning | false | Enable agent-level planning |
reasoning | false | Enable reasoning mode |
allow_delegation | false | Allow task delegation |
verbose | false | Verbose output |
tools | [] | List of tool names |
web | false | Enable web search capabilities |
web_fetch | false | Enable web content fetching |
handoff | – | Handoff configuration (see below) |
Handoff Configuration
Configure agent handoff with nested options:
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| Field | Default | Description |
|---|---|---|
to | [] | List of agent names to handoff to |
policy | “full” | Handoff policy: full, summary, none, last_n |
timeout | 30 | Timeout for handoff in seconds |
max_depth | 10 | Maximum depth of handoff chain |
max_concurrent | 5 | Maximum concurrent handoffs |
detect_cycles | false | Enable handoff cycle detection |
Specialized Agent Types
Use the agent: field to specify specialized agent types:
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 Type | Purpose | Key Options |
|---|---|---|
ImageAgent | Image generation | style, llm (dall-e-3) |
AudioAgent | TTS/STT | voice, audio config |
VideoAgent | Video generation | video config |
OCRAgent | Text extraction | ocr config |
DeepResearchAgent | Automated research | instructions |
For ImageAgent, style: is optional — when omitted, no default is injected and the provider picks one.
Step Options
All options available for step definitions.
Basic Step Fields
| Field | Required | Default | Description |
|---|---|---|---|
agent | ✅* | – | Agent to execute (*not needed for patterns) |
action | ❌ | {{input}} | What the step does |
~~description~~ | ❌ | – | Deprecated – use action |
name | ❌ | Auto-generated | Step identifier |
expected_output | ❌ | – | Description of expected output |
Output Options
| Field | Description |
|---|---|
output_file | Save output to file path |
create_directory | Create output directory if needed (set automatically for framework: praisonai tasks whose output_file has a parent directory) |
output_json | JSON schema for structured output |
output_pydantic | Pydantic model name from tools.py |
output_variable | Store output in named variable |
steps:
- agent: researcher
action: "Find topics"
output_json:
type: array
items:
type: object
properties:
title: { type: string }
url: { type: string }
output_variable: topicsContext & Dependencies
| Field | Description |
|---|---|
context | List of dependent step names |
steps:
- name: research_step
agent: researcher
action: "Research {{input}}"
- name: writing_step
agent: writer
action: "Write based on: {{previous_output}}"
context:
- research_step # Explicit dependencyExecution Control
| Field | Default | Description |
|---|---|---|
async_execution | false | Run asynchronously |
max_retries | 3 | Maximum retry attempts |
guardrail | – | Guardrail function name |
callback | – | Callback function name |
Workflow Patterns
Advanced workflow patterns available in both agents.yaml and workflow.yaml.
Execute multiple agents concurrently
RouteClassify and route to specialized agents
LoopIterate over a list of items
RepeatRepeat until condition is met
IncludeInclude modular recipes
Parallel
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
steps:
- agent: classifier
action: "Classify: {{input}}"
- name: routing
route:
technical: [tech_expert]
creative: [creative_expert]
default: [general_agent]Loop
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 workersMulti-Step Loop
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
steps:
- agent: writer
action: "Write article about {{topic}}"
repeat:
until: "approved"
max_iterations: 3Include
steps:
- include: ai-topic-gatherer
- include:
recipe: wordpress-publisher
input: "{{previous_output}}"
- agent: writer
action: "Summarize: {{previous_output}}"Loop Options
| Field | Required | Default | Description |
|---|---|---|---|
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 | ❌ | false | Execute iterations in parallel |
max_workers | ❌ | – | Limit parallel workers |
output_variable | ❌ | – | Store all outputs in variable |
Repeat Options
| Field | Required | Default | Description |
|---|---|---|---|
until | ✅ | – | Condition string to match in output |
max_iterations | ❌ | 5 | Maximum iterations |
Include Options
| Field | Required | Default | Description |
|---|---|---|---|
recipe | ✅ | – | Recipe name or path |
input | ❌ | {{previous_output}} | Input for included recipe |
Feature Compatibility Matrix
What works where:
| Feature | agents.yaml | workflow.yaml | Notes |
|---|---|---|---|
| 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
| Limitation | Workaround |
|---|---|
| Nested loops | Use multi-step loop with sequential steps |
| Conditional branching mid-step | Use route: pattern instead |
| Dynamic agent creation | Pre-define all agents in agents: section |
| Cross-workflow state | Use include: with explicit input passing |
| Real-time streaming in loops | Streaming works per-step, not across loop |
Migration Guide
From agents.yaml to workflow.yaml
- Rename container
roles:→agents: - Rename agent fields
backstory:→instructions: - Extract tasks to steps
Move nested
tasks:to top-levelsteps: - Rename step fields
description:→action: - Update input reference
topic:→input:(optional but recommended)
framework: praisonai
topic: "Research AI"
roles:
researcher:
role: Analyst
backstory: "Expert researcher"
goal: Research
tasks:
research_task:
description: "Research {{topic}}"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:
praisonai validate agents.yamlOutput shows:
- ✅ Valid configuration
- ⚠️ Non-blocking warnings (unknown fields, optional tool deps)
- ❌ Errors that would abort execution
Scan an entire directory:
praisonai validate check . --strict --jsonSee 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: