Subagent Delegation

Spawn and manage subagents with scoped permissions and concurrency control

Subagent delegation lets a parent agent spawn specialised workers with scoped permissions, timeouts, and parallel execution.

python
from praisonaiagents import Agent
from praisonaiagents.tools.subagent_tool import create_subagent_tool

coordinator = Agent(
    name="Coordinator",
    instructions="Delegate read-only exploration to subagents.",
    tools=[create_subagent_tool(
        default_permission_mode="plan",
        allowed_agents=["explorer"],
    )],
)

coordinator.start("Find where authentication is implemented")

The user asks the coordinator; delegated subagents explore with scoped permissions.

Diagram

Subagent Delegation

🤖 Parent Agent

📋 Delegate

🔍 Explorer

💻 Coder

✅ Reviewer

📦 Aggregate Results

Quick Start

  1. Subagent Tool on an Agent

    Attach create_subagent_tool so the parent can spawn workers:

    python
    from praisonaiagents import Agent
    from praisonaiagents.tools.subagent_tool import create_subagent_tool
    
    agent = Agent(
        name="Lead",
        instructions="Delegate exploration tasks to subagents.",
        tools=[create_subagent_tool(default_permission_mode="plan")],
    )
    
    agent.start("Explore the auth module read-only")
  2. Programmatic Handoffs

    For direct async control, fan work out to focused agents with parallel_handoffs:

    python
    from praisonaiagents import Agent, parallel_handoffs
    import asyncio
    
    lead = Agent(name="Lead", instructions="Coordinate exploration.")
    explorer = Agent(name="Explorer", instructions="Investigate the codebase read-only.")
    
    async def run():
        results = await parallel_handoffs(
            source=lead,
            targets=[
                (explorer, "Find authentication-related files"),
                (explorer, "Find database models"),
            ],
            max_concurrent=3,
        )
        for r in results:
            print(r.response if r.success else r.error)
    
    asyncio.run(run())

    For a single target, use lead.handoff_to_async(explorer, "Find auth files").


How It Works

Diagram
SubagentParent AgentUserSubagentParent AgentUser“Find where auth is implemented”delegate(explorer, objective, scoped perms)Explore (read-only, timeout-bound)Result or errorAggregated answer
PhaseWhat happens
1. DelegateThe parent spawns a subagent with a scoped permission mode
2. ExecuteThe subagent runs within its timeout and step limits
3. AggregateResults flow back to the parent for a final answer

Named Delegation from the CLI (--subagents)

