subagents/
Subagents live under subagents/<name>/, each with its own instructions.md
and agent.ts. Add one when a task should run with a narrower identity, model,
tool set, workspace, connection set, or durable run boundary.
Minimal Example
// subagents/researcher/agent.ts
import { defineSubagent } from "@assemblyline-agents/core";
export default defineSubagent({
model: "openai/gpt-5.4-mini",
reasoning: "low",
description: "Use this subagent for scoped research tasks.",
defaultTools: []
});
The description doubles as the model-facing "when to use this subagent" text,
so write it as guidance for the parent model.
Full Options
defineSubagent() accepts every defineAgent() field — with
model optional — plus two child-scoping fields:
| Field | Type / values | Default | Effect |
|---|---|---|---|
model | string | inherits the primary agent's model | Child model spec. |
workspace | AdapterDefinition | — | Child workspace adapter, e.g. adapter("local"). |
connections | string[] | — | Connection names the child may use. |
(all other defineAgent fields) | — | see agent.ts | reasoning, defaultTools, outputSchema, maxIterations, and the rest apply per child. |
When the inherited model uses a built-in host route, the child uses the same
route. In particular, an openai-codex/* primary agent and its inheriting
subagents share the host's Codex CLI OAuth session; no child-specific auth or
engine connection is required.
import { adapter, defineSubagent } from "@assemblyline-agents/core";
export default defineSubagent({
description: "Use this for durable coding sessions.",
model: "openai/gpt-5-codex",
workspace: adapter("local"),
connections: ["github"],
defaultTools: []
});
The compiler records which skills, tools, and context the subagent inherits.
harness and engineConnection are intentionally not configurable: Pi is the
single child-agent engine, and model-provider authentication follows model.
How The Parent Invokes A Subagent
The parent model calls the built-in spawn_subagent tool, and authored tools
can call ctx.spawnSubagent(...) directly. Both take the same input:
await ctx.spawnSubagent({
name: "researcher",
task: "Summarize the three most recent issues in repo assembly-line.",
expectedOutput: "A markdown summary with issue links.",
constraints: ["Read-only: do not comment on issues."]
});
name and task are required; expectedOutput and constraints are
optional. The result is the child run's JSON output.
Realtime Capabilities
Realtime services are connections and tools, not child-agent engines. For example, a Pi-backed subagent can be scoped to a LiveKit connection and invoke an authored LiveKit tool:
// subagents/caller/agent.ts
import { defineSubagent } from "@assemblyline-agents/core";
export default defineSubagent({
description: "Use this subagent to coordinate phone calls.",
connections: ["livekit"]
});
The realtime media worker still runs in LiveKit. @assemblyline-agents/livekit provides
the typed API client and outbound-call tool; Assembly Line remains the reasoning and
durability layer.
Conventions
- Use
defineSubagent()in subagent folders. AdefineAgent()default export also compiles (some examples do this), butdefineSubagentis the intended API and unlocksworkspaceandconnections. - Keep each subagent's
defaultToolsandconnectionsas narrow as the task allows. - Write
descriptionas when-to-use guidance for the parent model.