Repository Public
1---2title: Programmatic tool calling3url: https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling4description: Let Claude call your tools from code in the code execution container, cutting model round trips and token use in multi-tool workflows.5---67## Compatibility8- [ZDR](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention): not eligible9- Supported models: `claude-fable-5-1`, `claude-mythos-5-1`, `claude-fable-5`, `claude-mythos-5`, `claude-opus-5`, `claude-opus-4-8`, `claude-opus-4-7`, `claude-opus-4-6`, `claude-opus-4-5-20251101`, `claude-sonnet-5`, `claude-sonnet-4-6`, `claude-sonnet-4-5-20250929`10- Platforms: Claude API, Claude Platform on AWS, Microsoft Foundry [1]; not available on Amazon Bedrock, Google Cloud11- Programmatic tool calling requires the code execution tool with the `code_execution_20260120` or later [tool version](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool#tool-versions).12- Claude Haiku 4.5 accepts the `code_execution_20260120` and later tool versions but doesn't support programmatic tool calling.131. On [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry), programmatic tool calling requires a [Hosted on Anthropic deployment](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry#additional-features-not-supported-when-hosted-on-azure).1415Programmatic tool calling allows Claude to write code that calls your tools programmatically within a [code execution](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool) container, rather than requiring round trips through the model for each tool invocation. This reduces latency for multi-tool workflows and decreases token consumption by allowing Claude to filter or process data before it reaches the model's context window. On agentic search benchmarks like [BrowseComp](https://arxiv.org/abs/2504.12516) and [DeepSearchQA](https://github.com/google-deepmind/deepsearchqa), which test multistep web research and complex information retrieval, adding programmatic tool calling on top of basic search tools improved performance by an average of 11% while using 24% fewer input tokens (see [Improved web search with dynamic filtering](https://claude.com/blog/improved-web-search-with-dynamic-filtering)).1617Consider checking budget compliance across 20 employees: the traditional approach requires 20 separate model round-trips, pulling thousands of expense line items into the context along the way. With programmatic tool calling, a single script runs all 20 lookups, filters the results, and returns only the employees who exceeded their limits, shrinking what Claude needs to reason over from hundreds of kilobytes down to a handful of lines.1819<Tip>20 For a deeper look at the inference and context costs that programmatic tool calling addresses, see [Advanced tool use](https://www.anthropic.com/engineering/advanced-tool-use).21</Tip>2223Programmatic tool calling requires the [code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool) with tool version `code_execution_20260120` or later.2425## Quick start2627Here's an example where Claude programmatically queries a database multiple times and aggregates results. Adding `allowed_callers: ["code_execution_20260120"]` to a tool definition is what makes that tool callable from within code execution (see [The `allowed_callers` field](https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling#the-allowed-callers-field)):2829<CodeGroup>30 ```bash cURL31 curl https://api.anthropic.com/v1/messages \32 --header "x-api-key: $ANTHROPIC_API_KEY" \33 --header "anthropic-version: 2023-06-01" \34 --header "content-type: application/json" \35 --data '{36 "model": "claude-opus-5",37 "max_tokens": 4096,38 "messages": [39 {40 "role": "user",41 "content": "Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue"42 }43 ],44 "tools": [45 {46 "type": "code_execution_20260120",47 "name": "code_execution"48 },49 {50 "name": "query_database",51 "description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",52 "input_schema": {53 "type": "object",54 "properties": {55 "sql": {56 "type": "string",57 "description": "SQL query to execute"58 }59 },60 "required": ["sql"]61 },62 "allowed_callers": ["code_execution_20260120"]63 }64 ]65 }'66 ```6768 ```bash CLI69 ant messages create <<'YAML'70 model: claude-opus-571 max_tokens: 409672 messages:73 - role: user74 content: >-75 Query sales data for the West, East, and Central regions, then76 tell me which region had the highest revenue77 tools:78 - type: code_execution_2026012079 name: code_execution80 - name: query_database81 description: >-82 Execute a SQL query against the sales database. Returns a list83 of rows as JSON objects.84 input_schema:85 type: object86 properties:87 sql:88 type: string89 description: SQL query to execute90 required:91 - sql92 allowed_callers:93 - code_execution_2026012094 YAML95 ```9697 ```python Python98 client = anthropic.Anthropic()99100 response = client.messages.create(101 model="claude-opus-5",102 max_tokens=4096,103 messages=[104 {105 "role": "user",106 "content": "Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue",107 }108 ],109 tools=[110 {"type": "code_execution_20260120", "name": "code_execution"},111 {112 "name": "query_database",113 "description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",114 "input_schema": {115 "type": "object",116 "properties": {117 "sql": {"type": "string", "description": "SQL query to execute"}118 },119 "required": ["sql"],120 },121 "allowed_callers": ["code_execution_20260120"],122 },123 ],124 )125126 print(response)127 ```128129 ```typescript TypeScript130 const client = new Anthropic();131132 const response = await client.messages.create({133 model: "claude-opus-5",134 max_tokens: 4096,135 messages: [136 {137 role: "user",138 content:139 "Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue"140 }141 ],142 tools: [143 {144 type: "code_execution_20260120",145 name: "code_execution"146 },147 {148 name: "query_database",149 description:150 "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",151 input_schema: {152 type: "object" as const,153 properties: {154 sql: {155 type: "string",156 description: "SQL query to execute"157 }158 },159 required: ["sql"]160 },161 allowed_callers: ["code_execution_20260120"]162 }163 ]164 });165166 console.log(response);167 ```168169 ```csharp C#170 AnthropicClient client = new();171172 var parameters = new MessageCreateParams173 {174 Model = Model.ClaudeOpus5,175 MaxTokens = 4096,176 Messages = [177 new() {178 Role = Role.User,179 Content = "Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue"180 }181 ],182 Tools = [183 new CodeExecutionTool20260120(),184 new ToolUnion(new Tool()185 {186 Name = "query_database",187 Description = "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",188 InputSchema = new InputSchema()189 {190 Properties = new Dictionary<string, JsonElement>191 {192 ["sql"] = JsonSerializer.SerializeToElement(new { type = "string", description = "SQL query to execute" }),193 },194 Required = ["sql"],195 },196 AllowedCallers = ["code_execution_20260120"]197 }),198 ]199 };200201 var message = await client.Messages.Create(parameters);202 Console.WriteLine(message);203 ```204205 ```go Go206 client := anthropic.NewClient()207208 response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{209 Model: anthropic.ModelClaudeOpus5,210 MaxTokens: 4096,211 Messages: []anthropic.MessageParam{212 anthropic.NewUserMessage(anthropic.NewTextBlock("Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue")),213 },214 Tools: []anthropic.ToolUnionParam{215 {OfCodeExecutionTool20260120: &anthropic.CodeExecutionTool20260120Param{}},216 {OfTool: &anthropic.ToolParam{217 Name: "query_database",218 Description: anthropic.String("Execute a SQL query against the sales database. Returns a list of rows as JSON objects."),219 InputSchema: anthropic.ToolInputSchemaParam{220 Properties: map[string]any{221 "sql": map[string]any{222 "type": "string",223 "description": "SQL query to execute",224 },225 },226 Required: []string{"sql"},227 },228 AllowedCallers: []string{"code_execution_20260120"},229 }},230 },231 })232 if err != nil {233 log.Fatal(err)234 }235 fmt.Println(response.RawJSON())236 ```237238 ```java Java239 import com.anthropic.models.messages.CodeExecutionTool20260120;240 // ...241242 void main() {243 AnthropicClient client = AnthropicOkHttpClient.fromEnv();244245 MessageCreateParams params = MessageCreateParams.builder()246 .model(Model.CLAUDE_OPUS_5)247 .maxTokens(4096L)248 .addUserMessage("Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue")249 .addTool(CodeExecutionTool20260120.builder().build())250 .addTool(Tool.builder()251 .name("query_database")252 .description("Execute a SQL query against the sales database. Returns a list of rows as JSON objects.")253 .inputSchema(InputSchema.builder()254 .properties(JsonValue.from(Map.of(255 "sql", Map.of(256 "type", "string",257 "description", "SQL query to execute"258 )259 )))260 .putAdditionalProperty("required", JsonValue.from(List.of("sql")))261 .build())262 .allowedCallers(List.of(Tool.AllowedCaller.of("code_execution_20260120")))263 .build())264 .build();265266 Message response = client.messages().create(params);267 IO.println(response);268 }269 ```270271 ```php PHP272 $client = new Client();273274 $message = $client->messages->create(275 maxTokens: 4096,276 messages: [277 ['role' => 'user', 'content' => 'Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue'],278 ],279 model: 'claude-opus-5',280 tools: [281 [282 'type' => 'code_execution_20260120',283 'name' => 'code_execution',284 ],285 [286 'name' => 'query_database',287 'description' => 'Execute a SQL query against the sales database. Returns a list of rows as JSON objects.',288 'input_schema' => [289 'type' => 'object',290 'properties' => [291 'sql' => [292 'type' => 'string',293 'description' => 'SQL query to execute',294 ],295 ],296 'required' => ['sql'],297 ],298 'allowed_callers' => ['code_execution_20260120'],299 ],300 ],301 );302303 echo $message;304 ```305306 ```ruby Ruby307 client = Anthropic::Client.new308309 message = client.messages.create(310 model: "claude-opus-5",311 max_tokens: 4096,312 messages: [313 {314 role: "user",315 content: "Query sales data for the West, East, and Central regions, then tell me which region had the highest revenue"316 }317 ],318 tools: [319 {320 type: "code_execution_20260120",321 name: "code_execution"322 },323 {324 name: "query_database",325 description: "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",326 input_schema: {327 type: "object",328 properties: {329 sql: {330 type: "string",331 description: "SQL query to execute"332 }333 },334 required: ["sql"]335 },336 allowed_callers: ["code_execution_20260120"]337 }338 ]339 )340341 puts message342 ```343</CodeGroup>344345The response stops with `stop_reason: "tool_use"`, a `container` ID, and a `tool_use` block for `query_database` whose `caller` field identifies the code execution run that called it. Return the result as shown in [Step 3 of the example workflow](https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling#step-3-provide-tool-result) so the code can finish.346347## How programmatic tool calling works348349When you configure a tool to be callable from code execution and Claude determines that tool is needed:3503511. Claude writes Python code that invokes the tool as a function, potentially including multiple tool calls and pre/post-processing logic3522. Claude runs this code in a sandboxed container through code execution3533. When a tool function is called, code execution pauses and the API returns a `tool_use` block3544. You provide the tool result, and code execution continues (intermediate results are not loaded into Claude's context window)3555. Once all code execution completes, Claude receives the final output and continues working on the task356357This approach is particularly useful for:358359* **Large data processing:** Filter or aggregate tool results before they reach Claude's context360* **Multistep workflows:** Save tokens and latency by calling tools serially or in a loop without sampling Claude in-between tool calls361* **Conditional logic:** Make decisions based on intermediate tool results362363<Note>364 Tools that allow a code execution caller are exposed to Claude's code as async Python functions, so Claude can run them in parallel with `asyncio.gather`. Each function takes a single dict of arguments and returns a string: the text of the `tool_result` you send back. Claude's code awaits these functions with top-level `await` and parses results that it needs as structured data, for example `rows = json.loads(await query_database({"sql": "<sql>"}))`.365</Note>366367## Core concepts368369### The `allowed_callers` field370371The `allowed_callers` field specifies which contexts can invoke a tool:372373```json374{375 "name": "query_database",376 "description": "Execute a SQL query against the database",377 "input_schema": {378 // ...379 },380 "allowed_callers": ["code_execution_20260120"]381}382```383384**Possible values:**385386* `["direct"]` - Claude is guided to call this tool directly (default if omitted)387* `["code_execution_20260120"]` - Claude is guided to call this tool only from within code execution388* `["direct", "code_execution_20260120"]` - Claude may call this tool directly or from within code execution389390Both `"code_execution_20260120"` and `"code_execution_20260521"` are accepted in `allowed_callers` and are interchangeable: a request using either code-execution tool version satisfies tools that list either caller. Response blocks always tag the caller as `code_execution_20260120` regardless of which version the request declared.391392<Tip>393 Choose either `["direct"]` or `["code_execution_20260120"]` for each tool rather than enabling both, as this provides clearer guidance to Claude for how best to use the tool.394</Tip>395396<Note>397 `allowed_callers` controls how the tool is presented to Claude and is validated against `tool_choice`, but it is not a hard API-level block on direct invocation. Claude is strongly guided to respect it, but your client should still be prepared to handle a direct `tool_use` for any tool it defines. Do not rely on `allowed_callers` as a security boundary.398</Note>399400### The `caller` field in responses401402Every tool use block includes a `caller` field indicating how it was invoked:403404**Direct invocation (traditional tool use):**405406```json407{408 "type": "tool_use",409 "id": "toolu_abc123",410 "name": "query_database",411 "input": { "sql": "<sql>" },412 "caller": { "type": "direct" }413}414```415416**Programmatic invocation:**417418```json419{420 "type": "tool_use",421 "id": "toolu_xyz789",422 "name": "query_database",423 "input": { "sql": "<sql>" },424 "caller": {425 "type": "code_execution_20260120",426 "tool_id": "srvtoolu_abc123"427 }428}429```430431The `tool_id` is the `id` of the code execution `server_tool_use` block that made the call, so you can match each programmatic `tool_use` to the code execution run that produced it.432433### Container lifecycle434435Programmatic tool calling uses the same containers as code execution:436437* **Container creation:** A new container is created for each request unless you reuse an existing one438* **Container ID:** Returned in responses in the `container` field, along with an `expires_at` timestamp439* **Reuse:** Pass the container ID back on the next request to keep state. While a programmatic tool call is waiting for your result, the container ID is required on that request, not optional: the API rejects the request without it.440* **Expiration:** `expires_at` tells you how long the container has left. Idle containers are currently reclaimed after about 5 minutes, and no container can be reused more than 30 days after it was created.441442<Warning>443 While Claude's code is waiting for a programmatic tool result, the pending call times out after about 4 minutes and raises a `TimeoutError` inside the code. Return each tool result well before the `expires_at` timestamp on the paused response. See [Container expiration during tool call](https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling#container-expiration-during-tool-call).444</Warning>445446## Example workflow447448Here's how a complete programmatic tool calling flow works:449450### Step 1: Initial request451452Send a request with code execution and a tool that allows programmatic calling. To enable programmatic calling, add the `allowed_callers` field to your tool definition.453454<Note>455 Provide detailed descriptions of your tool's output format in the tool description. If you specify that the tool returns JSON, Claude attempts to deserialize and process the result in code. The more detail you provide about the output schema, the better Claude can handle the response programmatically.456</Note>457458The request shape is identical to the [Quick start](https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling#quick-start) example: include `code_execution` in your tools list, add `allowed_callers: ["code_execution_20260120"]` to any tool you want Claude to invoke from code, and send your user message. The remaining steps in this workflow use the user message `"Query customer purchase history from the last quarter and identify our top 5 customers by revenue"`.459460### Step 2: API response with tool call461462Claude writes code that calls your tool. The API pauses and returns:463464```json Output465{466 "role": "assistant",467 "content": [468 {469 "type": "text",470 "text": "I'll query the purchase history and analyze the results."471 },472 {473 "type": "server_tool_use",474 "id": "srvtoolu_abc123",475 "name": "code_execution",476 "input": {477 "code": "import json\n\nrows = json.loads(await query_database({'sql': '<sql>'}))\ntop_customers = sorted(rows, key=lambda x: x['revenue'], reverse=True)[:5]\nprint(f'Top 5 customers: {top_customers}')"478 }479 },480 {481 "type": "tool_use",482 "id": "toolu_def456",483 "name": "query_database",484 "input": { "sql": "<sql>" },485 "caller": {486 "type": "code_execution_20260120",487 "tool_id": "srvtoolu_abc123"488 }489 }490 ],491 "container": {492 "id": "container_xyz789",493 "expires_at": "2026-01-20T14:30:00Z"494 },495 "stop_reason": "tool_use"496}497```498499### Step 3: Provide tool result500501Send the full conversation history plus your tool result. Three details matter on this request:502503* The user message that carries your result can contain only `tool_result` blocks. See [Message formatting restrictions](https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling#message-formatting-restrictions).504* Pass the `container` ID from the paused response. The API rejects a continuation that has pending programmatic tool calls but no container ID.505* Send the same `tools` array as the original request. The code execution tool must still be present for the paused code to resume, and the tools you send on this request are the definitions Claude and the running code can use for the rest of the turn.506507<CodeGroup>508 ```bash cURL509 curl https://api.anthropic.com/v1/messages \510 --header "x-api-key: $ANTHROPIC_API_KEY" \511 --header "anthropic-version: 2023-06-01" \512 --header "content-type: application/json" \513 --data '{514 "model": "claude-opus-5",515 "max_tokens": 4096,516 "container": "container_xyz789",517 "messages": [518 {519 "role": "user",520 "content": "Query customer purchase history from the last quarter and identify our top 5 customers by revenue"521 },522 {523 "role": "assistant",524 "content": [525 {526 "type": "text",527 "text": "I'\''ll query the purchase history and analyze the results."528 },529 {530 "type": "server_tool_use",531 "id": "srvtoolu_abc123",532 "name": "code_execution",533 "input": {"code": "..."}534 },535 {536 "type": "tool_use",537 "id": "toolu_def456",538 "name": "query_database",539 "input": {"sql": "<sql>"},540 "caller": {541 "type": "code_execution_20260120",542 "tool_id": "srvtoolu_abc123"543 }544 }545 ]546 },547 {548 "role": "user",549 "content": [550 {551 "type": "tool_result",552 "tool_use_id": "toolu_def456",553 "content": "[{\"customer_id\": \"C1\", \"revenue\": 45000}, {\"customer_id\": \"C2\", \"revenue\": 38000}]"554 }555 ]556 }557 ],558 "tools": [559 {560 "type": "code_execution_20260120",561 "name": "code_execution"562 },563 {564 "name": "query_database",565 "description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",566 "input_schema": {567 "type": "object",568 "properties": {569 "sql": {570 "type": "string",571 "description": "SQL query to execute"572 }573 },574 "required": ["sql"]575 },576 "allowed_callers": ["code_execution_20260120"]577 }578 ]579 }'580 ```581582 ```bash CLI583 ant messages create <<'YAML'584 model: claude-opus-5585 max_tokens: 4096586 container: container_xyz789587 messages:588 - role: user589 content: >-590 Query customer purchase history from the last quarter and identify our591 top 5 customers by revenue592 - role: assistant593 content:594 - type: text595 text: I'll query the purchase history and analyze the results.596 - type: server_tool_use597 id: srvtoolu_abc123598 name: code_execution599 input:600 code: "..."601 - type: tool_use602 id: toolu_def456603 name: query_database604 input:605 sql: "<sql>"606 caller:607 type: code_execution_20260120608 tool_id: srvtoolu_abc123609 - role: user610 content:611 - type: tool_result612 tool_use_id: toolu_def456613 content: >-614 [{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2",615 "revenue": 38000}, ...]616 # Same tools array as the original request617 tools:618 - type: code_execution_20260120619 name: code_execution620 - name: query_database621 description: >-622 Execute a SQL query against the sales database. Returns a list623 of rows as JSON objects.624 input_schema:625 type: object626 properties:627 sql:628 type: string629 description: SQL query to execute630 required:631 - sql632 allowed_callers:633 - code_execution_20260120634 YAML635 ```636637 ```python Python638 response = client.messages.create(639 model="claude-opus-5",640 max_tokens=4096,641 container="container_xyz789", # Reuse the container642 messages=[643 {644 "role": "user",645 "content": "Query customer purchase history from the last quarter and identify our top 5 customers by revenue",646 },647 {648 "role": "assistant",649 "content": [650 {651 "type": "text",652 "text": "I'll query the purchase history and analyze the results.",653 },654 {655 "type": "server_tool_use",656 "id": "srvtoolu_abc123",657 "name": "code_execution",658 "input": {"code": "..."},659 },660 {661 "type": "tool_use",662 "id": "toolu_def456",663 "name": "query_database",664 "input": {"sql": "<sql>"},665 "caller": {666 "type": "code_execution_20260120",667 "tool_id": "srvtoolu_abc123",668 },669 },670 ],671 },672 {673 "role": "user",674 "content": [675 {676 "type": "tool_result",677 "tool_use_id": "toolu_def456",678 "content": '[{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2", "revenue": 38000}, ...]',679 }680 ],681 },682 ],683 # Same tools array as the original request684 tools=[685 {"type": "code_execution_20260120", "name": "code_execution"},686 {687 "name": "query_database",688 "description": "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",689 "input_schema": {690 "type": "object",691 "properties": {692 "sql": {"type": "string", "description": "SQL query to execute"}693 },694 "required": ["sql"],695 },696 "allowed_callers": ["code_execution_20260120"],697 },698 ],699 )700701 print(response)702 ```703704 ```typescript TypeScript705 const response = await client.messages.create({706 model: "claude-opus-5",707 max_tokens: 4096,708 container: "container_xyz789", // Reuse the container709 messages: [710 {711 role: "user",712 content:713 "Query customer purchase history from the last quarter and identify our top 5 customers by revenue"714 },715 {716 role: "assistant",717 content: [718 { type: "text", text: "I'll query the purchase history and analyze the results." },719 {720 type: "server_tool_use",721 id: "srvtoolu_abc123",722 name: "code_execution",723 input: { code: "..." }724 },725 {726 type: "tool_use",727 id: "toolu_def456",728 name: "query_database",729 input: { sql: "<sql>" },730 caller: {731 type: "code_execution_20260120",732 tool_id: "srvtoolu_abc123"733 }734 }735 ]736 },737 {738 role: "user",739 content: [740 {741 type: "tool_result",742 tool_use_id: "toolu_def456",743 content:744 '[{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2", "revenue": 38000}, ...]'745 }746 ]747 }748 ],749 // Same tools array as the original request750 tools: [751 {752 type: "code_execution_20260120",753 name: "code_execution"754 },755 {756 name: "query_database",757 description:758 "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",759 input_schema: {760 type: "object" as const,761 properties: {762 sql: {763 type: "string",764 description: "SQL query to execute"765 }766 },767 required: ["sql"]768 },769 allowed_callers: ["code_execution_20260120"]770 }771 ]772 });773774 console.log(response);775 ```776777 ```csharp C#778 AnthropicClient client = new();779780 var parameters = new MessageCreateParams781 {782 Model = Model.ClaudeOpus5,783 MaxTokens = 4096,784 Container = "container_xyz789",785 Messages =786 [787 new()788 {789 Role = Role.User,790 Content = "Query customer purchase history from the last quarter and identify our top 5 customers by revenue"791 },792 new()793 {794 Role = Role.Assistant,795 Content = new ContentBlock[]796 {797 new TextBlock { Text = "I'll query the purchase history and analyze the results." },798 new ServerToolUseBlock799 {800 Id = "srvtoolu_abc123",801 Name = "code_execution",802 Input = new { code = "..." }803 },804 new ToolUseBlock805 {806 Id = "toolu_def456",807 Name = "query_database",808 Input = new { sql = "<sql>" },809 Caller = new ToolCaller810 {811 Type = "code_execution_20260120",812 ToolId = "srvtoolu_abc123"813 }814 }815 }816 },817 new()818 {819 Role = Role.User,820 Content = new ContentBlockParam[]821 {822 new ToolResultBlockParam823 {824 ToolUseID = "toolu_def456",825 Content = "[{\"customer_id\": \"C1\", \"revenue\": 45000}, {\"customer_id\": \"C2\", \"revenue\": 38000}, ...]"826 }827 }828 }829 ],830 // Same tools array as the original request831 Tools = [832 new CodeExecutionTool20260120(),833 new ToolUnion(new Tool()834 {835 Name = "query_database",836 Description = "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",837 InputSchema = new InputSchema()838 {839 Properties = new Dictionary<string, JsonElement>840 {841 ["sql"] = JsonSerializer.SerializeToElement(new { type = "string", description = "SQL query to execute" }),842 },843 Required = ["sql"],844 },845 AllowedCallers = ["code_execution_20260120"]846 }),847 ]848 };849850 var message = await client.Messages.Create(parameters);851 Console.WriteLine(message);852 ```853854 ```go Go855 client := anthropic.NewClient()856857 response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{858 Model: anthropic.ModelClaudeOpus5,859 MaxTokens: 4096,860 Container: anthropic.MessageCreateParamsContainerUnion{861 OfString: anthropic.String("container_xyz789"),862 },863 Messages: []anthropic.MessageParam{864 anthropic.NewUserMessage(anthropic.NewTextBlock("Query customer purchase history from the last quarter and identify our top 5 customers by revenue")),865 {866 Role: anthropic.MessageParamRoleAssistant,867 Content: []anthropic.ContentBlockParamUnion{868 anthropic.NewTextBlock("I'll query the purchase history and analyze the results."),869 {OfServerToolUse: &anthropic.ServerToolUseBlockParam{870 ID: "srvtoolu_abc123",871 Name: anthropic.ServerToolUseBlockParamNameCodeExecution,872 Input: map[string]any{"code": "..."},873 }},874 {OfToolUse: &anthropic.ToolUseBlockParam{875 ID: "toolu_def456",876 Name: "query_database",877 Input: map[string]any{"sql": "<sql>"},878 Caller: anthropic.ServerToolUseBlockParamCallerUnion{879 OfCodeExecution20260120: &anthropic.ServerToolCaller20260120Param{880 ToolID: "srvtoolu_abc123",881 },882 },883 }},884 },885 },886 {887 Role: anthropic.MessageParamRoleUser,888 Content: []anthropic.ContentBlockParamUnion{889 {OfToolResult: &anthropic.ToolResultBlockParam{890 ToolUseID: "toolu_def456",891 Content: []anthropic.ToolResultBlockParamContentUnion{892 {OfText: &anthropic.TextBlockParam{893 Text: `[{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2", "revenue": 38000}, ...]`,894 }},895 },896 }},897 },898 },899 },900 // Same tools array as the original request901 Tools: []anthropic.ToolUnionParam{902 {OfCodeExecutionTool20260120: &anthropic.CodeExecutionTool20260120Param{}},903 {OfTool: &anthropic.ToolParam{904 Name: "query_database",905 Description: anthropic.String("Execute a SQL query against the sales database. Returns a list of rows as JSON objects."),906 InputSchema: anthropic.ToolInputSchemaParam{907 Properties: map[string]any{908 "sql": map[string]any{909 "type": "string",910 "description": "SQL query to execute",911 },912 },913 Required: []string{"sql"},914 },915 AllowedCallers: []string{"code_execution_20260120"},916 }},917 },918 })919 if err != nil {920 log.Fatal(err)921 }922 fmt.Println(response.RawJSON())923 ```924925 ```java Java926 import com.anthropic.models.messages.CodeExecutionTool20260120;927 // ...928929 void main() {930 AnthropicClient client = AnthropicOkHttpClient.fromEnv();931932 MessageCreateParams params = MessageCreateParams.builder()933 .model(Model.CLAUDE_OPUS_5)934 .maxTokens(4096L)935 .container("container_xyz789")936 .addUserMessage("Query customer purchase history from the last quarter and identify our top 5 customers by revenue")937 .addAssistantMessageOfBlockParams(List.of(938 ContentBlockParam.ofText(939 TextBlockParam.builder()940 .text("I'll query the purchase history and analyze the results.")941 .build()),942 ContentBlockParam.ofServerToolUse(943 ServerToolUseBlockParam.builder()944 .id("srvtoolu_abc123")945 .name("code_execution")946 .input(JsonValue.from(Map.of("code", "...")))947 .build()),948 ContentBlockParam.ofToolUse(949 ToolUseBlockParam.builder()950 .id("toolu_def456")951 .name("query_database")952 .input(JsonValue.from(Map.of("sql", "<sql>")))953 .codeExecution20260120Caller("srvtoolu_abc123")954 .build())955 ))956 .addUserMessageOfBlockParams(List.of(957 ContentBlockParam.ofToolResult(958 ToolResultBlockParam.builder()959 .toolUseId("toolu_def456")960 .content("[{\"customer_id\": \"C1\", \"revenue\": 45000}, {\"customer_id\": \"C2\", \"revenue\": 38000}, ...]")961 .build())962 ))963 // Same tools array as the original request964 .addTool(CodeExecutionTool20260120.builder().build())965 .addTool(Tool.builder()966 .name("query_database")967 .description("Execute a SQL query against the sales database. Returns a list of rows as JSON objects.")968 .inputSchema(InputSchema.builder()969 .properties(JsonValue.from(Map.of(970 "sql", Map.of(971 "type", "string",972 "description", "SQL query to execute"973 )974 )))975 .putAdditionalProperty("required", JsonValue.from(List.of("sql")))976 .build())977 .allowedCallers(List.of(Tool.AllowedCaller.of("code_execution_20260120")))978 .build())979 .build();980981 Message response = client.messages().create(params);982 IO.println(response);983 }984 ```985986 ```php PHP987 $client = new Client();988989 $message = $client->messages->create(990 maxTokens: 4096,991 messages: [992 [993 'role' => 'user',994 'content' => 'Query customer purchase history from the last quarter and identify our top 5 customers by revenue',995 ],996 [997 'role' => 'assistant',998 'content' => [999 [1000 'type' => 'text',1001 'text' => "I'll query the purchase history and analyze the results.",1002 ],1003 [1004 'type' => 'server_tool_use',1005 'id' => 'srvtoolu_abc123',1006 'name' => 'code_execution',1007 'input' => ['code' => '...'],1008 ],1009 [1010 'type' => 'tool_use',1011 'id' => 'toolu_def456',1012 'name' => 'query_database',1013 'input' => ['sql' => '<sql>'],1014 'caller' => [1015 'type' => 'code_execution_20260120',1016 'tool_id' => 'srvtoolu_abc123',1017 ],1018 ],1019 ],1020 ],1021 [1022 'role' => 'user',1023 'content' => [1024 [1025 'type' => 'tool_result',1026 'tool_use_id' => 'toolu_def456',1027 'content' => '[{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2", "revenue": 38000}, ...]',1028 ],1029 ],1030 ],1031 ],1032 model: 'claude-opus-5',1033 container: 'container_xyz789',1034 // Same tools array as the original request1035 tools: [1036 [1037 'type' => 'code_execution_20260120',1038 'name' => 'code_execution',1039 ],1040 [1041 'name' => 'query_database',1042 'description' => 'Execute a SQL query against the sales database. Returns a list of rows as JSON objects.',1043 'input_schema' => [1044 'type' => 'object',1045 'properties' => [1046 'sql' => [1047 'type' => 'string',1048 'description' => 'SQL query to execute',1049 ],1050 ],1051 'required' => ['sql'],1052 ],1053 'allowed_callers' => ['code_execution_20260120'],1054 ],1055 ],1056 );10571058 echo $message;1059 ```10601061 ```ruby Ruby1062 require "anthropic"10631064 client = Anthropic::Client.new10651066 message = client.messages.create(1067 model: "claude-opus-5",1068 max_tokens: 4096,1069 container: "container_xyz789",1070 messages: [1071 {1072 role: "user",1073 content: "Query customer purchase history from the last quarter and identify our top 5 customers by revenue"1074 },1075 {1076 role: "assistant",1077 content: [1078 {1079 type: "text",1080 text: "I'll query the purchase history and analyze the results."1081 },1082 {1083 type: "server_tool_use",1084 id: "srvtoolu_abc123",1085 name: "code_execution",1086 input: { code: "..." }1087 },1088 {1089 type: "tool_use",1090 id: "toolu_def456",1091 name: "query_database",1092 input: { sql: "<sql>" },1093 caller: {1094 type: "code_execution_20260120",1095 tool_id: "srvtoolu_abc123"1096 }1097 }1098 ]1099 },1100 {1101 role: "user",1102 content: [1103 {1104 type: "tool_result",1105 tool_use_id: "toolu_def456",1106 content: '[{"customer_id": "C1", "revenue": 45000}, {"customer_id": "C2", "revenue": 38000}, ...]'1107 }1108 ]1109 }1110 ],1111 # Same tools array as the original request1112 tools: [1113 {1114 type: "code_execution_20260120",1115 name: "code_execution"1116 },1117 {1118 name: "query_database",1119 description: "Execute a SQL query against the sales database. Returns a list of rows as JSON objects.",1120 input_schema: {1121 type: "object",1122 properties: {1123 sql: {1124 type: "string",1125 description: "SQL query to execute"1126 }1127 },1128 required: ["sql"]1129 },1130 allowed_callers: ["code_execution_20260120"]1131 }1132 ]1133 )11341135 puts message1136 ```1137</CodeGroup>11381139### Step 4: Next tool call or completion11401141The code picks up where it paused and processes your result. Each continuation response either pauses again with more programmatic `tool_use` blocks, or completes the code execution and lets Claude continue the turn (Step 5). Check `stop_reason` and each `tool_use` block's `caller` to tell the two apart: a response that pauses for you has `stop_reason: "tool_use"` and a `tool_use` block whose `caller` names a code execution version, and you repeat Step 3 with a `tool_result` for every pending programmatic call in one user message.11421143### Step 5: Final response11441145Once the code execution completes, Claude provides the final response:11461147```json Output1148{1149 "content": [1150 {1151 "type": "code_execution_tool_result",1152 "tool_use_id": "srvtoolu_abc123",1153 "content": {1154 "type": "code_execution_result",1155 "stdout": "Top 5 customers: [{'customer_id': 'C1', 'revenue': 45000}, {'customer_id': 'C2', 'revenue': 38000}, {'customer_id': 'C5', 'revenue': 32000}, {'customer_id': 'C8', 'revenue': 28500}, {'customer_id': 'C3', 'revenue': 24000}]",1156 "stderr": "",1157 "return_code": 0,1158 "content": []1159 }1160 },1161 {1162 "type": "text",1163 "text": "I've analyzed the purchase history from last quarter. Your top 5 customers generated $167,500 in total revenue, with Customer C1 leading at $45,000."1164 }1165 ],1166 "stop_reason": "end_turn"1167}1168```11691170## Advanced patterns11711172### Batch processing with loops11731174Claude can write code that processes multiple items efficiently:11751176```python1177regions = ["West", "East", "Central", "North", "South"]1178results = {}1179for region in regions:1180 rows = json.loads(await query_database({"sql": f"<sql for {region}>"}))1181 results[region] = sum(row["revenue"] for row in rows)11821183# Process results programmatically1184top_region = max(results.items(), key=lambda x: x[1])1185print(f"Top region: {top_region[0]} with ${top_region[1]:,} in revenue")1186```11871188This pattern:11891190* Reduces model round-trips from N (one per region) to 11191* Processes large result sets programmatically before returning to Claude1192* Saves tokens by only returning aggregated conclusions instead of raw data11931194### Early termination11951196Claude can stop processing as soon as success criteria are met:11971198```python1199endpoints = ["us-east", "eu-west", "apac"]1200for endpoint in endpoints:1201 status = await check_health({"endpoint": endpoint})1202 if status == "healthy":1203 print(f"Found healthy endpoint: {endpoint}")1204 break # Stop early, don't check remaining1205```12061207### Conditional tool selection12081209```python1210path = "/tmp/example.txt"1211file_info = json.loads(await get_file_info({"path": path}))1212if file_info["size"] < 10000:1213 content = await read_full_file({"path": path})1214else:1215 content = await read_file_summary({"path": path})1216print(content)1217```12181219### Data filtering12201221```python1222server_id = "srv-01"1223log_text = await fetch_logs({"server_id": server_id})1224errors = [line for line in log_text.splitlines() if "ERROR" in line]1225print(f"Found {len(errors)} errors")1226for error in errors[-10:]: # Only return last 10 errors1227 print(error)1228```12291230## Response format12311232### Programmatic tool call12331234When code execution calls a tool:12351236```json1237{1238 "type": "tool_use",1239 "id": "toolu_abc123",1240 "name": "query_database",1241 "input": { "sql": "<sql>" },1242 "caller": {1243 "type": "code_execution_20260120",1244 "tool_id": "srvtoolu_xyz789"1245 }1246}1247```12481249### Tool result handling12501251Your tool result is passed back to the running code:12521253```json1254{1255 "role": "user",1256 "content": [1257 {1258 "type": "tool_result",1259 "tool_use_id": "toolu_abc123",1260 "content": "[{\"customer_id\": \"C1\", \"revenue\": 45000, \"orders\": 23}, {\"customer_id\": \"C2\", \"revenue\": 38000, \"orders\": 18}, ...]"1261 }1262 ]1263}1264```12651266### Code execution completion12671268When all tool calls are satisfied and code completes:12691270```json1271{1272 "type": "code_execution_tool_result",1273 "tool_use_id": "srvtoolu_xyz789",1274 "content": {1275 "type": "code_execution_result",1276 "stdout": "Analysis complete. Top 5 customers identified from 847 total records.",1277 "stderr": "",1278 "return_code": 0,1279 "content": []1280 }1281}1282```12831284## Error handling12851286### Common errors12871288| Error | Where it appears | Description | Solution |1289| ------------------------------------------ | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- |1290| `invalid_tool_input` | `error_code` on the `code_execution_tool_result` error block in the response | Invalid parameters were passed to the code execution tool | See the [code execution tool errors](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool#errors) |1291| `invalid_request_error` (on `tool_choice`) | HTTP 400 error response | `tool_choice` names a tool whose `allowed_callers` does not include `"direct"` | Either add `"direct"` to that tool's `allowed_callers`, or remove the tool from `tool_choice` and let Claude invoke it from code |12921293### Container expiration during tool call12941295If your tool result doesn't arrive within about 4 minutes, the pending call raises a `TimeoutError` inside Claude's running code. Claude sees the error in `stderr` and typically retries the call:12961297```json1298{1299 "type": "code_execution_tool_result",1300 "tool_use_id": "srvtoolu_abc123",1301 "content": {1302 "type": "code_execution_result",1303 "stdout": "",1304 "stderr": "TimeoutError: Calling tool ['query_database'] timed out (no response after 270s).",1305 "return_code": 0,1306 "content": []1307 }1308}1309```13101311To prevent timeouts:13121313* Monitor the `expires_at` field in responses1314* Implement timeouts for your tool execution1315* Consider breaking long operations into smaller chunks13161317### Tool execution errors13181319If your tool returns an error:13201321```json1322{1323 "type": "tool_result",1324 "tool_use_id": "toolu_abc123",1325 "content": "Error: Query timeout - table lock exceeded 30 seconds"1326}1327```13281329Claude's code receives this error and can handle it appropriately.13301331## Constraints and limitations13321333### Feature incompatibilities13341335* **Structured outputs:** Tools with `strict: true` are not supported with programmatic calling1336* **Tool choice:** You cannot force programmatic calling of a specific tool through `tool_choice`1337* **Parallel tool use:** `disable_parallel_tool_use: true` is not supported with programmatic calling13381339### Input schema limitations13401341Custom tools whose `input_schema` contains a recursive `$ref` (a reference cycle, such as a schema that refers to itself) cannot be enabled for programmatic calling. Including a code execution tool version in `allowed_callers` for such a tool causes the request to fail with a `400 invalid_request_error` whose message contains `Circular $ref detected`. The same schema is accepted for direct tool calling.13421343To work around this, do one of the following:13441345* Keep the tool direct-only by omitting `allowed_callers` (or setting it to `["direct"]`). Other tools in the same request can still use programmatic calling.1346* Remove the cycle from the schema. For example, unroll the recursion to a fixed depth and describe any deeper nesting in the `description` of the innermost level, or replace the recursive property with a plain `{"type": "object"}` whose `description` explains the expected shape.13471348### Tool restrictions13491350The following tools cannot be called programmatically:13511352* Tools provided by an [MCP connector](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector)1353* The [computer use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/computer-use-tool) and [browser use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/browser-use-tool) toolsets (`computer_toolset_20260801` and `browser_toolset_20260801`), whose `allowed_callers` field accepts only `"direct"`13541355### Message formatting restrictions13561357When responding to programmatic tool calls, there are strict formatting requirements:13581359**Tool result only responses:** If there are pending programmatic tool calls waiting for results, your response message must contain **only** `tool_result` blocks. You cannot include any text content, even after the tool results.13601361Invalid - Cannot include text when responding to programmatic tool calls:13621363```json1364{1365 "role": "user",1366 "content": [1367 {1368 "type": "tool_result",1369 "tool_use_id": "toolu_01",1370 "content": "[{\"customer_id\": \"C1\", \"revenue\": 45000}]"1371 },1372 { "type": "text", "text": "What should I do next?" }1373 ]1374}1375```13761377Valid - Only tool results when responding to programmatic tool calls:13781379```json1380{1381 "role": "user",1382 "content": [1383 {1384 "type": "tool_result",1385 "tool_use_id": "toolu_01",1386 "content": "[{\"customer_id\": \"C1\", \"revenue\": 45000}]"1387 }1388 ]1389}1390```13911392This restriction only applies when responding to programmatic (code execution) tool calls. For regular client-side tool calls, you can include text content after tool results.13931394**Text-only tool result content:** The `content` of each `tool_result` that answers a programmatic call must be a string or `text` blocks. Image, document, and other content block types are rejected.13951396### Rate limits13971398Programmatic tool calls are subject to the same rate limits as regular tool calls. Each tool call from code execution counts as a separate invocation.13991400### Validate tool results before use14011402When implementing user-defined tools that will be called programmatically:14031404* **Tool results are returned as strings:** They can contain any content, including code snippets or executable commands that may be processed by the execution environment.1405* **Validate external tool results:** If your tool returns data from external sources or accepts user input, be aware of code injection risks if the output will be interpreted or executed as code.14061407## Token efficiency14081409Programmatic tool calling reduces token consumption in three ways:14101411* **Tool results from programmatic calls are not added to Claude's context** - only the final code output is1412* **Intermediate processing happens in code** - filtering, aggregation, and other transformations don't consume model tokens1413* **Multiple tool calls in one code execution** - reduces overhead compared to separate model turns14141415For example, calling 10 tools directly uses \~10x the tokens of calling them programmatically and returning a summary.14161417In Anthropic's internal evaluations on a production Claude model:14181419* On a 75-tool project-management agent benchmark, enabling programmatic tool calling reduced billed input tokens by roughly 38% with no change in task accuracy.1420* On [τ²-bench](https://arxiv.org/abs/2506.07982) (airline, retail, and telecom domains), where each turn makes one or two sequential tool calls, programmatic tool calling left scores unchanged and cost roughly 8% more. Sequential single-call workflows do not benefit.1421* Across production API traffic, requests whose `tools` array contains 10 to 49 tool definitions see typical token savings of 20% to 40% with programmatic tool calling enabled.14221423Actual savings vary with workload shape. See [When to use programmatic calling](https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling#when-to-use-programmatic-calling).14241425## Usage and pricing14261427Programmatic tool calling uses the same pricing as code execution. See the [code execution pricing](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool#usage-and-pricing) for details.14281429<Note>1430 Token counting for programmatic tool calls: Tool results from programmatic invocations do not count toward your input/output token usage. Only the final code execution result and Claude's response count.1431</Note>14321433## Best practices14341435### Tool design14361437* **Provide detailed output descriptions:** Because Claude deserializes tool results in code, document the format (JSON structure and field types)1438* **Return structured data:** JSON or other machine-readable formats work best for programmatic processing1439* **Keep responses concise:** Return only necessary data to minimize processing overhead14401441### When to use programmatic calling14421443Programmatic tool calling trades a small fixed overhead (container startup, script generation) for large savings on tool-result tokens and model round-trips. Whether that trade pays off depends on workload shape.14441445**Strong fit:**14461447* Fan-out or parallel operations across many items (for example, checking 50 endpoints or looking up 20 records)1448* Large tool results that can be filtered, aggregated, or summarized before reaching Claude's context1449* Agentic search and retrieval, where iterative querying and result filtering dominate the workflow14501451**Weak fit:**14521453* Strictly sequential workflows where each call depends on Claude reasoning over the previous result, because the script cannot skip the model round-trip in that case1454* A small number of tool calls with small responses, especially on the first turn of a conversation, where container and script overhead can exceed the savings1455* Tools that require immediate user feedback between calls14561457If you are unsure, measure billed input tokens with and without `allowed_callers` on a representative sample of your traffic before enabling it broadly.14581459### Performance optimization14601461* **Reuse containers** when making multiple related requests to maintain state1462* **Batch similar operations** in a single code execution when possible14631464## Troubleshooting14651466### Common issues14671468**`invalid_request_error` when setting `tool_choice`**14691470* `tool_choice` cannot name a tool whose `allowed_callers` omits `"direct"`. Either add `"direct"` to that tool's `allowed_callers`, or remove the tool from `tool_choice` and let Claude invoke it from code.14711472**Container expiration**14731474* Respond to each programmatic tool call well before the paused response's `expires_at` timestamp. Claude's code stops waiting for a result after about 4 minutes, and idle containers are currently reclaimed after about 5 minutes.1475* Consider implementing faster tool execution14761477**Tool result not parsed correctly**14781479* Ensure your tool returns string data that Claude can deserialize1480* Provide clear output format documentation in your tool description14811482### Debugging tips148314841. **Log all tool calls and results** to track the flow14852. **Check the `caller` field** to confirm programmatic invocation14863. **Monitor container IDs** to ensure proper reuse14874. **Test tools independently** before enabling programmatic calling14881489## Why programmatic tool calling works14901491Claude is trained on large amounts of code, so presenting tools as callable Python functions lets it use that strength:14921493* **Tool composition:** Chained calls, loops, and conditionals are ordinary Python control flow instead of a series of model round trips1494* **Result processing:** Claude's code filters and aggregates large tool outputs, or writes them to files, and only the final output enters the context window1495* **Latency:** The model is not re-sampled between the tool calls inside one code execution14961497## Alternative implementations14981499Programmatic tool calling is a generalizable pattern that can also be implemented on your own infrastructure. Here's how the approaches compare:15001501### Client-side direct execution15021503Provide Claude with a code execution tool and describe what functions are available in that environment. When Claude invokes the tool with code, your application executes it locally where those functions are defined.15041505**Advantages:**15061507* Minimal re-architecting of your application1508* Full control over the environment and instructions15091510**Disadvantages:**15111512* Executes untrusted code outside of a sandbox1513* Tool invocations can be vectors for code injection15141515**Use when:** Your application can safely execute arbitrary code, you want the smallest implementation, and Anthropic's managed offering doesn't fit your needs.15161517### Self-managed sandboxed execution15181519Same approach from Claude's perspective, but code runs in a sandboxed container with security restrictions (for example, no network egress). If your tools require external resources, you'll need a protocol for executing tool calls outside the sandbox.15201521**Advantages:**15221523* Safe programmatic tool calling on your own infrastructure1524* Full control over the execution environment15251526**Disadvantages:**15271528* Complex to build and maintain1529* Requires managing both infrastructure and inter-process communication15301531**Use when:** Security is critical and Anthropic's managed solution doesn't fit your requirements.15321533### Anthropic-managed execution15341535Anthropic's programmatic tool calling is a managed version of sandboxed execution with an opinionated Python environment tuned for Claude. Anthropic handles container management, code execution, and secure tool invocation communication.15361537**Advantages:**15381539* Safe and secure by default1540* Enabled with a tool definition, with no infrastructure to run1541* Environment and instructions optimized for Claude15421543Consider using Anthropic's managed solution if you're using the Claude API, [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws), or [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry). On Microsoft Foundry, programmatic tool calling requires a [Hosted on Anthropic deployment](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry#additional-features-not-supported-when-hosted-on-azure).15441545## Data retention15461547Programmatic tool calling is built on the code execution infrastructure and uses the same sandbox containers. Container data, including execution artifacts and outputs, is retained for up to 30 days.15481549For ZDR eligibility across all features, see [API and data retention](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention).15501551## Next steps15521553<CardGroup cols={2}>1554 <Card title="Fine-grained tool streaming" icon="bolt" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/fine-grained-tool-streaming">1555 Stream tool inputs without server-side JSON buffering for latency-sensitive applications.1556 </Card>15571558 <Card title="Code execution tool" icon="code" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool">1559 Run Python and bash code in a sandboxed container to analyze data, generate files, and iterate on solutions.1560 </Card>15611562 <Card title="Tool use with Claude" icon="wrench" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview">1563 Connect Claude to external tools and APIs. See where tools execute, when Claude calls them, and which tool fits your task.1564 </Card>15651566 <Card title="Define tools" icon="hammer" href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/define-tools">1567 Specify tool schemas, write effective descriptions, and control when Claude calls your tools.1568 </Card>1569</CardGroup>1570