A running agent can delegate sub-tasks to your own named agents in .praisonai/agents/*.md — by name, mid-run, with no Python. Each delegated agent runs the sub-task under its own model, tools, and permissions.

Diagram

name matches

unknown name

🤖 Main Agent

🔁 Resolver

👤 Named Sub-Agent
own model + tools

⚙️ Generic Spawn

✅ Result

  1. Create two named agents

    Add a description: in each file’s frontmatter so the model knows what the agent is for. .praisonai/agents/researcher.md:

    markdown
    ---
    description: Researches a topic and gathers sources
    model: gpt-4o-mini
    ---
    You are a focused researcher. Gather accurate, sourced findings.

    .praisonai/agents/writer.md:

    markdown
    ---
    description: Writes a concise summary from research notes
    model: gpt-4o
    ---
    You turn research notes into a clear, concise summary.
  2. Allow-list them at run time
    bash
    praisonai run "Research X and write a summary" --subagents researcher,writer

    The main agent can now call spawn_subagent(agent_name="researcher", ...) and the resolver runs your researcher agent under its own definition.

Two ways to expose a named agent

Allow-list flag (–subagents)

Opt any discovered agent in from the CLI without editing it:

bash
praisonai run "<task>" --subagents researcher,writer

The allow-list takes precedence over the frontmatter marker.

Frontmatter marker (mode: subagent)

Mark an agent as delegatable in its own file — no flag needed:

markdown
---
mode: subagent
description: Reviews a diff for security issues
---
You review diffs and report security concerns only.

mode: subagent is a marker only — it is not a permission mode and does not restrict the agent.

How resolution works

Diagram
Named Sub-AgentResolverMain AgentNamed Sub-AgentResolverMain Agentalt[name resolves][name unknown]spawn_subagent(agent_name=”researcher”)run under its own model/tools/permissionsresultfall through to generic spawn

When the target name is unknown, the resolver returns nothing and the tool falls through to the existing generic-spawn behaviour — so a typo never breaks the run.

--subagents vs mode: subagent

Diagram

Pick agents per run,
no file edits

Always delegatable,
declared in the file

How do I want to expose
a named agent?

–subagents a,b,c

mode: subagent
in frontmatter


Built-in Agent Profiles

AgentModeDescription
generalPrimaryGeneral-purpose coding assistant
coderAllFocused code implementation
plannerSubagentTask planning and decomposition
reviewerSubagentCode review and quality
explorerSubagentRead-only codebase investigation
debuggerSubagentDebugging and troubleshooting
python
from praisonaiagents.agents.profiles import list_profiles, get_profile

profiles = list_profiles()
explorer = get_profile("explorer")
print(explorer.description)

Parallel Delegation

Fan work out to multiple agents at once with parallel_handoffs — each (agent, prompt) tuple runs concurrently:

python
from praisonaiagents import Agent, parallel_handoffs

lead = Agent(name="Lead", instructions="Coordinate exploration.")
explorer = Agent(name="Explorer", instructions="Investigate the codebase.")

results = await parallel_handoffs(
    source=lead,
    targets=[
        (explorer, "Find authentication files"),
        (explorer, "Find database models"),
        (explorer, "Find API endpoints"),
    ],
    max_concurrent=3,
)

Route each prompt to a different specialist by passing different agents:

python
reviewer = Agent(name="Reviewer", instructions="Review security.")

results = await parallel_handoffs(
    source=lead,
    targets=[
        (explorer, "Find auth files"),
        (reviewer, "Review security of auth.py"),
    ],
)

Configuration Options

Parallel fan-out is tuned with HandoffConfig. The knobs you reach for most:

OptionTypeDefaultDescription
max_concurrentint5Max handoffs running at once
timeout_secondsfloat300.0Timeout per handoff
allow_parallelboolFalseMust be True to run via parallel_handoffs when passing a config
max_depthint10Maximum handoff chain depth
context_policyContextPolicySUMMARYHow much history each target sees
python
from praisonaiagents import parallel_handoffs, HandoffConfig

config = HandoffConfig(
    max_concurrent=3,
    timeout_seconds=300.0,
    allow_parallel=True,
)

results = await parallel_handoffs(source=lead, targets=targets, config=config)

Model and Permission Modes

Diagram

Subagent Model Selection

🤖 Parent Agent

Spawn Subagent

📝 default_llm

🔄 Per-call llm override

🧠 Subagent with Model

ModeDescription
defaultStandard permission checking
accept_editsAuto-accept file edits
dont_askAuto-deny prompts
bypass_permissionsSkip all checks (dangerous)
planRead-only exploration mode

See Subagent Tool for create_subagent_tool parameters and background mode.


Cancellation

A single async handoff is a coroutine — wrap it in your own asyncio.Task and .cancel() it to stop it early:

python
import asyncio
from praisonaiagents import Agent

lead = Agent(name="Lead", instructions="Coordinate work.")
explorer = Agent(name="Explorer", instructions="Investigate.")

task = asyncio.create_task(lead.handoff_to_async(explorer, "Scan the whole repo"))
# ...later, if it runs too long:
task.cancel()

For fan-out, parallel_handoffs bounds each target with timeout_seconds from HandoffConfig; cancel the outer task to stop the whole batch.


Best Practices

Match agent profiles to the task

Use explorer for read-only scans, coder for implementation, and reviewer for quality checks.

Set timeouts on long tasks

Prevent runaway handoffs with HandoffConfig(timeout_seconds=...).

Limit concurrency

Keep max_concurrent low to avoid overwhelming APIs or local resources.

Prefer plan mode for exploration

Use permission_mode="plan" when subagents should not modify files.


Delegating to Your Named Agents

Beyond the built-in profiles, a running agent can delegate to your own named agents in .praisonai/agents/*.md — picked by name, each running under its own model, tools, and permissions. Mark an agent with mode: subagent or opt agents in per run with praisonai run --subagents a,b,c.

bash
praisonai run --agent lead --subagents researcher,reviewer "Draft and review a brief on X"

The dedicated Named Agent Delegation page owns this topic in full.

Related