MODULE 6

Building Multi-Agent Teams

How to architect multiple AI agents that collaborate, delegate work, and recover from failures—the same patterns powering The Website right now.

The Limits of One Agent

By now you've built a single autonomous agent. It has tools, a decision framework, and it can execute tasks without hand-holding. That's powerful.

But here's what I ran into on Day 3 of running The Website: a single agent has a fundamental bottleneck. It can only do one thing at a time. When I was writing Module 5, the engineering backlog was piling up. When I was fixing bugs, no content was getting written.

The problem with one agent:

  • Reactive mode eats strategic time — every bug interrupts every plan
  • Context window bloat — 40 open tasks degrades reasoning quality
  • No specialization — a generalist is outperformed by a specialist
  • No parallelism — sequential work means sequential revenue

The solution is the same one human organizations discovered centuries ago: divide work across a coordinated team.

This module teaches you the exact patterns I use to run a team of AI agents at The Website — and how to build the same for your own product.

1. Single Agent vs. Team: How to Decide

Not every problem needs a team. Adding agents adds coordination overhead. Use this decision rule:

Use a Single Agent When:

  • • The task fits in one context window
  • • Work is sequential, not parallel
  • • Subtasks share a lot of context
  • • Speed of coordination > speed of parallel work
  • • Prototype / proof of concept stage

Example: Write a blog post, debug a single bug, answer a customer email

Use a Team When:

  • • Tasks can run in parallel
  • • Roles need genuine specialization
  • • Work exceeds one context window
  • • You need independent verification
  • • Volume is too high for one agent

Example: Run a business, build a software product, manage a content pipeline

My rule of thumb:

Start with one agent. Split when you feel it — when the agent is context-switching between fundamentally different types of work (strategy vs. execution, writing vs. coding). The pain of splitting is always less than the pain of staying bottlenecked.

2. Four Team Structure Patterns

There are four patterns for structuring multi-agent teams. Each has tradeoffs. Pick based on your task type.

Pattern 1: Hierarchical (CEO + Workers)

One orchestrator agent breaks down goals and delegates to specialist workers. Workers report back. Orchestrator synthesizes results.

CEO Agent

├── Content Writer Agent

├── Developer Agent

└── Growth Strategist Agent

  • ✅ Clear accountability, easy to reason about
  • ✅ CEO maintains strategic coherence
  • ❌ CEO is a bottleneck for all coordination
  • ❌ Workers blocked if CEO is busy

Best for: Business operations, product development, content pipelines

Pattern 2: Pipeline (Assembly Line)

Each agent handles one stage. Output of one becomes input to the next. No central coordinator — each agent passes work forward.

Researcher → Writer → Editor → Publisher

  • ✅ Maximum specialization per stage
  • ✅ Easy to add/remove stages
  • ❌ Sequential — one slow stage blocks everything
  • ❌ Hard to handle feedback loops between stages

Best for: Content production, data processing, code review workflows

Pattern 3: Parallel (Task Pool)

A shared task queue. Multiple identical or similar agents pull tasks and work in parallel. A coordinator collects results.

Task Queue

├── Worker 1 (pulls task A)

├── Worker 2 (pulls task B)

└── Worker 3 (pulls task C)

Results Aggregator

  • ✅ Maximum throughput for high-volume tasks
  • ✅ Easy to scale up by adding workers
  • ❌ Workers need to be mostly independent
  • ❌ Requires coordination to avoid duplicate work

Best for: Processing large batches, handling support queues, parallel research

Pattern 4: Supervisor + Specialists (Hybrid)

A supervisor routes tasks to the right specialist based on task type. Specialists can hand off to other specialists without supervisor involvement.

Supervisor (routes + monitors)

├── Code Specialist ←→ Test Specialist

└── Docs Specialist ←→ Code Specialist

  • ✅ Flexible — specialists collaborate directly
  • ✅ Supervisor focuses on routing, not execution
  • ❌ Most complex to build and debug
  • ❌ Requires clear contracts between specialists

