Week 3 · Day 12 of 40 · Build AI

Multi-agent systems and frameworks

You ship: A 4-agent pipeline for customer replies, with guardrails, handoffs and tracing, and an intake workflow. Builds on: Day 11.

What you'll build today

After Day 11, WorkBot has one agent that investigates a question on its own. Two other jobs need more structure. A message sent to WorkBot has to become a request in the queue, with a title, a team and a priority. A reply to a customer has to be checked for accuracy and safety before it goes out.

Today you build both. Intake is a plain function with 2 fixed steps, because a task whose steps never change does not need an agent. The reply pipeline runs 4 agents on the Claude Agent SDK, Anthropic's framework for agent systems. A researcher, a writer and a safety editor each do one part of the job, and an orchestrator runs them in order and sends drafts back for revision.

Along the way you learn how one agent hands work to another, and how guardrails written as code reject a bad result. By the end of the day, a message posted to WorkBot becomes a triaged request, and one command turns a customer's question into an approved, traced reply.

By the end of the day you can

  • Design multi-agent architectures for complex tasks
  • Use the Claude Agent SDK to build production agent systems
  • Know when to use a framework and when to build from scratch

Topics

Multi-Agent Patterns

  • Orchestrator: one "manager" agent delegates to specialist agents. It suits complex tasks with distinct sub-problems.
  • Pipeline: agents work in sequence, and Agent A's output feeds Agent B. It suits content creation and data processing.
  • Swarm: many agents work on sub-tasks in parallel, and their results are merged. It suits research and analysis.
  • Debate: agents argue different positions, and a judge agent picks the best. It suits decisions and evaluation.
  • When to use several agents: the task needs specialists, gains quality from different views, or splits into sub-tasks that can run in parallel

Agent Delegation and Handoffs

  • What context to pass between agents: the full context, a summary or structured data
  • Shared memory: how agents share findings and state
  • Handoff protocols: how Agent A tells Agent B what to do and what is already done
  • Coordination: avoid duplicate work, and merge results that conflict

Claude Agent SDK

  • What it is: Anthropic's official framework for building agent systems in TypeScript
  • Agent definition: instructions (the system prompt), tools and the model configuration
  • Guardrails: input validation rejects harmful inputs, and output validation checks the quality of a response
  • Handoffs: how agents pass control to each other
  • Tracing: built-in logging of every agent decision, tool call and handoff
  • The SDK or your own loop: use the SDK for production systems, and build from scratch to learn or for simple agents
  • Day 23 builds the same pipeline on LangGraph.js and the OpenAI Agents SDK

Framework Comparison

  • Claude Agent SDK: best when you build on Anthropic models for production, with guardrails and tracing built in
  • LangGraph: graph-based orchestration, state machines and checkpointing. It is best for complex workflows with conditional logic.
  • CrewAI: role-based agents with task assignment. It suits content pipelines.
  • Choosing: for most use cases, start with your model provider's agent SDK. That is the Claude Agent SDK today, and the OpenAI Agents SDK on Day 23. Reach for LangGraph when you need complex state machines.

Build

Features shipped today

  • WorkBot: The first workflows: intake, which triages a message into a request, and an explainer pipeline for customer replies, with a researcher, a writer and a safety editor

First build intake as a plain function: a small model triages a message, then WorkBot creates the request. Then build a multi-agent pipeline for customer replies on the Claude Agent SDK:

Agents

  1. Researcher: given a customer's question, searches the knowledge base, reads the policies that matter and lists the facts, each with its source
  2. Writer: takes the facts and writes the reply to the customer
  3. Safety editor: checks the draft for accuracy and safety. It approves the draft, or asks for specific, numbered edits.
  4. Orchestrator: runs the pipeline, passes context between the agents, and sends the draft back to the writer when the editor asks for revisions

Requirements

  • Build it on the Claude Agent SDK, with a proper definition for each agent
  • Add guardrails: the researcher must include sources, the writer must stay on topic, and the editor must give specific feedback
  • Add handoffs: researcher → writer → editor (→ back to the writer if revisions are needed)
  • Add tracing: log every agent's actions, so you can see the whole pipeline run
  • Use a different model per agent: the researcher uses Haiku (speed), and the writer and the editor use Sonnet (quality)

Walkthrough

Part 1

Share the knowledge tools

The pipeline's agents need the same knowledge base tools as Day 11's investigation agent, so you move those tools into a module of their own before anything else uses them.

Study first

  • Look again at the Tool type and the tool() helper from Day 7. The Agent SDK builds its tools from a Zod object schema's .shape, the map of its fields.

Build

  1. Write src/lib/knowledge-tools.ts with searchKnowledgeBase and readPolicy, built with the tool() helper, and make the investigation agent import them instead of defining them.
  2. Change the Tool type's input to a ZodObject, because the Agent SDK's tool() takes the schema's .shape.

Done when

  • pnpm test passes unchanged, and the investigation agent's tool list is 2 definitions shorter.

Part 2

The intake workflow

Intake has 2 steps in a fixed order, so you write it as a plain function rather than an agent. First a small model, Haiku from Anthropic's small tier, triages the message, and then WorkBot creates a request for a person to review.

Study first

  • Read the AI SDK's guide to generating structured data, which Day 10 used through generateText and Output.object. This time the field descriptions carry the business rules, such as which team owns what and what makes a priority high.

Build

  1. Write src/lib/intake.ts with a Triage schema (title, body, team, priority) whose descriptions say how to decide each field. triage(message, model) returns a Triage, and intake(message, model) parses that result through the request schema from Day 3 and creates the request.
  2. Add POST /api/intake, which takes { message }, 10 to 10,000 characters long, and answers 201 with the request. Its request_submitted event carries channel: "api".
  3. Write a unit test with a mock model, and a route test. Then add a live test on the small model that triages a real message about a printer. It asserts team === "operations", a high or normal priority, and a title that names the printer or its labels.

