subagents

Installation
SKILL.md

Subagent Dispatch Skill

Use call_subagent to delegate tasks to other agents, and wait_for_subagents to collect results from background runs.

When To Use

Delegate when at least one is true:

  • The task is large enough to benefit from an isolated execution context
  • Multiple independent tasks can run in parallel
  • You need a specialized agent type (read-only explore, shell-heavy work)

Do not delegate when:

  • The task is small and can be done directly
  • The work requires constant access to the current conversation state
  • Multiple sub-agents would write to the same file with no merge plan
  • You cannot summarize the full context into a self-contained prompt

Depth limit: sub-agents cannot call call_subagent. Only the root agent may dispatch.

Tool: call_subagent

from sdk.tool import tool

result = tool.call("call_subagent", {
    "agent_name": str,   # required
    "agent_id":   str,   # required
    "prompt":     str,   # required
    "model_id":   str,   # optional, defaults to inheriting the caller's model
    "background": bool,  # optional, default False
})

agent_name

Maps to a .agent filename under agents/. Built-in types:

  • magic: general-purpose, full tool access (web, files, code). Use for complex multi-step tasks.
  • explore: read-only. Searches files, reads code, answers structural questions. Cannot modify anything.
  • shell: shell command specialist. Runs scripts, installs deps, performs system operations.
  • search: web research specialist. Searches the web and reads pages to gather external information. Cannot modify local files.

Other .agent files (e.g. data-analyst) can also be used by name.

agent_id

Human-readable session identity, e.g. market-research-phase1.

  • Same agent_id → resume the existing conversation (same chat history)
  • Different agent_id → fresh start with empty history
  • Name by responsibility, not by sequence: ppt-outline, shell-install-ffmpeg — not task1, worker-a

prompt

The sub-agent has no access to the parent's conversation history. The prompt must be fully self-contained. Include:

  • The exact task
  • Expected output format
  • Relevant file paths or object identifiers
  • Constraints (e.g. read-only, specific file to write)
  • Success criteria

Bad:

Find out what competitors are doing and summarize.

Good:

Search the web for the top 3 competitors of [product category] that have launched or updated in the past 12 months.
For each, return: product name, target users, main differentiator, and source URL.
Focus on product launch articles, review sites, and tech media. Do not modify files.

background

  • False (default): run synchronously, block until the sub-agent finishes, return result immediately.
  • True: dispatch as a background task and return immediately. Must follow with wait_for_subagents to collect the result.

Use background=True for all parallel workloads. Sequential call_subagent(..., background=True) calls result in concurrent execution regardless of whether the model supports parallel tool calls.

Tool: wait_for_subagents

from sdk.tool import tool

result = tool.call("wait_for_subagents", {
    "agent_ids": ["id-a", "id-b"],  # required, list of agent_ids from background calls
    "timeout":   30,                # optional, seconds, default 30, recommended 30–60
})

Awaits all listed agents together. result.content uses this format per agent:

[i/total] agent_type/session_id: status
Result:
```final output```
  • status values: done, error, interrupted, running, not_found, ambiguous
  • Result: appears only when status is done — contains the sub-agent's final output
  • When status is running (timed out), Result: is replaced by Last message: — this is the last assistant message the sub-agent produced before the timeout, useful for gauging progress
  • wait_for_subagents is idempotent — if status is still running, call it again or decide to stop waiting
  • result.data["results"]: structured list for programmatic access, fields: agent_id, agent_name, status, result, error, last_activity

Output Target

Decide where results go before dispatching. If the output target is missing from the prompt, the sub-agent will guess — and will usually create a file or object it shouldn't.

Three patterns:

Shared container (canvas, slides): pass the same container identifier (e.g. project path) to every sub-agent; tell each one which section it owns. Do not let sub-agents create or choose their own container.

Single file (report, document): assign the full file to one agent, or have parallel agents draft their sections independently then designate one merge agent to write the final file.

Independent outputs (one file per topic, one canvas per theme): each agent gets its own target; no coordination needed.

Never let multiple sub-agents write to the same file concurrently.

Reporting Results to the User

Sub-agents may include output file paths in their results. When reporting to the user, convert those paths to [@file_path:path] format — the frontend renders them as clickable links.

Example: Research report is ready: [@file_path:reports/market-research.md]

Sync Example

from sdk.tool import tool

result = tool.call("call_subagent", {
    "agent_name": "explore",
    "agent_id": "find-product-positioning-doc",
    "prompt": """Find the single workspace document that is most useful for answering: "What is this project, who is it for, and what does it provide?"
Check workspace folders that are likely to contain project briefs, product analysis, requirements, launch materials, or internal planning before searching elsewhere.
Return:
1. the file path
2. a 3-5 bullet summary
3. one related file worth reading next
Do not modify files.""",
    "background": False,
})

print(result.content)

Parallel Example

Dispatch first (sequential calls, concurrent execution):

from sdk.tool import tool

def dispatch(agent_id, prompt):
    tool.call("call_subagent", {
        "agent_name": "search",
        "agent_id": agent_id,
        "prompt": prompt,
        "background": True,
    })

dispatch("research-competitors", """Search the web for the top 3-5 competitors in this product space.
For each, return: product name, target users, main differentiator, and source URL.
Focus on product launches, review sites, and tech media from the past 12 months.""")
dispatch("research-market-signals", """Search the web for recent market signals in this product space.
Return:
1. notable user needs or pain points (with source URLs)
2. recurring themes across articles or community discussions
3. any emerging trends worth tracking""")

Then wait:

result = tool.call("wait_for_subagents", {
    "agent_ids": ["research-competitors", "research-market-signals"],
    "timeout": 60,
})

print(result.content)

Checklist

Before dispatching:

  • Is delegation actually necessary?
  • Does the prompt contain all required context (no reference to parent conversation)?
  • Is agent_id stable, human-readable, and unique to this task branch?
  • Is the output target explicit and conflict-free?
  • If background=True, is there a matching wait_for_subagents?
Related skills
Installs
3
Repository
dtyq/magic
GitHub Stars
4.8K
First Seen
10 days ago