# Claude Agent SDK tutorial: build your own agent in TypeScript or Python

> The Claude Agent SDK is Claude Code as a library. Install `@anthropic-ai/claude-agent-sdk` for TypeScript or `claude-agent-sdk` for Python, call `query()` with a prompt and options, and read the stream of messages until a result arrives. Built-in tools, permissions, sessions and MCP support come with it. Use it when you want that agent loop inside your own program.

Mindket editors · Published 2026-11-04 · Updated 2026-11-05 · https://mindket.com/learn/claude-code-advanced/claude-agent-sdk

## In short

- `query()` returns an async stream that ends in a result message. Its `subtype` says whether the run succeeded or hit a limit, so check it before you read `result`.
- `allowedTools` pre-approves the tools you list and does not restrict the rest. Pair it with `permissionMode: "dontAsk"` for a locked-down agent, or use `disallowedTools` to remove a tool.
- The SDK loads your user, project and local settings by default, so the deny rules from the settings lesson apply to your agent. Pass `settingSources: []` to switch that off.
- Cap every production agent with `maxTurns` and `maxBudgetUsd`. A single-shot call raises after an error result, so keep the loop inside try and catch.

## The Agent SDK next to the other ways to run Claude

The Agent SDK puts the loop behind Claude Code into a library: the same built-in tools, permission system, sessions, hooks and MCP support, driven from your own Python or TypeScript code. The [GitHub Actions lesson](https://mindket.com/learn/claude-code-advanced/claude-code-github-actions) already used it, since the action is built on the SDK, and `claude -p` from the [headless lesson](https://mindket.com/learn/claude-code-advanced/claude-code-headless) is its command-line form. Anthropic's [overview](https://code.claude.com/docs/en/agent-sdk/overview) sorts the four options by who runs the agent.

The library runs in Python and TypeScript only. From another language, start the CLI as a subprocess with `-p` and `--output-format json`. For a single step in a script, `claude -p` is the smaller tool. Reach for the SDK when your own code has to answer approval prompts, define tools that run inside your process or keep sessions for several users.

Each language has its own repository on GitHub, where the changelog and issues live. On GitHub, the Python one has the larger following.

**The two SDK repositories on GitHub**

- **8.4k** stars on claude-agent-sdk-python (Source: [anthropics/claude-agent-sdk-python on GitHub](https://github.com/anthropics/claude-agent-sdk-python), read 2026-11-05)
- **1.4k** forks of the Python SDK (Source: [anthropics/claude-agent-sdk-python on GitHub](https://github.com/anthropics/claude-agent-sdk-python), read 2026-11-05)
- **1.9k** stars on claude-agent-sdk-typescript (Source: [anthropics/claude-agent-sdk-typescript on GitHub](https://github.com/anthropics/claude-agent-sdk-typescript), read 2026-11-05)
- **246** forks of the TypeScript SDK (Source: [anthropics/claude-agent-sdk-typescript on GitHub](https://github.com/anthropics/claude-agent-sdk-typescript), read 2026-11-05)

| You want to | Use | What you get |
| --- | --- | --- |
| Run Claude Code's agent inside your own app, in a process you operate | Agent SDK | A library with Claude Code's tools, permissions, sessions and hooks |
| Work interactively or run one-off tasks in a terminal | Claude Code CLI | The terminal interface built for daily use |
| Call the Claude API from your own code | Client SDK | Direct API access. You write the tool loop, or let the beta tool runner drive it |
| Have Anthropic host the agent | Managed Agents | Anthropic runs the agent loop for you, with sessions in its cloud sandbox or your own self-hosted one |

## Install it and run a first agent

You need Node.js 18.14 or newer, or Python 3.10 or newer, and an API key from the [Claude Console](https://platform.claude.com/settings/keys). Both packages bundle a native Claude Code binary, so most installs need no separate Claude Code. Anthropic's [quickstart](https://code.claude.com/docs/en/agent-sdk/quickstart) builds an agent that fixes two crashing functions in a file named `utils.py`. This is that agent in TypeScript.

The `prompt` is the task, `options` is the configuration and `query` returns the stream. Claude picks the tools. Here `allowedTools` pre-approves three of them and `acceptEdits` approves the file changes. The steps after the script install it and run it.

````typescript
import { query } from "@anthropic-ai/claude-agent-sdk";

// Agentic loop: streams messages as Claude works
for await (const message of query({
  prompt: "Review utils.py for bugs that would cause crashes. Fix any issues you find.",
  options: {
    allowedTools: ["Read", "Edit", "Glob"], // Auto-approve these tools
    permissionMode: "acceptEdits" // Auto-approve file edits
  }
})) {
  // Print human-readable output
  if (message.type === "assistant" && message.message?.content) {
    for (const block of message.message.content) {
      if ("text" in block) {
        console.log(block.text); // Claude's reasoning
      } else if ("name" in block) {
        console.log("Tool: " + block.name); // Tool being called
      }
    }
  } else if (message.type === "result") {
    console.log("Done: " + message.subtype); // Final result
  }
}
````

1. Make a folder and install: `npm init -y`, `npm pkg set type=module`, `npm install @anthropic-ai/claude-agent-sdk` and `npm install --save-dev tsx`. For Python, create a virtual environment and run `pip install claude-agent-sdk`, or use `uv add claude-agent-sdk`.
2. Export `ANTHROPIC_API_KEY` in the shell that runs the agent. The SDK reads the process environment and does not load `.env` files, so load one yourself with a package such as dotenv.
3. Save the script as `agent.ts` beside a `utils.py` with a function that crashes on an empty list, then run `npx tsx agent.ts`. The agent prints its reasoning and each tool it calls, and ends with `Done: success`.

| Concept | TypeScript | Python |
| --- | --- | --- |
| Options object | A plain object | `ClaudeAgentOptions` |
| Pre-approved tools | `allowedTools` | `allowed_tools` |
| Permission mode | `permissionMode` | `permission_mode` |
| Approval callback | `canUseTool` | `can_use_tool` |
| Turn and spend caps | `maxTurns`, `maxBudgetUsd` | `max_turns`, `max_budget_usd` |
| Settings to load | `settingSources` | `setting_sources` |
| Fork a session | `forkSession` | `fork_session` |
| Spot the result | `message.type === "result"` | `isinstance(message, ResultMessage)` |

> On Amazon Bedrock, Google Cloud's Agent Platform or Microsoft Foundry, set `CLAUDE_CODE_USE_BEDROCK=1`, `CLAUDE_CODE_USE_VERTEX=1` or `CLAUDE_CODE_USE_FOUNDRY=1` and configure that cloud's credentials. Claude Platform on AWS takes `CLAUDE_CODE_USE_ANTHROPIC_AWS=1` and `ANTHROPIC_AWS_WORKSPACE_ID`, with AWS credentials.

## Read the stream, then check the result

One `query()` call runs the whole loop. Claude answers or asks for a tool, the SDK runs it and feeds the output back, and this repeats until a reply has no tool calls. You receive a `system` message with the init data, an `assistant` message for each content block, a `user` message for each tool result and finally a `result`. Stream events join them only when you turn on partial messages. Anthropic's [agent loop page](https://code.claude.com/docs/en/agent-sdk/agent-loop) has the full list.

Iterate to the end instead of breaking on the result, because a few trailing system events can still arrive after it. Then branch on `subtype`. The loop below prints the text and the tool calls, and says what stopped the run.

````typescript
import { query } from "@anthropic-ai/claude-agent-sdk";

try {
  for await (const message of query({ prompt: "Summarize this project" })) {
    if (message.type === "assistant") {
      // Each assistant message carries one content block
      for (const block of message.message.content) {
        if (block.type === "text") {
          console.log("Claude: " + block.text);
        } else if (block.type === "tool_use") {
          console.log("Tool call: " + block.name);
        }
      }
    }
    if (message.type === "result") {
      if (message.subtype === "success") {
        console.log(message.result);
      } else {
        console.log("Stopped: " + message.subtype);
      }
    }
  }
} catch (error) {
  // A single-shot query() throws after yielding an error result.
  console.log("Session ended with an error: " + error);
}
````

- Every result carries `total_cost_usd`, `usage`, `num_turns` and `session_id`, even an error one, so you can log spend and resume. `usage` covers the main loop only. `modelUsage` covers the whole tree, subagents included.
- `maxTurns` counts each turn that calls tools plus one for the final text-only reply. With a cap of 2, the four-turn test fix in Anthropic's example would stop before the edit.
- `maxBudgetUsd` is checked after each response arrives, so spend can pass the cap by one response plus any subagents still running. Subagent spend counts toward it, and spawning another one after the cap fails with `Budget limit reached`. Those cap behaviors need Claude Code v2.1.217 or later.
- A single-shot `query()` yields the error result and then raises, so the try and catch above is the normal shape. To catch a refusal, test `stop_reason` for `refusal`.

| Subtype | What happened | `result` present |
| --- | --- | --- |
| `success` | Claude finished the task | Yes |
| `error_max_turns` | The `maxTurns` limit came first | No |
| `error_max_budget_usd` | The `maxBudgetUsd` limit came first | No |
| `error_during_execution` | An error interrupted the loop, such as a cancelled request | No |
| `error_max_structured_output_retries` | No valid structured output arrived within the retry limit | No |

## Permissions: what runs without asking

With Claude Code v2.1.302 or later, an SDK app starts in `default` mode unless you set a mode or its settings files do. In `default`, a call that needs approval is denied unless an allow rule, a hook or your callback approves it. A tool call that comes back denied in a headless run usually traces back to this.

Two options do most of the work. `allowedTools` auto-approves what it lists, and the other tools still exist: an unlisted tool falls through to the mode. `disallowedTools` is the block. A bare name such as `Bash` removes the tool from Claude's context, while `Bash(rm *)` leaves it available and denies matching calls in every mode as written, so `/bin/rm` slips past it. A scoped allow entry such as `Bash(npm test *)` works the same way in reverse and approves only matching calls.

For a locked-down agent, list the read tools and set `dontAsk`, so every call that would prompt is denied. Behind both options sits one fixed order, which [the permissions page](https://code.claude.com/docs/en/agent-sdk/permissions) lists and the steps below repeat.

````typescript
const options = {
  allowedTools: ["Read", "Glob", "Grep"],
  permissionMode: "dontAsk"
};
````

1. Hooks run first. A hook can deny a call, and a hook that allows it does not skip the deny and ask rules after it.
2. Deny rules, from `disallowedTools` or settings files. A match denies the call in every mode, `bypassPermissions` included.
3. Ask rules from settings files. A match sends the call to your callback, again even in `bypassPermissions`.
4. The permission mode. `acceptEdits` approves file edits and filesystem commands such as `mkdir`, `mv` and `cp` inside the working directory, and `bypassPermissions` approves what reaches it.
5. Allow rules, from `allowedTools` and settings files. A match approves the call.
6. Your `canUseTool` callback decides whatever is left. In `dontAsk` mode this step is skipped and the call is denied.

> `allowedTools` does not constrain `bypassPermissions`. With `allowedTools: ["Read"]` and that mode, every tool is approved, `Bash` included. TypeScript also needs `allowDangerouslySkipPermissions: true` for the mode, and on Linux and macOS it will not start as root outside a recognized sandbox.

## Approvals in your own code

Your callback fires when nothing earlier resolved the call, and when Claude uses the `AskUserQuestion` tool to put a question to the person. It receives the tool name and its input. It returns an allow, with optional edited input, or a deny with a message that Claude reads as the tool result. Execution waits until you answer. The full contract is on the [user input page](https://code.claude.com/docs/en/agent-sdk/user-input).

> Auto-approved tools never reach canUseTool.
>
> Anthropic, Agent SDK documentation, [Agent SDK docs: Configure permissions](https://code.claude.com/docs/en/agent-sdk/permissions) (read 2026-11-04)

````typescript
import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "Create a test file in /tmp and then delete it",
  options: {
    canUseTool: async (toolName, input) => {
      // Display the tool request
      console.log("Tool: " + toolName, input);

      // Ask the user with your own prompt helper
      const response = await prompt("Allow this action? (y/n): ");

      if (response.toLowerCase() === "y") {
        // Allow: the tool runs with the original (or modified) input
        return { behavior: "allow", updatedInput: input };
      }
      // Deny: the tool does not run, and Claude sees the message
      return { behavior: "deny", message: "User denied this action" };
    }
  }
})) {
  if ("result" in message) console.log(message.result);
}
````

- Put checks that must see every call in a `PreToolUse` hook. Hooks run before every other step, and a hook deny holds even in `bypassPermissions`.
- A callback can stay pending indefinitely. If a person may take longer than your process can live, return the `defer` decision from a `PreToolUse` hook, let the process exit and resume the saved session later.
- In Python the callback has a catch that the docs call a required workaround. Pass the prompt as an async generator that yields user messages, and add a `PreToolUse` hook that returns `{"continue_": True}` so the stream stays open.
- The TypeScript SDK prints a process warning with the code `CLAUDE_SDK_CAN_USE_TOOL_SHADOWED` once per query when `canUseTool` sits beside `bypassPermissions` or a bare tool name in `allowedTools`, because the callback will not see those calls.

## Give Claude a tool of your own

A custom tool has four parts: a unique name, a description Claude reads to decide when to call it, an input schema and an async handler. The schema is a Zod schema in TypeScript and a dict of types in Python. The handler returns a `content` array of result blocks. You wrap tools in an in-process MCP server, so nothing runs as a separate process. The [custom tools page](https://code.claude.com/docs/en/agent-sdk/custom-tools) has the Python version.

Pass the server in `mcpServers` and list each tool by its full name in `allowedTools`, here `mcp__weather__get_temperature`. That name joins the server key and the tool name with double underscores.

````typescript
import { query, tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
import { z } from "zod";

// Define a tool: name, description, input schema, handler
const getTemperature = tool(
  "get_temperature",
  "Get the current temperature at a location",
  {
    latitude: z.number().describe("Latitude coordinate"),
    longitude: z.number().describe("Longitude coordinate")
  },
  async (args) => {
    const response = await fetch(
      "https://api.open-meteo.com/v1/forecast?latitude=" + args.latitude +
        "&longitude=" + args.longitude +
        "&current=temperature_2m&temperature_unit=fahrenheit"
    );
    const data: any = await response.json();

    // Return a content array: Claude sees this as the tool result
    return {
      content: [{ type: "text", text: "Temperature: " + data.current.temperature_2m + " F" }]
    };
  }
);

// Wrap the tool in an in-process MCP server
const weatherServer = createSdkMcpServer({
  name: "weather",
  version: "1.0.0",
  tools: [getTemperature]
});

for await (const message of query({
  prompt: "What's the temperature in San Francisco?",
  options: {
    mcpServers: { weather: weatherServer },
    allowedTools: ["mcp__weather__get_temperature"]
  }
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}
````

- An uncaught exception inside a handler does not stop the loop. The server turns it into an error result carrying the raw message, and Claude can retry or explain. Catch it yourself and return `isError: true` when Claude needs a message it can act on, such as which request failed.
- Custom tools run one at a time by default. Set `readOnlyHint: true` in a tool's annotations to let Claude call it in parallel with other read-only tools.

## Attach MCP servers other people wrote

Servers you did not write go in the same `mcpServers` option. A stdio server takes a `command` and `args` and runs as a local process. A remote one takes `type: "http"` and a `url`, as in this example that connects Anthropic's documentation server. You can also keep the list in a `.mcp.json` at the project root, which loads through the `project` setting source. [The MCP page](https://code.claude.com/docs/en/agent-sdk/mcp) covers authentication and errors.

````typescript
import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "Use the docs MCP server to explain what hooks are in Claude Code",
  options: {
    mcpServers: {
      "claude-code-docs": {
        type: "http",
        url: "https://code.claude.com/docs/mcp"
      }
    },
    allowedTools: ["mcp__claude-code-docs__*"]
  }
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}
````

- MCP tools need explicit permission. Without it Claude sees them and cannot call them. `acceptEdits` does not cover them, and `bypassPermissions` does but also drops most other prompts, so list the tools in `allowedTools`.
- A wildcard works only after a literal `mcp__` and a server name. `mcp__github__*` approves that server's tools, while `["*"]` or `["mcp__*"]` in an allow list is ignored.
- A stdio server, or a remote one without a cached tool list, holds up the first turn until it connects, for 30 seconds by default (`MCP_TIMEOUT`). When tools seem missing, read each server's status in the init message.
- A dot or a space in a server key becomes an underscore in tool names, so `my.server` gives `mcp__my_server__list_issues`.

## Sessions: continue, resume and fork

A session is the conversation history, the prompt, every tool call and result and the replies, and the SDK writes it to disk without being asked. It stores the conversation and not your files, so use file checkpointing when you need to revert edits. Within one `query()` call the agent already takes as many turns as it needs, and approval prompts are handled in the loop. Sessions matter once separate prompts should share context, as [the sessions page](https://code.claude.com/docs/en/agent-sdk/sessions) describes.

````typescript
import { query } from "@anthropic-ai/claude-agent-sdk";

let sessionId: string | undefined;

// First run: read the session ID off the result message
for await (const message of query({
  prompt: "Analyze the auth module and suggest improvements",
  options: { allowedTools: ["Read", "Glob", "Grep"] }
})) {
  if (message.type === "result") sessionId = message.session_id;
}

// Later run: resume it, and the agent keeps the earlier analysis
for await (const message of query({
  prompt: "Now implement the refactoring you suggested",
  options: {
    resume: sessionId,
    allowedTools: ["Read", "Edit", "Write", "Glob", "Grep"]
  }
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}
````

- Forking copies the history into a new session and leaves the original untouched. It does not copy files, so a forked agent's edits are real for every session in that directory.
- Session files are local to the machine that wrote them, under `~/.claude/projects` in a folder named from the working directory. To resume on another host, attach a `sessionStore` adapter, or pass the results you need into a fresh session's prompt.
- After `error_max_turns` or `error_max_budget_usd`, resume the session with a higher limit.
- The experimental TypeScript V2 session API, `createSession()`, was removed in SDK 0.3.142. A tutorial that calls it needs `query()` with `continue` or `resume` instead.

| What you build | What to use |
| --- | --- |
| A one-shot task | One `query()` call and nothing else |
| A chat in one process | Python `ClaudeSDKClient`, or `continue: true` in TypeScript |
| Pick up after a restart | `continue_conversation=True` or `continue: true`, which resumes the newest session in the directory |
| One session per user | Capture the session ID and pass it to `resume` |
| Try another approach and keep the original | Fork it with `fork_session` or `forkSession` |
| Nothing written to disk | `persistSession: false` in TypeScript, or `CLAUDE_CODE_SKIP_PROMPT_HISTORY` in Python's `env` |

## What the SDK reads from disk

The SDK starts the Claude Code binary, so the files that shape Claude Code shape your agent unless you opt out.

- With `settingSources` omitted, `query()` loads user, project and local settings, the same as the CLI. Your `.claude/settings.json` allow, ask and deny rules and a `.mcp.json` apply, which is why the [settings lesson](https://mindket.com/learn/claude-code-advanced/claude-code-settings) matters here. CLAUDE.md files load when `project` is among the sources. Python narrows the default to user and project when you set `skills` and leave `setting_sources` unset.
- Pass `settingSources: []` for an agent that ignores all three. Managed policy settings still load, because they are not a source you can switch off.
- In TypeScript the default system prompt is minimal. Pass `{ type: "preset", preset: "claude_code" }` as `systemPrompt`, or `system_prompt` in Python, to use Claude Code's own, with an optional `append`.
- The `env` option replaces the subprocess environment in TypeScript, so pass `{ ...process.env, YOUR_VAR: "value" }` to keep `PATH`. In Python it merges on top of the inherited environment.
- For several tenants in one service, give each its own `settingSources`, `env` and `cwd`.

## Errors before the first message

- `CLINotFoundError` in Python means the SDK launched the CLI as a subprocess and found none. Platform wheels bundle it, but a source install, for example on ARM64 Windows, does not. Install Claude Code natively, confirm `claude --version` works where your app runs, or set `cli_path`. A service started outside your shell often has a different `PATH`.
- `Refusing to execute batch script` on Windows means the SDK will not run an npm `claude.cmd` shim, because `cmd.exe` re-parses arguments and could run injected commands. Point `cli_path` at a `claude.exe` or remove it so the bundled binary is used. The check arrived in `claude-agent-sdk` 0.2.124.
- In TypeScript, a message that the native CLI binary for your platform was not found means the install skipped optional dependencies, as `npm ci --omit=optional` does. Reinstall without skipping them, or set `pathToClaudeCodeExecutable`.
- A bare `ProcessError` in Python prints "Error output: Check stderr output for details", which is fixed text. Pass a `stderr` callback in the options to capture what the CLI wrote.
- Calling a `ClaudeSDKClient` method before it connects raises `Not connected. Call connect() first.` Open the client with `async with`, which connects on entry.
- `Not logged in` or `Invalid API key` usually means `ANTHROPIC_API_KEY` is not set in the environment of the process that runs the agent. Check that process, not your shell history.

## Boris Cherny used Lean to find bugs in the Agent SDK itself

Boris Cherny, who created Claude Code, posted [on X](https://x.com/bcherny/status/2102543349102338309) in September that he had used Opus 5.5 to formally verify the Agent SDK with Lean, a language for machine-checked proofs. A couple of short prompts produced 16 pull requests that fixed bugs and race conditions. He added that TLA+ works well too, and that he sometimes combines the two to look at data flow, concurrency and state. He said he knows neither language well.

Fixes like these ship in new SDK releases, so keep the package current with `npm update @anthropic-ai/claude-agent-sdk` or `pip install -U claude-agent-sdk`, and read the changelog first. The method also works on your own code: ask Claude to model the part of your agent that handles sessions or parallel tool calls, then look for the states your tests never reach.

For a longer walkthrough, Thariq Shihipar of Anthropic gave a workshop on the SDK, recorded by the AI Engineer channel.

> I used Opus 5.5 to formally verify the Claude Agent SDK using Lean. A couple short prompts = 16 PRs fixing various bugs and race conditions.
>
> Boris Cherny, Creator of Claude Code, at Anthropic, [X](https://x.com/bcherny/status/2102543349102338309) (read 2026-11-05)

[![Boris Cherny (@bcherny) on X, 22 September 2026: he used Opus 5.5 to formally verify the Claude Agent SDK using Lean, and a couple of short prompts gave 16 PRs fixing bugs and race conditions. TLA+ also works well.](https://mindket.com/blog/shots/x-bcherny-agent-sdk-lean.webp?v=05d5ce1672af)](https://x.com/bcherny/status/2102543349102338309)

Boris Cherny on X, 22 September 2026

[Claude Agent SDK [Full Workshop] — Thariq Shihipar, Anthropic](https://www.youtube.com/watch?v=TqC1qOfiVcQ)

Claude Agent SDK [Full Workshop] by Thariq Shihipar of Anthropic, on the AI Engineer channel on YouTube.

> A screenshot of X's own embed of the post, taken on 5 November 2026, with the time in UTC. X cuts the post short with Show more. Select it to open the post on X.

## Try it yourself

- Run the quickstart agent, then set `maxTurns` to 2 and read the result subtype. Raise it and compare.
- Switch to `permissionMode: "dontAsk"` with only `Read` allowed and ask for an edit. Watch the denial come back as a tool result and see what Claude does next.
- Add the weather tool, rename its server key to `my.weather` and work out the allowed tool name you now need.
- Capture a `session_id` from a result, resume it with a follow-up prompt, then fork it and compare the two IDs.

## Next course: Open-weight models

This lesson ran the agent on Claude in the cloud. The next course, [Open-weight models](https://mindket.com/learn/open-weight-models/what-are-open-weight-models), explains the models you can download and run yourself, and the Local AI course after it runs one with [Ollama](https://mindket.com/learn/local-ai/ollama-tutorial). The MCP course comes later. [Build an MCP server in Python](https://mindket.com/learn/mcp/build-mcp-server-python) writes a server that any agent can connect to, including one you run with this SDK.

Subagents work through the same options. The SDK takes an `agents` option that defines them in code, and the [subagents guide](https://mindket.com/blog/claude-code-subagents) covers when to split work that way.

## Check yourself

1. You set allowedTools to ["Read"] together with permissionMode "bypassPermissions". Which tools run without a prompt?

   A. Only Read
   B. Read and the other read-only tools
   C. Every tool, Bash and Edit included

   Answer: C. allowedTools only pre-approves what it lists, and bypassPermissions approves every call that reaches the mode step, so it does not constrain that mode.

2. What do you check on the final message of a query() loop before you read its result field?

   A. That its subtype is success
   B. That its session_id is set
   C. That its total_cost_usd is above zero

   Answer: A. Only the success variant carries result. The error subtypes, such as error_max_turns, have none.

3. In Python you set can_use_tool and pass a plain string as the prompt. What does the docs' pattern ask for instead?

   A. Switch the permission_mode to acceptEdits
   B. Add the callback to allowed_tools
   C. Set setting_sources to an empty list
   D. Pass the prompt as an async generator and add a PreToolUse hook that keeps the stream open

   Answer: D. The docs call the streaming prompt with a dummy PreToolUse hook a required workaround for can_use_tool in Python.

4. A custom tool get_temperature lives in an in-process server keyed weather. Which allowedTools entry pre-approves it?

   A. get_temperature
   B. mcp__weather__get_temperature
   C. weather.get_temperature

   Answer: B. MCP tool names join the server key and the tool name with double underscores after an mcp prefix.

## Frequently asked questions

### Is the Agent SDK the same as the Claude Code SDK?

The Agent SDK is the package you move to. Anthropic has a migration guide for the older Claude Code SDK packages, so a tutorial that imports those needs the guide first.

### How do I choose the model?

Set the `model` option to an alias such as `sonnet`, `opus` or `haiku`, or to a full model name. Without it the default from the CLI applies. A subagent can override it with the `model` field on its definition, and `inherit` uses the main model.

### Can my app sign users in with their Claude subscription?

Unless Anthropic has approved it in advance, third party developers may not offer claude.ai login or its rate limits in their products, and that includes agents built on the Agent SDK. Use API key authentication, or Bedrock, Vertex or Foundry credentials.

### What is the difference between query() and ClaudeSDKClient in Python?

`query()` starts a new session for each call and handles one exchange, without interrupts. `ClaudeSDKClient` keeps one session across exchanges and supports interrupts. That suits chat interfaces and work where the next step depends on Claude's answer. TypeScript has no client object and uses `continue: true`.

### How do I stream text as Claude writes it?

Partial messages do it. Once they are on, the stream adds `StreamEvent` messages that carry the raw API streaming events, such as text deltas. The option is `includePartialMessages` in TypeScript and `include_partial_messages` in Python.

### Can I call my product Claude Code?

No. Anthropic's branding guidelines allow "Claude Agent", or your own agent name followed by "Powered by Claude", and they do not permit "Claude Code" or "Claude Code Agent". Your product keeps its own branding.

### When is the Client SDK a better choice?

When you need one model call, or want to own the tool loop. It gives direct access to the Claude API, and you write the loop or use the beta tool runner. The Agent SDK ships the loop, so your time goes into tools and permissions instead.

## Sources

- [Claude Code docs: Agent SDK overview](https://code.claude.com/docs/en/agent-sdk/overview) (read 2026-11-05)
- [Claude Code docs: Agent SDK quickstart](https://code.claude.com/docs/en/agent-sdk/quickstart) (read 2026-11-05)
- [Claude Code docs: How the agent loop works](https://code.claude.com/docs/en/agent-sdk/agent-loop) (read 2026-11-04)
- [Claude Code docs: Configure permissions](https://code.claude.com/docs/en/agent-sdk/permissions) (read 2026-11-04)
- [Claude Code docs: Handle approvals and user input](https://code.claude.com/docs/en/agent-sdk/user-input) (read 2026-11-04)
- [Claude Code docs: Give Claude custom tools](https://code.claude.com/docs/en/agent-sdk/custom-tools) (read 2026-11-04)
- [Claude Code docs: Connect to external tools with MCP](https://code.claude.com/docs/en/agent-sdk/mcp) (read 2026-11-04)
- [Claude Code docs: Work with sessions](https://code.claude.com/docs/en/agent-sdk/sessions) (read 2026-11-04)
- [Claude Code docs: Agent SDK reference, TypeScript](https://code.claude.com/docs/en/agent-sdk/typescript) (read 2026-11-04)
- [Claude Code docs: Agent SDK reference, Python](https://code.claude.com/docs/en/agent-sdk/python) (read 2026-11-04)
- [anthropics/claude-agent-sdk-python on GitHub](https://github.com/anthropics/claude-agent-sdk-python) (read 2026-11-05)
- [anthropics/claude-agent-sdk-typescript on GitHub](https://github.com/anthropics/claude-agent-sdk-typescript) (read 2026-11-05)
- [Boris Cherny on X: formally verifying the Claude Agent SDK with Lean](https://x.com/bcherny/status/2102543349102338309) (read 2026-11-05)
- [AI Engineer on YouTube: Claude Agent SDK [Full Workshop], Thariq Shihipar](https://www.youtube.com/watch?v=TqC1qOfiVcQ) (read 2026-11-05)

[Browse skills](https://mindket.com/skills)