Done when

  • curl -X POST /api/intake with a message written like an email, greeting and sign-off included, creates a request on /requests.
  • The request's title is under 120 characters and names the issue, and the request names the team that owns it and has a priority.
A message triaged into the queue
A message posted to /api/intake comes back as a request. The small model wrote the title and kept the body in the sender's words, and the field descriptions chose the team and priority.
Technical notes
  • The schema's describe() strings are the only place the routing rules live, so changing who owns vendor questions is a one-line edit.
  • The small model triages, and the request schema validates what it returns. A title over 120 characters therefore fails before it reaches the database.
  • The route reuses the request's own event name with a channel property, so the intake funnel from Day 5 counts API intake alongside the form.

Part 3

Agents, hooks and guardrails

A reply to a customer goes through 4 agents. A researcher gathers the facts with their sources, a writer drafts the reply, and a safety editor approves the draft or sends it back with numbered edits. An orchestrator runs them in order and allows at most 2 revisions, after which the draft is either approved or left for a person to review. The researcher, the writer and the editor are subagents. A subagent is an agent with its own prompt, tools and model, which the orchestrator calls to do one part of the job.

Study first

  • Read the Claude Agent SDK overview for TypeScript. Its main call is query() with options, and its subagents are agents definitions, each with a description, prompt, tools and model.
  • Read how the SDK takes custom tools. createSdkMcpServer and tool serve them over an in-process Model Context Protocol (MCP) server, the protocol from Day 5, which runs inside your own process.
  • Read the SDK's page on hooks, which run before a tool call (PreToolUse) and after it (PostToolUse). A hook's return value can change the call. updatedInput on PreToolUse rewrites its input, and decision: "block" hands back a reason, which the orchestrator reads as feedback.

Build

  1. Run pnpm add @anthropic-ai/claude-agent-sdk. In src/lib/explainer.ts, serve the 2 knowledge tools to the SDK over an in-process MCP server named knowledge.
  2. Write 3 agent definitions. researcher runs on Haiku with the knowledge tools, and its prompt tells it to end every fact with its source in brackets. writer and editor run on Sonnet, Anthropic's large tier, with no tools, and the editor answers APPROVED alone or REVISE with numbered edits.
  3. Write the workflow as the orchestrator's system prompt. It runs the researcher, the writer and the editor, and goes back to the writer on REVISE, at most twice. It ends with APPROVED and the reply, or else with NOT APPROVED, the latest draft and the remaining edits, for a person to finish.
  4. Add 3 hooks. The orchestrator runs each subagent through the SDK's Agent tool, so 2 of the hooks watch that tool. foreground is a PreToolUse hook on the Agent tool that returns updatedInput with run_in_background: false, so the orchestrator gets each subagent's result rather than a task to wait for. guardrail is a PostToolUse hook on the same tool. It returns decision: "block" with a reason when a researcher output has any unsourced fact, or when an editor's REVISE has no numbered edits. record runs on both events and traces every tool call and handoff with its agent and time.
  5. Write tests that call the hooks directly.

Done when

  • pnpm test shows guardrail blocking an unsourced fact and a REVISE without numbered edits, and foreground setting run_in_background: false on an Agent call.
Technical notes
  • Write guardrails as code, not as prompt text. The PostToolUse hook checks a subagent's output after the Agent call returns, and decision: "block" with a reason hands that reason to the orchestrator as feedback on the call. The reason tells the orchestrator to run the agent again. The writer's on-topic guardrail is the editor's check that every claim traces to a fact.
  • Without the foreground hook, the orchestrator can start subagents in the background and go on with a task id instead of facts. In the reference run it did, which is why the hook sets run_in_background: false on every Agent call, so each subagent finishes first.
  • Pick each agent's model by its work. The researcher reads and lists, which Haiku is fast and cheap enough for, while writing and judging get Sonnet.

Part 4

Run and test the pipeline

With the agents and their guardrails defined, you wrap the pipeline in one function, run it from the command line and test it end to end.

Study first

  • Read the SDK's TypeScript reference for the messages that query() yields, and for the result message that ends a run with its cost and its number of turns.

Build

  1. Write explain(question, on, run, model?). on holds the trace and text callbacks, run is the SDK's query by default and a scripted generator in tests, and model overrides each agent's model. The function returns { approved, reply, trace, cost, turns }.
  2. Add pnpm explain "<question>", which prints the trace as it happens and then the reply.
  3. Write tests for 3 end-to-end cases with a scripted run, one approved, one not approved and one with an error.
  4. Add a live test that runs the real pipeline on Haiku. It checks that the researcher runs first, that the writer runs before the last editor, and that the reply contains 200.

Done when

  • pnpm explain "Why was my refund only $200 when I paid $250?" traces the researcher, the writer and the editor, and prints an approved reply that contains the $200 limit.
  • pnpm test:live passes.
The explainer pipeline
A real run on the small model traces each handoff and tool call with its agent and elapsed time, and the approved reply comes last.
Technical notes
  • The SDK uses the Claude Code sign-in on the machine, not ANTHROPIC_API_KEY, so the cost it reports comes out of that subscription's usage.
  • The model parameter overrides each agent's model, and the live test uses it to run the whole pipeline on Haiku.
  • This pattern is often taught as an article pipeline that searches the web. WorkBot's version writes customer replies, with the knowledge base in place of web search. Day 23 compares this SDK with other frameworks.
  • maxTurns: 24 bounds the orchestrator the way the Day 11 loop's step limit does.

Resources