Multi-Agent Orchestration (AskCollaborator)
This playbook shows how one orchestrator agent delegates subtasks to named specialist responders (a researcher and a writer) through the loopback-by-default AskCollaborator MCP tool. The wiring is code-only: you build collaborator responders, create a runtime extension, and attach it to the orchestrator per request.
For in-process helpers, the built-in Agent tool
provides a config-first option. Configure subagents.models to offer model choices,
then select model and effort on each call; omitted values inherit profile pins
or the parent’s effective route. For continued work in one conversation, create a
helper with persist: true and resume or close it using AgentSend; configure
subagents.instances for its idle TTL and caps. The collaborator setup below remains useful for
separately composed responders.
Who this is for
Section titled “Who this is for”Workflow designers composing specialist agents — you want a single orchestrator that decides when to hand a subtask to a researcher, a writer, or any other named collaborator, rather than doing everything in one prompt.
One orchestrator agent delegates subtasks to named collaborator responders (researcher, writer) via the loopback-by-default AskCollaborator MCP tool.
Features used
Section titled “Features used”orchestrator.ask-collaborator— loopback-by-default MCP tool delegating to named collaborator responders, with guarded non-loopback opt-in, call caps, and per-collaborator timeout (coverage: code).harness.request-runtime-options— per-request runtime option extensions viacreateConfiguredAgentResponder({ runtimeOptionsForRequest })(coverage: code).runtime.custom— custom runtime composition that drives the orchestrator (coverage: code).
Configuration
Section titled “Configuration”This capability is code-only — there is no mono-agent.config.json key for it. You construct the collaborator extension programmatically and pass its run options to the orchestrator’s responder. See programmatic composition and multi-agent.
After importing createConfiguredAgentResponder and
createCollaboratorToolRuntimeExtension, build the config and both collaborator
responders, then attach the request-scoped extension:
// Assume config and both collaborator responders have already been created.const orchestrator = await createConfiguredAgentResponder({ config, runtimeOptionsForRequest: async (input) => { const extension = await createCollaboratorToolRuntimeExtension({ collaborators: [ { id: "researcher", label: "Researcher", responder: researcherResponder }, { id: "writer", label: "Writer", responder: writerResponder }, ], conversationId: input.request.conversationId, originalUserMessage: input.request.userMessage, abortSignal: input.request.abortSignal, maxCalls: 10, }); return { runtimeOptions: extension.runtimeOptions, cleanup: extension.cleanup, }; },});- Build collaborator responders (one
createConfiguredAgentResponderper specialist, or A2A consumers). - Inside
runtimeOptionsForRequest, callcreateCollaboratorToolRuntimeExtensionwith the requiredcollaborators,conversationId,originalUserMessage, andabortSignalfields (plus optionalmaxCalls). - Return
{ runtimeOptions: extension.runtimeOptions, cleanup: extension.cleanup }from the callback so the host attaches the loopback tool and closes the ephemeral MCP server when the turn ends. - Run the orchestrator with a task that requires delegation.
- Inspect the run artifact for
AskCollaboratorcalls.
Smoke test
Section titled “Smoke test”For command-based workers, use background process jobs
to hand off Exec/Bash stages and resume from their completion turns.
processJobs.maxChainDepth defaults to 4 and accepts at most 64; choose a
budget for the workflow without resetting lineage. A depth-32 exhausted wake
cannot start another background stage when the configured budget is 32.
Use wake_on_completion: false explicitly for helpers whose terminal card
is sufficient, and treat an unknown wake receipt as non-replayable.
Related
Section titled “Related”- Programmatic: multi-agent
- Programmatic: composition
- Programmatic: A2A consumer
- Runtime backends
- Observability: artifacts and traces
- Composer skill:
mono-agent-composer(run/mono-agent-composerto scaffold and validate an agent from one config).
Let a persistent child ask for direction
Section titled “Let a persistent child ask for direction”Start a child with Agent({persist: true, prompt: "Review the design"}).
A child can call AskParent({question: "Which scope?", options: ["API", "UI"]})
to save its question and end its turn. The successful parent-facing result has
status awaiting_reply, an instance id, and the structured question. Answer with
AgentSend({id, message: "Focus on the API"}); the child resumes its own durable
context. Global or profile AskParent denies disable this dialogue. The child
cannot contact the user: the parent decides whether to answer or ask the user.
Failed replies leave the question pending. Close-only retires the instance;
there is no background execution or automatic wake in this dialogue path.
Detached persistent work
Section titled “Detached persistent work”Use Agent with persist:true, background:true when the current reply need not
wait for the child. Continue it with AgentSend and background:true plus a
message. The started receipt is durable, and the exact originating conversation
wakes on completion, failure, interruption or AskParent. Answer an awaiting
child with AgentSend. Do not poll or replay. A terminal childStillBusy:true job
means another send must wait for ownership resolution. Late settlement is not
proof that a failed transcript was retained: lost/unknown continuity requires
explicit close/create, and unavailable owners cannot be bypassed. See
background child lifecycle.
For long verification inside a detached child, use foreground Bash/Exec with
timeout_ms. Its ceiling is min(remaining job runtime, subagents.commandTimeoutMs)
at child-run setup (command default: 30 minutes); the job deadline still applies
throughout execution. Configure subagents.timeoutMs / profile timeouts and
processJobs.maxRuntimeMs for the whole task too. Child-owned background commands
remain unsupported; foreground children and NodeRepl keep their existing caps.