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.
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.
Quick Start
- Subagent Tool on an Agent
Attach
create_subagent_toolso 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") - 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
| Phase | What happens |
|---|---|
| 1. Delegate | The parent spawns a subagent with a scoped permission mode |
| 2. Execute | The subagent runs within its timeout and step limits |
| 3. Aggregate | Results 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.
- 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. - Allow-list them at run time
bash praisonai run "Research X and write a summary" --subagents researcher,writerThe main agent can now call
spawn_subagent(agent_name="researcher", ...)and the resolver runs yourresearcheragent 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:
praisonai run "<task>" --subagents researcher,writerThe allow-list takes precedence over the frontmatter marker.
Frontmatter marker (mode: subagent)
Mark an agent as delegatable in its own file — no flag needed:
---
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
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
Built-in Agent Profiles
| Agent | Mode | Description |
|---|---|---|
general | Primary | General-purpose coding assistant |
coder | All | Focused code implementation |
planner | Subagent | Task planning and decomposition |
reviewer | Subagent | Code review and quality |
explorer | Subagent | Read-only codebase investigation |
debugger | Subagent | Debugging and troubleshooting |
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:
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:
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:
| Option | Type | Default | Description |
|---|---|---|---|
max_concurrent | int | 5 | Max handoffs running at once |
timeout_seconds | float | 300.0 | Timeout per handoff |
allow_parallel | bool | False | Must be True to run via parallel_handoffs when passing a config |
max_depth | int | 10 | Maximum handoff chain depth |
context_policy | ContextPolicy | SUMMARY | How much history each target sees |
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
| Mode | Description |
|---|---|
default | Standard permission checking |
accept_edits | Auto-accept file edits |
dont_ask | Auto-deny prompts |
bypass_permissions | Skip all checks (dangerous) |
plan | Read-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:
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.
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.