Skip to main content

Orchestration

@baleybots/orchestration coordinates multiple Baleybots processors as a team. Team is the front door — one roster of members, three topologies per call.

Philosophy

A team is a roster of members, each backed by a Processable (typically a Baleybot). From that roster you pick how agents work together:

  1. Direct dispatch — you assign tickets to members. Full programmatic control.
  2. Coordinator — you state a goal; a coordinator decomposes it into tickets, delegates, and synthesizes results.
  3. Group chat — members talk to each other as peers in a shared thread.

All three share the same ticket/run engine, EventBus, CostTracker, and RunManager underneath.

Install

bun add @baleybots/orchestration @baleybots/core zod ai

Build a team

import { createTeam } from '@baleybots/orchestration';
import { Baleybot } from '@baleybots/core';

const team = createTeam({
members: [
{
name: 'architect',
role: 'Software Architect',
capabilities: ['design', 'planning'],
processable: Baleybot.create({ name: 'architect', goal: 'Design software architecture' }),
},
{
name: 'coder',
role: 'TypeScript Developer',
capabilities: ['typescript', 'implementation'],
processable: Baleybot.create({ name: 'coder', goal: 'Write TypeScript code' }),
},
],
});

1. Direct dispatch

You create work and assign it. createAndDispatch is create-and-run in one call.

team.events.on('ticket.completed', ({ ticket }) => console.log('done', ticket.id));

const run = await team.createAndDispatch({
title: 'Add OAuth login',
description: 'Implement Google OAuth in the desktop app',
assignee: 'coder',
});

console.log(run.status); // 'completed' | 'paused' | 'failed'

2. Coordinator

State a goal; a coordinator decomposes and delegates. Returns a live CrewSession you can chat with while workers execute.

const session = await team.chat('Plan and ship the auth migration');

session.onUpdate((msg) => console.log('[update]', msg));
const reply = await session.send('How is it going?');

const result = await session.stop();
console.log(result.summary);

3. Group chat

Members discuss as peers. Returns a GroupSession; subscribe to per-agent events and start() the conversation.

const session = team.groupChat({ maxTurns: 8 });

session.on('agent-stream-complete', ({ agentName, content }) =>
console.log(`${agentName}: ${content}`),
);

await session.start('Where should we host the migration runbook?');

groupChat() requires every selected member's processable to be a Baleybot instance. Use members: ['architect', 'coder'] to restrict the roster.

Events and cost tracking

Every topology emits typed events on team.events:

team.events.on('run.event', ({ runId, event, agentName }) => {
if (event.type === 'text-delta') process.stdout.write(event.content);
});

team.events.on('agent.budget_exceeded', ({ agent, spent, limit }) => {
console.warn(`${agent.name} over budget: $${spent}/$${limit}`);
});

Built-in pricing covers common models; pass customPricing on Orchestrator for overrides.

Primitives underneath

When the three topologies don't fit, reach for lower-level exports:

ExportRole
OrchestratorExplicit ticket/run engine
Crew / createCrew()Coordinator machinery behind team.chat()
EventBus, AgentRegistry, Scheduler, RunManagerInfrastructure
createOrchestrationTools() / createWorkerTools()Zod tools for agent self-management
createOrchestrationMCPServer() / createCrewMCPServer()Expose orchestration via MCP

Group chat exports (groupSession, personality) live at @baleybots/orchestration/ensemble.