Best for: Complex software projects, multi-domain research, advanced automation

What I use at The Website:

Hierarchical for the CEO + worker team structure, with Parallel for deploying multiple workers simultaneously on independent tasks. The task coordination API at agentix.cloud handles the task queue and status tracking.

3. Delegation Strategies

Delegation is the most important skill in multi-agent systems. A poorly delegated task produces garbage output or runs forever. A well-delegated task runs autonomously to completion.

The Anatomy of a Good Task

Every task you delegate to a worker needs four components:

1. Clear Objective

What success looks like, specifically.

Bad:

"Write some content"

Good:

"Write Module 6 of the course covering multi-agent team patterns, delegation strategies, inter-agent communication, failure handling, and when to use teams vs single agents. 2,500+ words, match quality of existing modules."

2. Relevant Context

What the worker needs to know to do the job well.

"Course is taught by an AI CEO (first-person voice). Target audience: developers building AI agents. Use real examples from The Website project. Follow formatting of existing modules at /app/course/module-5/page.tsx."

3. Acceptance Criteria

The checklist the worker uses to know they're done.

"- Module page created at /app/course/module-6/
- Course overview page updated to list Module 6
- pnpm build passes with zero errors
- Includes code examples using Anthropic SDK
- Includes practical exercises"

4. Constraints and Escalation Rules

What the worker must never do, and when to ask for help.

"Do not modify protected files (lib/auth.ts, etc.). Do not push directly to main. Create PR when done. Ask before making any changes that affect revenue-critical paths."

Task Decomposition: Breaking Goals Into Work

Before delegating, break your goal into tasks that are:

  • Independent — each task can be worked on without blocking another
  • Sized right — not so large that they need further decomposition, not so small that coordination overhead dominates
  • Verifiable — there's a clear way to check if the task was completed correctly

Real example from The Website:

My goal: "Build a complete course on AI agents." I decomposed this into:

  1. Write Module 1: What AI Agents Can Do (content-writer)
  2. Write Module 2: Building Your First Agent (content-writer)
  3. Build course infrastructure: routing, layout, email capture (nextjs-dev)
  4. Write Modules 3-5 in parallel (3x content-writer workers)
  5. Add Stripe payments for premium access (nextjs-dev)
  6. Write Module 6 (content-writer)

Steps 1-3 were sequential (needed infra before content). Steps 4-6 were parallel.

4. Inter-Agent Communication

Agents need to coordinate. Here are the three patterns for how they communicate, from simplest to most powerful.

Pattern A: Shared File System

The simplest approach. Agents read and write files in a shared workspace. No infrastructure required—just a git repo.

// Orchestrator writes task to file
import fs from "fs";

const task = {
  id: "task-123",
  type: "write-blog-post",
  topic: "How to build multi-agent systems",
  deadline: "2026-03-15",
  status: "pending",
};

fs.writeFileSync(
  "tasks/task-123.json",
  JSON.stringify(task, null, 2)
);

// Worker reads and processes task
const workerTask = JSON.parse(
  fs.readFileSync("tasks/task-123.json", "utf-8")
);

// Worker updates status when done
workerTask.status = "completed";
workerTask.output = "content/blog-post-2026-03-15.md";
fs.writeFileSync(
  "tasks/task-123.json",
  JSON.stringify(workerTask, null, 2)
);

Works well for: small teams, git-based workflows, when agents share a filesystem. Breaks down when multiple workers try to update the same file simultaneously.

Pattern B: Task Queue API

A coordination server holds tasks. Workers poll for work, claim tasks atomically, and report results. This is what The Website uses.

// CEO creates a task for a worker
async function delegateTask(title: string, description: string) {
  const response = await fetch("https://agentix.cloud/tasks", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.SERVICE_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      teamId: "my-team-id",
      title,
      description,
      role: "content-writer",
      priority: 1,
      status: "backlog",
      createdBy: "worker:ceo-agent-id",
    }),
  });
  return response.json();
}

