Claude Agent SDK with TypeScript: Complete Guide

· 5 min read

Overview

The Claude Agent SDK is designed with TypeScript as a first-class citizen. Every API surface is fully typed, from agent definitions to tool schemas to orchestrator configurations. This means you get compile-time safety, IDE autocompletion, and self-documenting code when building multi-agent systems.

This guide walks through building a complete multi-agent system in TypeScript, covering project setup, agent definitions, typed tools, orchestration, error handling, and deployment considerations.

When to Use This Guide

This guide is for you if:

Getting Started: Project Setup

Initialize the Project

// package.json (key fields)
{
  "type": "module",
  "dependencies": {
    "@anthropic-ai/agent-sdk": "^1.0.0",
    "zod": "^3.23.0"
  },
  "devDependencies": {
    "typescript": "^5.5.0",
    "@types/node": "^20.0.0",
    "tsx": "^4.0.0"
  }
}
// tsconfig.json (key fields)
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src/**/*"]
}

Define Your First Typed Agent

import { Agent, AgentConfig } from "@anthropic-ai/agent-sdk";
import { z } from "zod";

// Define the output schema
const AnalysisResult = z.object({
  summary: z.string().describe("A 2-3 sentence summary of findings"),
  keyPoints: z.array(z.object({
    point: z.string(),
    confidence: z.number().min(0).max(1),
    evidence: z.string(),
  })).min(1).max(10),
  recommendation: z.enum(["proceed", "investigate-further", "abort"]),
  reasoning: z.string(),
});

type AnalysisResult = z.infer<typeof AnalysisResult>;

// Create the agent with typed output
const analysisAgent = new Agent<typeof AnalysisResult>({
  name: "analyst",
  model: "claude-sonnet-4-20250514",
  instructions: `You are a business analyst. Analyze the provided information and produce
a structured assessment. Be specific in your evidence and conservative in your confidence scores.`,
  outputSchema: AnalysisResult,
});

// The result is fully typed
const result = await analysisAgent.run("Analyze the Q3 market trends for SaaS...");
console.log(result.output.recommendation); // TypeScript knows this is "proceed" | "investigate-further" | "abort"
console.log(result.output.keyPoints[0].confidence); // TypeScript knows this is a number

Building Typed Tools

Tools are how agents interact with the outside world. The Claude Agent SDK uses Zod schemas to define tool inputs and outputs, giving you type safety throughout.

import { Tool } from "@anthropic-ai/agent-sdk";
import { z } from "zod";

const SearchInput = z.object({
  query: z.string().describe("The search query"),
  maxResults: z.number().min(1).max(20).default(5).describe("Maximum results to return"),
  domain: z.string().optional().describe("Restrict search to this domain"),
});

const SearchResult = z.object({
  results: z.array(z.object({
    title: z.string(),
    url: z.string().url(),
    snippet: z.string(),
    relevanceScore: z.number(),
  })),
  totalFound: z.number(),
});

const searchTool = new Tool({
  name: "web_search",
  description: "Search the web for information on a topic",
  inputSchema: SearchInput,
  outputSchema: SearchResult,
  execute: async (input): Promise<z.infer<typeof SearchResult>> => {
    // input is typed as { query: string; maxResults: number; domain?: string }
    const response = await fetch(`https://api.search.example.com/search?q=${encodeURIComponent(input.query)}&limit=${input.maxResults}`);
    const data = await response.json();
    return {
      results: data.results.map((r: any) => ({
        title: r.title,
        url: r.url,
        snippet: r.snippet,
        relevanceScore: r.score,
      })),
      totalFound: data.total,
    };
  },
});

Tool Composition

Build complex tools by composing simpler ones.

const databaseTool = new Tool({
  name: "query_database",
  description: "Query the product database",
  inputSchema: z.object({
    table: z.enum(["customers", "orders", "products"]),
    filters: z.record(z.string(), z.union([z.string(), z.number()])),
    limit: z.number().default(50),
  }),
  execute: async (input) => {
    // Type-safe database query
    const results = await db.select().from(tables[input.table]).where(
      Object.entries(input.filters).map(([k, v]) => eq(tables[input.table][k], v))
    ).limit(input.limit);
    return { rows: results, count: results.length };
  },
});

Multi-Agent Orchestration

The orchestrator coordinates multiple agents into a team. TypeScript ensures that agent configurations, handoff data, and workflow definitions are all type-checked.

import { Agent, Orchestrator, WorkflowStep } from "@anthropic-ai/agent-sdk";

// Define agents
const researcher = new Agent({
  name: "researcher",
  model: "claude-sonnet-4-20250514",
  instructions: "Research the topic using available tools. Produce structured findings.",
  tools: [searchTool, databaseTool],
  outputSchema: ResearchOutputSchema,
});

const writer = new Agent({
  name: "writer",
  model: "claude-sonnet-4-20250514",
  instructions: "Write a clear, well-structured report based on the research findings.",
  outputSchema: ReportSchema,
});

const reviewer = new Agent({
  name: "reviewer",
  model: "claude-sonnet-4-20250514",
  instructions: `Review the report for accuracy, completeness, and clarity.
If the report needs revision, specify exactly what needs to change.`,
  outputSchema: ReviewSchema,
});

// Define the workflow
const team = new Orchestrator({
  agents: [researcher, writer, reviewer],
  workflow: {
    type: "custom",
    steps: [
      { agent: "researcher" },
      { agent: "writer", dependsOn: ["researcher"] },
      {
        agent: "reviewer",
        dependsOn: ["writer"],
        review: {
          targetAgent: "writer",
          maxIterations: 2,
          passCondition: (review) => review.output.approved === true,
        },
      },
    ],
  },
  hooks: {
    onAgentStart: (agentName, input) => {
      console.log(`[${agentName}] Starting with input length: ${JSON.stringify(input).length}`);
    },
    onAgentComplete: (agentName, output, durationMs) => {
      console.log(`[${agentName}] Completed in ${durationMs}ms`);
    },
    onError: (agentName, error) => {
      console.error(`[${agentName}] Error:`, error.message);
    },
  },
});

const result = await team.run("Analyze the competitive landscape for AI developer tools in 2026");

Error Handling Patterns

Type-safe error handling ensures you account for all failure modes.

import { AgentError, ToolError, OrchestrationError } from "@anthropic-ai/agent-sdk";

try {
  const result = await team.run(input);
  if (result.status === "success") {
    return result.output;
  } else if (result.status === "partial") {
    console.warn("Some agents did not complete:", result.incompleteAgents);
    return result.partialOutput;
  }
} catch (error) {
  if (error instanceof ToolError) {
    console.error(`Tool "${error.toolName}" failed:`, error.message);
    // Retry with the tool disabled
  } else if (error instanceof AgentError) {
    console.error(`Agent "${error.agentName}" failed:`, error.message);
    // Fall back to a simpler workflow
  } else if (error instanceof OrchestrationError) {
    console.error("Workflow error:", error.message);
    // Log the full trace for debugging
    console.error("Trace:", error.trace);
  }
}

Integration with Agent Teams

The complete type safety of the Claude Agent SDK in TypeScript means that generated agent team configurations from Build Agents Store can be used as typed objects in your code. When you generate a team, you get not just prompts but a configuration that maps directly to SDK types.

This eliminates the gap between generating an agent team configuration and implementing it. The configuration is the implementation — import it, pass it to the Orchestrator, and run it. TypeScript's compiler verifies that all the pieces fit together before you ever execute the code.

Key TypeScript advantages for agent teams:

Skip the setup — generate agent teams instantly →