Cereal docs
Configure agents

Multiple agents

Compose reusable agents by reference, then initialize and serve them together.

Each defineAgent call returns an independent agent with its own tools, hooks, verification settings, and session helpers. Pass the returned object directly in another agent's subagents array:

import { createAgentRouter, defineAgent, defineProvider } from "@trycereal/sdk"

const gateway = defineProvider({ slug: "gateway", type: "vercel-ai-gateway", secret: process.env.AI_GATEWAY_API_KEY })
const model = { provider: gateway, model: "anthropic/claude-sonnet-4.6" }

export const researcher = defineAgent({
  agent: {
    slug: "researcher",
    description: "Find evidence and cite sources before drawing a conclusion.",
    model,
    system: "Research the assigned question."
  }
})

export const coordinator = defineAgent({
  agent: {
    slug: "coordinator",
    model,
    system: "Delegate research, then synthesize an answer.",
    subagents: [researcher]
  }
})

export const agents = createAgentRouter({ agents: [coordinator] })
// Optional early startup. The session action below also initializes dependencies.
await agents.init()

const session = await coordinator.sessions.start({ message: "Compare our options." })

The router discovers researcher through the reference, mounts each agent at /api/cereal/<slug>/mcp and /api/cereal/<slug>/hooks, and initializes dependencies before parents. Shared provider and agent references initialize once. Its agents array uses that same dependency order. Duplicate slugs on distinct objects, reference cycles, and empty routers are rejected.

A router owns its agents' HTTP paths: construct it before serving requests and use one router per agent instance. agent.paths reports the active paths. Mount agents.fetch or agents.handlers in your framework; the framework guides include Express, Fastify, and Hono.

Name a delegation role or pin a version

const coordinator = defineAgent({
  agent: {
    slug: "coordinator",
    model,
    system: "Ask the reviewer to check claims.",
    subagents: [{
      agent: researcher,
      name: "reviewer",
      description: "Check factual claims against primary evidence.",
      version: 3
    }]
  }
})

Without a wrapper, the roster name is the referenced agent's slug and the description comes from its definition, falling back to the slug. Set a useful description so the model knows when to delegate. Omitting version resolves the latest version when a child is spawned; a pin must already exist in the target environment. Syncing an agent creates its current version, not an arbitrary historical pin.

External and derived agents

Existing wire references still work alongside local objects:

subagents: [
  researcher,
  { kind: "agent", name: "billing", agent: "billing-service", description: "Handle billing questions." },
  { kind: "derived", name: "review", extends: "parent", description: "Review the result." }
]

String references are external: initialization does not register them. Use object references for agents in the same deployment. Development channel transport applies the same namespace to the registered agents and their object references.

coordinator.init() initializes its referenced agents before itself, and the parent's handlers can serve their separate routes. Use createAgentRouter to group independent agents. Construct routers before serving requests and use one router per agent instance.

Initialization is sequential across dependencies and is not a transaction: a server failure can leave initialized dependencies in place. A later action retries failed work. Call agents.close() during shutdown to stop the group's outbound channels.

Delegation itself follows the same sub-agent policies as a roster authored through the API.

On this page