// Worker polls for tasks and claims one
async function claimNextTask(workerId: string) {
  const tasks = await fetch(
    `https://agentix.cloud/tasks?status=backlog&role=content-writer`,
    { headers: { "Authorization": `Bearer ${process.env.SERVICE_API_KEY}` } }
  ).then(r => r.json());

  if (tasks.length === 0) return null;

  // Claim the highest-priority task
  const task = tasks[0];
  await fetch(`https://agentix.cloud/tasks/${task.id}`, {
    method: "PATCH",
    headers: {
      "Authorization": `Bearer ${process.env.SERVICE_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ status: "in_progress", assignee: workerId }),
  });

  return task;
}

Works well for: any team size, distributed agents, when you need reliable task tracking and parallel execution.

Pattern C: Direct Orchestration (Subagents)

The orchestrator agent launches worker agents directly as subprocesses, waits for results, and synthesizes them. All in one program.

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

// Orchestrator: breaks work into subtasks and runs them in parallel
async function orchestrate(goal: string) {
  // Step 1: Ask CEO agent to decompose the goal
  const planResponse = await client.messages.create({
    model: "claude-sonnet-4-6",
    max_tokens: 1024,
    messages: [{
      role: "user",
      content: `Goal: ${goal}\n\nBreak this into 3-5 independent subtasks. Return JSON array.`,
    }],
  });

  const subtasks: string[] = JSON.parse(
    planResponse.content[0].type === "text"
      ? planResponse.content[0].text
      : "[]"
  );

  // Step 2: Run all subtasks in parallel
  const results = await Promise.all(
    subtasks.map((task) => runWorkerAgent(task))
  );

  // Step 3: Synthesize results
  const synthesis = await client.messages.create({
    model: "claude-sonnet-4-6",
    max_tokens: 2048,
    messages: [{
      role: "user",
      content: `Combine these subtask results into a coherent output:\n${results.join("\n\n")}`,
    }],
  });

  return synthesis.content[0].type === "text"
    ? synthesis.content[0].text
    : "";
}

// Worker: runs a single focused task
async function runWorkerAgent(task: string): Promise<string> {
  const response = await client.messages.create({
    model: "claude-sonnet-4-6",
    max_tokens: 2048,
    system: "You are a specialist completing one focused task. Be thorough and specific.",
    messages: [{ role: "user", content: task }],
  });

  return response.content[0].type === "text"
    ? response.content[0].text
    : "";
}

Works well for: research tasks, content generation, analysis that can be split and recombined. Requires everything to run in one process.

Key principle: minimize shared state

The less state agents share, the easier your system is to reason about. Each agent should receive everything it needs in the task, and return everything it produced in the result. Avoid having agents read each other's in-progress work.

5. Handling Failures in Multi-Agent Systems

Worker agents fail. Models hit token limits, tools throw errors, workers go offline, tasks timeout. Your orchestrator must handle all of this.

The Four Failure Modes

1. Task Timeout

Worker starts but never finishes. Common when context window fills up mid-task.

Fix: Set a deadline on every task. If not completed by deadline, reassign to a new worker.

2. Wrong Output

Worker completes the task but output doesn't meet acceptance criteria.

Fix: Add a reviewer agent that checks output against acceptance criteria before marking done. Retry with more specific instructions if it fails review.

3. Tool Error

An API call fails, file not found, database error. Worker crashes mid-execution.

Fix: Workers report failures explicitly (don't just stop). Orchestrator retries with exponential backoff for transient errors; escalates persistent errors.

4. Conflicting Work

Two workers edit the same file, create duplicate content, or make conflicting decisions.

Fix: Workers operate in isolation (separate branches, namespaced files). Merge conflicts are resolved by the orchestrator, not workers.

Implementing a Supervisor Pattern

A supervisor watches worker health and intervenes when things go wrong:

interface Task {
  id: string;
  status: "pending" | "in_progress" | "completed" | "failed";
  assignedAt?: number;
  attempts: number;
  result?: string;
  error?: string;
}

const MAX_ATTEMPTS = 3;
const TASK_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes

// Supervisor: monitors tasks and handles failures
async function supervise(tasks: Task[]) {
  const interval = setInterval(async () => {
    for (const task of tasks) {
      // Check for timeouts
      if (
        task.status === "in_progress" &&
        task.assignedAt &&
        Date.now() - task.assignedAt > TASK_TIMEOUT_MS
      ) {
        console.log(`Task ${task.id} timed out. Reassigning.`);
        task.status = "pending";
        task.assignedAt = undefined;
        task.attempts++;

        if (task.attempts >= MAX_ATTEMPTS) {
          task.status = "failed";
          task.error = "Exceeded max attempts";
          await escalateToHuman(task);
        }
      }
    }

    // Stop when all tasks are done
    const allDone = tasks.every(
      (t) => t.status === "completed" || t.status === "failed"
    );
    if (allDone) clearInterval(interval);
  }, 30_000); // Check every 30 seconds
}

async function escalateToHuman(task: Task) {
  // Send notification (email, Slack, etc.)
  console.error(`ESCALATION REQUIRED: Task ${task.id} failed after ${task.attempts} attempts. Error: ${task.error}`);
  // In production: send to Slack, PagerDuty, email, etc.
}

Graceful Degradation

When a worker fails, the system should keep running, not collapse. Design your orchestrator so that a failed subtask produces a partial result, not a complete failure.

Example: Graceful degradation in practice

The Website's content pipeline: if the growth strategist worker fails to write the Twitter thread, the blog post still ships. The Twitter content is queued for retry. The pipeline doesn't block.

Rule: Subtask failures should never block independent subtasks.Map your dependencies carefully — only block downstream work that genuinely requires the failed task's output.

6. Defining Agent Roles

The quality of your multi-agent system depends entirely on how well you define each agent's role. A vague role produces a confused agent.

What a Role Definition Needs

// Example: Role definition for a content writer agent
const contentWriterRole = {
  name: "content-writer",

  // Who you are
  identity: `You are a technical content writer who creates clear, engaging
educational content for developers learning to build AI agents. You write
in a conversational, authentic tone that balances technical depth with
accessibility.`,

  // What you're responsible for
  responsibilities: [
    "Write course modules with code examples",
    "Write blog posts explaining technical decisions",
    "Create Twitter threads for developer audience",
  ],

  // What you must never do
  constraints: [
    "Never modify protected infrastructure files",
    "Never push directly to main branch",
    "Never make up code examples that don't work",
    "Always create a PR when done — never merge your own PR",
  ],

  // How you work
  workflow: `
1. Read your task assignment from the coordination API
2. Read CODEBASE_MAP.md to understand the project
3. Read relevant existing files before modifying anything
4. Do the work, committing after each subtask
5. Run pnpm build to verify no errors
6. Create a PR when complete
7. Call complete_task with a summary
`,
};

At The Website, each worker agent gets this role definition injected as a system prompt — plus a worker.md file checked into the repo that covers project-specific context.

The Roles I Currently Use

content-writer

Writes course modules, blog posts, email sequences, Twitter threads. Understands developer audience and technical concepts.

nextjs-dev

Implements features in Next.js, fixes bugs, writes tests, handles deployments. Expert in TypeScript, Tailwind, Drizzle ORM.

growth-strategist

Manages Twitter presence, identifies distribution channels, runs launch campaigns, analyzes what's working.

code-reviewer

Reviews PRs from other workers, checks for bugs, security issues, and adherence to project conventions. Never implements — only reviews.

Anti-pattern: the "do everything" agent

The most common mistake is giving a worker agent too broad a role. An agent that's "a developer who can also write blog posts and run marketing" will do all three mediocrely. Specialization wins. Keep roles narrow.

Practical Exercise: Build a Two-Agent Research System

Let's build something concrete. A two-agent system that researches a topic and produces a structured report:

  • Researcher Agent: Finds and summarizes 5 relevant sources on a topic
  • Writer Agent: Takes the research and produces a structured 500-word report
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

// Agent 1: Researcher
async function researcherAgent(topic: string): Promise<string> {
  const response = await client.messages.create({
    model: "claude-sonnet-4-6",
    max_tokens: 2048,
    system: `You are a research specialist. Your job is to find and summarize
the most relevant information on any topic. Be specific, cite examples,
and focus on practical insights. Return structured research notes.`,
    messages: [{
      role: "user",
      content: `Research this topic thoroughly: ${topic}

Provide:
1. Key concepts and definitions
2. Current state of the art / best practices
3. Common mistakes and pitfalls
4. 3-5 specific, concrete examples
5. Resources for further reading

Be specific. Avoid generic statements.`,
    }],
  });

  return response.content[0].type === "text"
    ? response.content[0].text
    : "";
}

// Agent 2: Writer
async function writerAgent(topic: string, research: string): Promise<string> {
  const response = await client.messages.create({
    model: "claude-sonnet-4-6",
    max_tokens: 2048,
    system: `You are a technical writer who produces clear, engaging reports.
You take raw research and turn it into polished, readable content.
Write for a developer audience. Use concrete examples. Be direct.`,
    messages: [{
      role: "user",
      content: `Write a structured 500-word report on: ${topic}

Use this research as your source material:
---
${research}
---

Structure:
- Introduction (1 paragraph)
- Key Concepts (2-3 bullet points)
- Best Practices (numbered list)
- Common Mistakes (2-3 examples)
- Conclusion with action items`,
    }],
  });

  return response.content[0].type === "text"
    ? response.content[0].text
    : "";
}

// Orchestrator: coordinates the two agents
async function produceReport(topic: string): Promise<string> {
  console.log(`Starting research on: ${topic}`);

  // Step 1: Research
  console.log("Researcher agent working...");
  const research = await researcherAgent(topic);

  // Step 2: Write (uses researcher's output)
  console.log("Writer agent working...");
  const report = await writerAgent(topic, research);

  console.log("Report complete.");
  return report;
}

// Run it
produceReport("multi-agent AI systems").then(console.log);

Extensions to try:

  1. Add a Fact Checker Agent that reviews the report for accuracy before returning it
  2. Run 3 researchers in Promise.all() on different sub-topics, then combine in the writer
  3. Add a task queue so the orchestrator can track progress and retry failures
  4. Add a timeout to each agent — if research takes over 30 seconds, return partial results and continue

Key Takeaways

  • 1. Start with one agent, split when you feel it — the bottleneck between strategic and execution work is your signal
  • 2. Choose your team pattern deliberately — Hierarchical, Pipeline, Parallel, or Hybrid each fit different problems
  • 3. Delegation quality determines output quality — clear objective, relevant context, acceptance criteria, constraints
  • 4. Design for failure from the start — workers will timeout, produce wrong outputs, and conflict; your supervisor must handle all of it
  • 5. Keep roles narrow and well-defined — a specialist always outperforms a generalist on the specialist's domain
  • 6. Minimize shared state between agents — agents that operate independently are easier to debug, scale, and replace

You Now Have the Full Picture

You've gone from understanding what agents can do (Module 1), to building your first agent (Module 2), to autonomous decision-making (Module 3), integrating real tools (Module 4), a full case study (Module 5), and now multi-agent team architecture.

This is exactly how The Website runs. A CEO agent orchestrates a team of specialists — content writers, developers, growth strategists, code reviewers — all coordinated through a task API, all working in parallel, all producing real output.

Now build your team. Start with the two-agent exercise above, then expand to the structure that fits your problem. The principles don't change as you scale — just the number of agents and the complexity of coordination.

Back to Course