Skip to main content
Multi-Agent Hooks let you run custom code when tasks start, complete, or when you need custom completion detection in multi-agent workflows.
The user registers hooks; the workflow fires them as each task starts and completes.
Multi-agent lifecycle hooks fire on both sync (team.start()) and async (team.astart()) workflows, and callbacks may be either regular functions or async def coroutines. See Async and Sync Callbacks below.

Quick Start

1

Task Lifecycle Logging

Log every task transition with on_task_start and on_task_complete:
2

Async Workflow with async def Hooks

Run the team with astart() and use async def callbacks to await I/O directly:
3

Custom Completion Checker

Override the default completion logic with your own validation:

How It Works

Async and Sync Callbacks

MultiAgentHooksConfig accepts either regular functions or async def coroutines for on_task_start and on_task_complete.
  • In sync workflows (team.start()), only sync callables are meaningful — an async def here would return an un-awaited coroutine.
  • In async workflows (team.astart() / arun_task()), the framework detects the callable type and does the right thing:
    • async def callbacks are awaited inline.
    • Sync callbacks are offloaded to the default executor via loop.run_in_executor(None, ...), so a blocking hook can’t stall the event loop.
  • Exceptions raised by either callback are logged (logger.error) and swallowed — they never abort the task.

Global Variables Propagation

Pass variables= once at the team level and every task substitutes them into its description at runtime:
Values passed to variables= are shallow-copied into task.variables before each task runs (unless the task defines its own variables), then substituted into task.description. The shallow copy means a task mutating its own variables no longer leaks back into the team-level dict, so parallel tasks in a process="workflow" team with async_execution=True on each task don’t stomp on each other.
process accepts "sequential", "hierarchical", or "workflow". Passing any other value (including "parallel") raises ValueError at PraisonAIAgents(...) construction. To fan out tasks in parallel, keep process="workflow" and set async_execution=True on each Task.

Configuration Options

MultiAgentHooksConfig SDK Reference

Full parameter reference for MultiAgentHooksConfig

Common Patterns

Pattern 1 — Logging workflow progress

Pattern 2 — Quality gate with retry logic

Pattern 3 — Async I/O in a completion hook


Best Practices

Callbacks are invoked on the orchestrator’s task-completion path. In sync workflows, an expensive hook blocks the next task. In async workflows, sync hooks are offloaded to a thread executor and async def hooks are awaited, so blocking work is safer — but a slow hook still increases end-to-end task latency. Prefer async def for I/O-bound work (DB writes, HTTP notifications) and keep CPU-bound work off the hook path entirely.
When you run the team with astart(), use async def callbacks for on_task_start / on_task_complete so you can await I/O directly. Sync callbacks still work — the framework offloads them to the default executor — but writing them as coroutines is clearer and avoids an unnecessary executor hop.
The completion_checker is ideal for enforcing output quality requirements — minimum length, required fields, absence of error text. Return False to trigger a retry and True to accept the result.
Hook callbacks receive task references. Mutating task properties during execution can cause unexpected behavior. Use hooks for observation and notification, not for changing task state.

Async Agents

Run multi-agent workflows with astart()

Hooks

Single-agent lifecycle hooks

Callbacks

Agent callback system

Multi-Agent Execution

Configure iteration and retry limits