Core concepts

Teams

Named, validated groups of agents you compose into workflows.

A team is a named, validated group of agents. It gives a set of related agents an identity — "support", "review-panel" — and guarantees at construction time that the group is well-formed: non-empty, and free of duplicate agent names. Workflows then consume the team's agents instead of ad-hoc arrays scattered across files.

Teams are pure composition: they hold no topology and no runtime state. The same team can back a pipeline in one workflow and a parallel review panel in another. That separation keeps the "who" (the team) independent from the "how" (the workflow topology).

Defining a team#

Call team({...}) with a name, an optional description, and the member agents.

src/teams/review-panel.ts
import { agent, team } from "@assemble-dev/sdk";
import { openai } from "@assemble-dev/providers";

const safetyReviewer = agent({
  name: "safety-reviewer",
  role: "Checks content for policy violations",
  model: openai({ model: "gpt-4o-mini" }),
  instructions: "Return approve or request-changes with a reason.",
});

const qualityReviewer = agent({
  name: "quality-reviewer",
  role: "Checks content for clarity and accuracy",
  model: openai({ model: "gpt-4o-mini" }),
  instructions: "Return approve or request-changes with a reason.",
});

export const reviewPanel = team({
  name: "review-panel",
  description: "Concurrent content reviewers",
  agents: [safetyReviewer, qualityReviewer],
});

Options#

OptionTypeDescription
namestringNon-empty team identifier. Required.
descriptionstringWhat the team is for. Defaults to "".
agentsWorkflowAgentDefinition[]The member agents. At least one, with unique names. Required.

The returned definition is frozen and exposes two read-only views:

FieldTypeDescription
agentsreadonly WorkflowAgentDefinition[]The member agent definitions, in order.
agentNamesreadonly string[]The member names, in the same order — useful for route functions and parallel agentNames.

Unique-name enforcement#

team({...}) validates eagerly and throws an AppError with a 400 status for each failure mode, so a malformed team never reaches a run:

  • an empty or whitespace-only name — team name must not be empty
  • an empty agents array — team "<name>" must include at least one agent
  • two agents sharing a name — team "<name>" contains duplicate agent name "<agent>"

Unique names matter because everything downstream is keyed by agent name: supervisor routing, tool allowlists, parallel output merging, and trace events. Catching a collision at definition time is much cheaper than debugging a run where two agents overwrite each other's artifacts.

Composing a team into a workflow#

A workflow takes agents, not teams, so spread the team's agents into the agents array. The team stays the single source of truth for membership.

src/workflow.ts
import { workflow } from "@assemble-dev/sdk";
import { z } from "zod";
import { reviewPanel } from "./teams/review-panel";

export const panel = workflow({
  name: "review-panel",
  inputSchema: z.object({ content: z.string().min(1) }),
  agents: [...reviewPanel.agents],
  topology: { kind: "parallel" },
});

team.agentNames pairs well with topology options that take names, such as the parallel topology's agentNames subset or a supervisor route function that iterates over candidates.

Team presets#

For the three common shapes, the SDK ships preset builders that turn a team into a ready-made WorkflowConfig. Each returns a plain config object — pass it straight to workflow(...), or spread it and override fields before constructing.

PresetExtra inputsProduces
buildPipelineTeamWorkflowConfigteam, name, inputSchema, outputSchema?A { kind: "pipeline" } workflow over the team's agents in order.
buildSupervisorTeamWorkflowConfigteam, name, supervisorName, route, inputSchema, outputSchema?, maxSteps?A { kind: "supervisor" } workflow where your route function picks among the team's agents.
buildReviewPanelWorkflowConfigteam, name, inputSchemaA { kind: "parallel" } workflow that fans the whole team out concurrently.
src/workflows/panel.ts
import { buildReviewPanelWorkflowConfig, workflow } from "@assemble-dev/sdk";
import { z } from "zod";
import { reviewPanel } from "../teams/review-panel";

export const panelWorkflow = workflow(
  buildReviewPanelWorkflowConfig({
    team: reviewPanel,
    name: "content-review",
    inputSchema: z.object({ content: z.string().min(1) }),
  }),
);

Presets cover topology and schemas only. To attach tools, policies, or memory, spread the preset into your own config:

ts
export const auditedPanel = workflow({
  ...buildReviewPanelWorkflowConfig({
    team: reviewPanel,
    name: "content-review",
    inputSchema: z.object({ content: z.string().min(1) }),
  }),
  policies: [auditPolicy],
});

The content review panel in examples uses exactly this shape end to end, including an eval suite over the merged panel output. For topology semantics and when to choose each shape, see workflows.