Follow Discord
Sweep 22 Oct 2026 · 21:04Z Build v2.1.309 528 read Stable v2.1.308 Latest v2.1.309 Next v2.1.309 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One capture · api

One read of Claude Developer Platformapi-20260819T220710Z

34 pages moved out of 567 read.

Pages moved 34 significant first
Pages read 567 in this capture
Captured 22:07 UTC
Corpus hash a20c929de37f corpus-hash

What this read moved

1-25 of 34, page 1 of 2

This capture is too large to show at once. Changes 1-25 of 34 are below, significant first; the rest are on the following screens.

agents-and-tools/agent-skills/overview Changed · +1 / -5 lines

from line 149
149149 
150150The Claude API supports both pre-built Agent Skills and custom Skills. Both work identically: specify the relevant `skill_id` in the `container` parameter along with the [code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool).
151151 
152**Prerequisites:** Using Skills through the API requires the [code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool), whose container Skills run in, and one beta header:
153 
154* `skills-2025-10-02` - Enables Skills functionality
155 
156Add a second header, `files-api-2025-04-14`, when you use the [Files API](https://platform.claude.com/docs/en/build-with-claude/files) to upload input files to the container or download files a Skill produces.
152**Prerequisites:** Using Skills through the API requires the [code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool), whose container Skills run in. On the Claude API, neither the Skills API nor the `container.skills` parameter requires a beta header, and requests that still send `skills-2025-10-02` continue to work.
157153 
158154Use pre-built Agent Skills by referencing their `skill_id` (`pptx`, `xlsx`, `docx`, or `pdf`), or create and upload your own through the Skills API (`/v1/skills` endpoints). Custom Skills are shared workspace-wide: all workspace members can access them.
159155 

agents-and-tools/agent-skills/quickstart Changed · +3 / -2 lines

from line 364
364364* **`skill_id: "pptx"`:** The PowerPoint Skill identifier
365365* **`version: "latest"`:** The Skill version set to the most recently published
366366* **`tools`:** Enables code execution (required for Skills)
367* **Beta header:** `skills-2025-10-02`
368367 
369368<Note>
370 The examples on this page use the `code_execution_20260521` tool version, which is generally available and needs only the `skills-2025-10-02` beta header. The Step 3 code parses the result types that current tool versions return. Skills also work with older [code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool) versions such as `code_execution_20250825`: any current code execution tool version satisfies the Skills requirement. If you use a different version, keep its tool `type` and any beta header consistent with the code execution tool page, and always include `skills-2025-10-02`.
369 Skills are generally available on the Claude API and don't require a beta header. The examples on this page still send the `skills-2025-10-02` beta header and use the SDKs' `beta` namespace. Both remain valid, so you can run the examples as written and omit the header in your own requests.
370 
371 The examples use the `code_execution_20260521` tool version, and the Step 3 code parses the result types that current tool versions return. Skills also work with older [code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool) versions such as `code_execution_20250825`: any current code execution tool version satisfies the Skills requirement without a beta header. If you use a different version, use the tool `type` listed on the code execution tool page.
371372</Note>
372373 
373374When you make this request, Claude automatically matches your task to the relevant Skill. Because you asked for a presentation, Claude determines the PowerPoint Skill is relevant and loads its full instructions: the second level of progressive disclosure. Then Claude runs the Skill's code to create your presentation.

agents-and-tools/tool-use/web-search-tool Changed · +6 / -0 lines

from line 237
237237 Web search is enabled for your organization unless an administrator has disabled it in the [Claude Console](https://platform.claude.com/settings/privacy), where they can also restrict which domains it searches. If it's disabled, a request that includes the tool fails with a 400 `invalid_request_error` that says web search is not enabled, rather than an [error code](https://platform.claude.com/docs/en/agents-and-tools/tool-use/web-search-tool#errors) inside a search result.
238238</Note>
239239 
240These organization-level settings in the Claude Console apply to Messages API requests only. [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview) sessions use only the per-tool `allowed_domains` and `blocked_domains` lists on the agent toolset; see [Restrict web search and web fetch domains](https://platform.claude.com/docs/en/managed-agents/tools#restrict-web-search-and-web-fetch-domains).
241 
240242Provide the web search tool in your API request:
241243 
242244<CodeGroup>
from line 448
446448 
447449For the full domain filtering rules, see [Domain filtering](https://platform.claude.com/docs/en/agents-and-tools/tool-use/server-tools#domain-filtering) in the Server tools guide.
448450 
451On [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview), set these fields on the `web_search` entry of the agent toolset; see [Restrict web search and web fetch domains](https://platform.claude.com/docs/en/managed-agents/tools#restrict-web-search-and-web-fetch-domains).
452 
449453### Localization
450454 
451455The `user_location` parameter allows you to localize search results based on a user's location. Provide at least one of `city`, `region`, `country`, or `timezone`.
from line 459
455459* `region`: The region or state
456460* `country`: The two-letter [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country code. The API rejects unsupported country codes with a 400 error.
457461* `timezone`: The [IANA timezone ID](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).
462 
463On Claude Managed Agents, the `web_search` entry of the agent toolset accepts a `user_location` object with the same fields. The API rejects an unsupported `country` code with a 400 error when you create or update the agent, or when you create or update a session that supplies the setting. See [Restrict web search and web fetch domains](https://platform.claude.com/docs/en/managed-agents/tools#restrict-web-search-and-web-fetch-domains).
458464 
459465### Response inclusion
460466 

api/overview Changed · +3 / -3 lines

from line 29
2929* **[Message Batches API](https://platform.claude.com/docs/en/api/messages/batches/create)**: Process large volumes of Messages requests asynchronously with 50% cost reduction (`POST /v1/messages/batches`)
3030* **[Token Counting API](https://platform.claude.com/docs/en/api/messages-count-tokens)**: Count tokens in a message before sending to manage costs and rate limits (`POST /v1/messages/count_tokens`)
3131* **[Models API](https://platform.claude.com/docs/en/api/models/list)**: List available Claude models and their details (`GET /v1/models`)
32* **[Files API](https://platform.claude.com/docs/en/api/beta/files/upload)**: Upload and manage files for use across multiple API calls (`POST /v1/files`, `GET /v1/files`)
33* **[Skills API](https://platform.claude.com/docs/en/api/skills/create-skill)**: Create and manage custom agent skills (`POST /v1/skills`, `GET /v1/skills`)
3234 
3335**Beta:**
3436 
35* **[Files API](https://platform.claude.com/docs/en/api/beta/files/upload)**: Upload and manage files for use across multiple API calls (`POST /v1/files`, `GET /v1/files`)
36* **[Skills API](https://platform.claude.com/docs/en/api/skills/create-skill)**: Create and manage custom agent skills (`POST /v1/skills`, `GET /v1/skills`)
3737* **[Agents API](https://platform.claude.com/docs/en/managed-agents/agent-setup)**: Define reusable, versioned agent configurations for Claude Managed Agents (`POST /v1/agents`, `GET /v1/agents`)
3838* **[Sessions API](https://platform.claude.com/docs/en/managed-agents/sessions)**: Run stateful agent sessions in managed cloud sandboxes (`POST /v1/sessions`, `GET /v1/sessions/{id}/events/stream`)
3939* **[Environments API](https://platform.claude.com/docs/en/managed-agents/environments)**: Configure sandbox templates for agent sessions (`POST /v1/environments`, `GET /v1/environments`)
from line 152
152152Every SDK provides an auto-paginating iterator that follows `next_page` for you. In Python and TypeScript, you get it by iterating the list result directly. The other SDKs provide the iterator through a separate method. SDK auto-pagination is forward-only; to go back a page, read `prev_page` from the response and pass it back as the `page` parameter yourself. See [client SDKs](https://platform.claude.com/docs/en/cli-sdks-libraries/overview) for language-specific details.
153153 
154154<Note>
155 Some list endpoints use a different cursor scheme. The [Message Batches API](https://platform.claude.com/docs/en/build-with-claude/batch-processing), the [Files API](https://platform.claude.com/docs/en/build-with-claude/files), the [Models API](https://platform.claude.com/docs/en/api/models/list), and several [Admin API](https://platform.claude.com/docs/en/manage-claude/admin-api) endpoints take `after_id` and `before_id` query parameters instead of `page`. Their responses return `has_more`, `first_id`, and `last_id` instead of `next_page`. Some endpoints that use the `page` scheme, such as `GET /v1/skills`, also return a `has_more` Boolean alongside `next_page`. See the reference page for each endpoint for its exact pagination fields.
155 Some list endpoints use a different cursor scheme. The [Message Batches API](https://platform.claude.com/docs/en/build-with-claude/batch-processing), the [Models API](https://platform.claude.com/docs/en/api/models/list), and several [Admin API](https://platform.claude.com/docs/en/manage-claude/admin-api) endpoints take `after_id` and `before_id` query parameters instead of `page`. Their responses return `has_more`, `first_id`, and `last_id` instead of `next_page`. The [Files API](https://platform.claude.com/docs/en/build-with-claude/files) also uses that scheme when a request includes the `files-api-2025-04-14` beta header; without the header, `GET /v1/files` takes `page` and returns `next_page`. Some endpoints that use the `page` scheme, such as `GET /v1/skills`, also return a `has_more` Boolean alongside `next_page`. See the reference page for each endpoint for its exact pagination fields.
156156</Note>
157157 
158158## Rate limits and availability

api/rate-limits Changed · +4 / -0 lines

### Files API

from line 193
193193| Create endpoints (for example, agents, sessions, and environments) | 300 requests per minute |
194194| Read endpoints (for example, retrieve, list, and stream) | 1,200 requests per minute |
195195 
196### Files API
197 
198[Files API](https://platform.claude.com/docs/en/build-with-claude/files) requests have their own per-organization limit, shared across upload, list, retrieve, download, and delete operations and separate from the Messages API limits described earlier on this page. See [Files API rate limits](https://platform.claude.com/docs/en/build-with-claude/files#rate-limits) for the current value.
199 
196200### Fast mode rate limits
197201 
198202When using [fast mode](https://platform.claude.com/docs/en/build-with-claude/fast-mode) (research preview) with `speed: "fast"` on Claude Opus 5 or Opus 4.8, dedicated rate limits apply that are separate from standard Opus rate limits. When fast mode rate limits are exceeded, the API returns a `429` error with a `retry-after` header. Fast mode is not available on Claude Opus 4.7 (requests return an error) or Claude Opus 4.6 (requests to `claude-opus-4-6` with `speed: "fast"` run at standard speed). See [Fast mode](https://platform.claude.com/docs/en/build-with-claude/fast-mode#supported-models).

build-with-claude/files Changed · +30 / -11 lines

### File expiration

from line 5
55---
66 
77## Compatibility
8- Status: Beta
9- [Beta header](https://platform.claude.com/docs/en/api/beta-headers): `files-api-2025-04-14`
108- [ZDR](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention): not eligible
11- Platforms: Claude API (beta), Claude Platform on AWS (beta), Microsoft Foundry (beta) [1]; not available on Amazon Bedrock, Google Cloud
9- Platforms: Claude API, Claude Platform on AWS (beta), Microsoft Foundry (beta) [1]; not available on Amazon Bedrock, Google Cloud
12101. On [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry), the Files API 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).
1311 
1412The Files API lets you upload and manage files to use with the Claude API without re-uploading content with each request. This is particularly useful when using the [code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool) to provide inputs (for example, datasets and documents) and then download outputs (for example, charts). You can [explore the API reference directly](https://platform.claude.com/docs/en/api/beta/files/upload), in addition to this guide.
1513 
16<Note>
17 Reach out through the [feedback form](https://forms.gle/tisHyierGwgN4DUE9) to share your experience with the Files API.
18</Note>
19 
2014## File type support
2115 
2216Referencing a `file_id` in a Messages request is supported on all models that support the given file type. [Images](https://platform.claude.com/docs/en/build-with-claude/vision) are supported on all current Claude models. For [PDFs](https://platform.claude.com/docs/en/build-with-claude/pdf-support) and [other file types with the code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool#model-compatibility), see the linked pages for model support.
from line 33
3933## How to use the Files API
4034 
4135<Note>
42 To use the Files API, you'll need to include the beta feature header: `anthropic-beta: files-api-2025-04-14`. The SDKs add this header automatically when you call methods on the `beta.files` namespace, so the SDK examples on this page don't pass it explicitly for file operations. Messages requests that reference a file do need it, which the SDK examples pass through their `betas` parameter.
36 Requests to the Files API endpoints (`/v1/files`) don't need a beta header, and neither do Messages or Message Batches requests that reference an uploaded file. Two things to know about the `anthropic-beta: files-api-2025-04-14` header the examples on this page still send:
37 
38 * **Referencing a file from the Messages API.** Requests that use an uploaded file as a `document` or `image` source, or in a `container_upload` block for the code execution tool, work with or without the header. The SDK examples on this page still pass it through their `betas` parameter, which continues to work.
39 * **Sending the header on Files API requests.** The SDK `beta.files` methods and the CLI `ant beta:files` commands add the header automatically, and the cURL examples on this page include it. Those requests keep working and return the earlier response format: the list endpoint paginates with `before_id` and `after_id`, returns `has_more`, `first_id`, and `last_id` instead of `next_page`, and rejects the `page` and `ids[]` parameters as unknown fields. File objects returned under the header omit `expires_at` instead of returning `null` when no expiration is set. To use `page` and `ids[]` as described under [List files](https://platform.claude.com/docs/en/build-with-claude/files#list-files), send the request without the beta header.
4340</Note>
4441 
4542### Uploading a file
from line 162
165162 "mime_type": "application/pdf",
166163 "size_bytes": 1024000,
167164 "created_at": "2025-01-01T00:00:00Z",
168 "downloadable": false
165 "downloadable": false,
166 "expires_at": null
169167}
170168```
171169 
from line 699
701699 
702700#### List files
703701 
704Retrieve a list of your uploaded files. The endpoint is paginated: each request returns up to `limit` files (20 by default), and the `before_id` and `after_id` parameters fetch the adjacent page. See the [List Files API reference](https://platform.claude.com/docs/en/api/beta/files/list). The SDKs return the first page and provide auto-pagination helpers. The CLI example bounds the total with `--max-items`:
702Retrieve a list of your uploaded files. The endpoint is paginated: each request returns up to `limit` files (20 by default, and at most 1,000), and the response's `next_page` cursor fetches the next page when passed back as the `page` parameter. Files are ordered newest first. See the [List Files API reference](https://platform.claude.com/docs/en/api/beta/files/list). The SDKs return the first page and provide auto-pagination helpers. The CLI example bounds the total with `--max-items`:
705703 
706704<CodeGroup>
707705 ```bash cURL
from line 769
771769 ```
772770</CodeGroup>
773771 
772To check a known set of files in one request instead of paging, pass up to 100 file IDs as `ids[]` query parameters. An `ids[]` request always returns a single page (`next_page` is `null`), and any ID that does not resolve to a file in your workspace is silently omitted from `data`; compare the returned IDs against the requested IDs to detect misses. `ids[]` cannot be combined with `page` or `limit`.
773 
774The `page` parameter, the `next_page` cursor, and the `ids[]` filter apply to requests sent without the `anthropic-beta: files-api-2025-04-14` header. The preceding examples send it (the SDKs and CLI add it for `beta.files` calls), so they receive the earlier list format described in the note under [How to use the Files API](https://platform.claude.com/docs/en/build-with-claude/files#how-to-use-the-files-api).
775 
774776#### Get file metadata
775777 
776778Retrieve information about a specific file:
from line 988
986988 
987989* Files are scoped to the workspace of the API key that uploaded them. Any API key in the same workspace can reference them; never accept file IDs from untrusted sources (see the [workspace access warning](https://platform.claude.com/docs/en/build-with-claude/files#workspace-scoped-access))
988990* Files cannot be modified or renamed after upload. To change a file's content, upload a new file and delete the old one
989* Files persist until you delete them with the `DELETE /v1/files/{file_id}` endpoint
991* Files persist until you delete them with the `DELETE /v1/files/{file_id}` endpoint or they reach their `expires_at`
990992* Deleted files cannot be recovered
991993* Files are inaccessible through the API shortly after deletion, but they may persist in active Messages API calls and associated tool uses
992994* Files that users delete will be deleted in accordance with Anthropic's [data retention policy](https://privacy.claude.com/en/articles/7996866-how-long-do-you-store-my-organization-s-data). For ZDR eligibility across all features, see [API and data retention](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention)
995 
996### File expiration
997 
998To have a file expire automatically, include an `expires_in_seconds` form field when you upload it. The value is an integer number of seconds between 3,600 (1 hour) and 7,776,000 (90 days). The resulting `expires_at` timestamp (RFC 3339) appears on every file response and is `null` for files uploaded without an expiration. Expiration is set once at upload and cannot be changed.
999 
1000When a file reaches its `expires_at`:
1001 
1002* Downloading its content (`GET /v1/files/{file_id}/content`) returns a 404 error
1003* A Messages request that references the file fails before inference
1004* Its metadata (`GET /v1/files/{file_id}`) remains readable for up to 30 days, with `expires_at` in the past
1005* It continues to appear in list responses during that window; compare `expires_at` to the current time to filter expired files
1006 
1007Deleting an expired file with `DELETE /v1/files/{file_id}` removes its metadata immediately instead of waiting for the 30-day window to elapse.
1008 
1009<Note>
1010 Expiration is a lifecycle feature, not a guaranteed-deletion control. After `expires_at`, file content is no longer retrievable through the API and is released from your storage quota; the underlying content may be retained for a limited period thereafter for safety review before permanent deletion, and file metadata remains visible for up to 30 days after expiration. To remove a file before its scheduled expiration, use `DELETE /v1/files/{file_id}`.
1011</Note>
9931012 
9941013### Audit logging
9951014 

build-with-claude/overview Changed · +4 / -4 lines

from line 82
8282 
8383| Feature | Description | ZDR | Availability |
8484| ------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------ |
85| [Agent Skills](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview) | Extend Claude's capabilities with Skills. Use pre-built Skills (PowerPoint, Excel, Word, PDF) or create custom Skills with instructions and scripts. Skills use progressive disclosure to efficiently manage context. | Not ZDR eligible | <PlatformAvailability claudeApiBeta claudePlatformAwsBeta azureAiBeta />† |
85| [Agent Skills](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview) | Extend Claude's capabilities with Skills. Use pre-built Skills (PowerPoint, Excel, Word, PDF) or create custom Skills with instructions and scripts. Skills use progressive disclosure to efficiently manage context. | Not ZDR eligible | <PlatformAvailability claudeApi claudePlatformAwsBeta azureAiBeta />† |
8686| [Fine-grained tool streaming](https://platform.claude.com/docs/en/agents-and-tools/tool-use/fine-grained-tool-streaming) | Stream tool use parameters without buffering/JSON validation, reducing latency for receiving large parameters. | ZDR eligible | <PlatformAvailability claudeApi claudePlatformAws bedrock vertexAi azureAi /> |
8787| [MCP connector](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector) | Connect to remote [MCP](https://platform.claude.com/docs/en/mcp) servers directly from the Messages API without a separate MCP client. | Not ZDR eligible | <PlatformAvailability claudeApiBeta claudePlatformAwsBeta azureAiBeta />† |
8888| [Programmatic tool calling](https://platform.claude.com/docs/en/agents-and-tools/tool-use/programmatic-tool-calling) | Enable Claude to call your tools programmatically from within code execution containers, reducing latency and token consumption for multi-tool workflows. | Not ZDR eligible | <PlatformAvailability claudeApi claudePlatformAws azureAi />† |
from line 105
105105 
106106Manage files and assets for use with Claude.
107107 
108| Feature | Description | ZDR | Availability |
109| ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------- |
110| [Files API](https://platform.claude.com/docs/en/build-with-claude/files) | Upload and manage files to use with Claude without re-uploading content with each request. Supports PDFs, images, and text files. | Not ZDR eligible | <PlatformAvailability claudeApiBeta claudePlatformAwsBeta azureAiBeta />† |
108| Feature | Description | ZDR | Availability |
109| ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- | ---------------- | --------------------------------------------------------------------- |
110| [Files API](https://platform.claude.com/docs/en/build-with-claude/files) | Upload and manage files to use with Claude without re-uploading content with each request. Supports PDFs, images, and text files. | Not ZDR eligible | <PlatformAvailability claudeApi claudePlatformAwsBeta azureAiBeta />† |
111111 
112112\* **Structured outputs:** Your prompts and Claude's outputs are not stored. Only JSON schemas are cached, for up to 24 hours since last use. **Web search and web fetch:** ZDR-eligible except when [dynamic filtering](https://platform.claude.com/docs/en/agents-and-tools/tool-use/web-search-tool#dynamic-filtering) is enabled. **Fallback credit and server-side fallback:** The features retain no message content, but both handle refusals from Claude Fable 5, which [is not available under ZDR](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#model-specific-data-retention-requirements). See [ZDR details](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#feature-eligibility).
113113 

build-with-claude/skills-guide Changed · +22 / -155 lines

from line 47
4747| ------------------ | ------------------------------------------ | ------------------------------------------------------------------------------------------------------ |
4848| **Type value** | `anthropic` | `custom` |
4949| **Skill IDs** | Short names: `pptx`, `xlsx`, `docx`, `pdf` | Generated: `skill_01AbCdEfGhIjKlMnOpQrStUv` |
50| **Version format** | Date-based: `20251013` or `latest` | Epoch timestamp: `1759178010641129` or `latest` |
50| **Version format** | Date-based: `20251013` or `latest` | Version ID: `skver_01AbCdEfGhIjKlMnOpQrStUv` or `latest` |
5151| **Management** | Pre-built and maintained by Anthropic | Upload and manage through the [Skills API](https://platform.claude.com/docs/en/api/beta/skills/create) |
5252| **Availability** | Available to all users | Private to your workspace |
5353 
from line 58
5858To use Skills, you need:
5959 
60601. **Claude API key** from the [Claude Console](https://platform.claude.com/settings/keys)
612. **[Code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool)** enabled in your requests
6162 
622. **Beta headers:**
63Skills are generally available on the Claude API and don't require an `anthropic-beta` header, either for the Skills API or for `container.skills` in Messages requests. The examples in this guide still send the `skills-2025-10-02` beta header (plus `code-execution-2025-08-25` in Messages requests) and use the SDKs' `beta` namespace. Both headers remain valid opt-ins, so the examples work as written, and you can omit them in your own requests.
6364 
64 * `code-execution-2025-08-25` - Enables code execution (required for Skills)
65 * `skills-2025-10-02` - Enables Skills API
66 * `files-api-2025-04-14` - Required only when you use the [Files API](https://platform.claude.com/docs/en/build-with-claude/files) to upload input files or download files a Skill produces
67 
683. **[Code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool)** enabled in your requests
69 
7065Skills require the code execution tool, so use a model from its [model compatibility list](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool#model-compatibility).
7166 
7267***
from line 70
7570 
7671### Container parameter
7772 
78Skills are specified using the `container` parameter in the Messages API. You can include up to 8 Skills for each request.
73Skills are specified using the `container` parameter in the Messages API. You can include up to 20 Skills for each request.
7974 
8075The structure is identical for both Anthropic and custom Skills. Specify the required `type` and `skill_id`, and optionally include `version` to pin to a specific version:
8176 
from line 2251
22562251 
22572252Upload your custom Skill to make it available in your workspace. You can upload a zip archive or individual file objects. The Python SDK also provides a `files_from_dir` helper that accepts a directory path.
22582253 
2259Files are identified by the filename you attach. Per-file uploads must keep a common top-level directory in their paths (the `;filename=` suffix in the cURL example and the filename arguments in the SDK examples). A zip archive must contain the skill directory as its single top-level entry. For the walkthrough's skill, create one with `zip -r financial_skill.zip financial_skill/` and substitute it for the `example_skill.zip` placeholder in the zip-upload options.
2254Files are identified by the filename you attach (the `;filename=` suffix in the cURL example and the filename arguments in the SDK examples). For the walkthrough's skill, create a zip with `zip -r financial_skill.zip financial_skill/` and substitute it for the `example_skill.zip` placeholder in the zip-upload options.
22602255 
22612256<CodeGroup defaultLanguage="CLI">
22622257 ```bash cURL
from line 2521
25262521 
25272522**Requirements:**
25282523 
2529* Must include a `SKILL.md` file at the top level
2524* Must include a `SKILL.md` file at the upload root (or at the top of a single enclosing folder)
25302525 
2531* All files must specify a common root directory in their paths
2526* `display_name` is optional: when omitted, it derives from the `SKILL.md` `name`; an explicit value may be up to 255 characters and does not need to be unique within the workspace
25322527 
2533* The top-level directory name must match the `name` in `SKILL.md` frontmatter (case and underscore insensitive: `Financial_Skill` matches `financial-skill`)
2534 
2535* `display_title` is optional: when omitted, it derives from the `SKILL.md` `name`; an explicit value must be unique among the custom skills in your workspace
2536 
25372528* Total upload size must be under 30 MB (uncompressed)
25382529 
25392530* YAML frontmatter requirements:
from line 2787
27962787 
27972788### Deleting a Skill
27982789 
2799To delete a Skill, you must first delete all its versions:
2790Deleting a Skill also removes all of its versions. The cascade is GA-only behavior, so unlike the other examples in this guide, these call the GA surface directly rather than the `beta` namespace.
28002791 
28012792<CodeGroup defaultLanguage="CLI">
28022793 ```bash cURL
2803 # Step 1: List the versions, then delete each one
2804 curl "https://api.anthropic.com/v1/skills/skill_01AbCdEfGhIjKlMnOpQrStUv/versions" \
2805 -H "x-api-key: $ANTHROPIC_API_KEY" \
2806 -H "anthropic-version: 2023-06-01" \
2807 -H "anthropic-beta: skills-2025-10-02"
2808 
2809 # Repeat for each version the list returned
2810 curl -X DELETE "https://api.anthropic.com/v1/skills/skill_01AbCdEfGhIjKlMnOpQrStUv/versions/1759178010641129" \
2811 -H "x-api-key: $ANTHROPIC_API_KEY" \
2812 -H "anthropic-version: 2023-06-01" \
2813 -H "anthropic-beta: skills-2025-10-02"
2814 
2815 # Step 2: Delete the Skill
28162794 curl -X DELETE "https://api.anthropic.com/v1/skills/skill_01AbCdEfGhIjKlMnOpQrStUv" \
28172795 -H "x-api-key: $ANTHROPIC_API_KEY" \
2818 -H "anthropic-version: 2023-06-01" \
2819 -H "anthropic-beta: skills-2025-10-02"
2796 -H "anthropic-version: 2023-06-01"
28202797 ```
28212798 
28222799 ```bash CLI
2823 # Step 1: List the versions, then delete each one
2824 ant beta:skills:versions list \
2825 --skill-id skill_01AbCdEfGhIjKlMnOpQrStUv \
2826 --transform version \
2827 --raw-output
2828 
2829 # Repeat for each version id the list returned
2830 ant beta:skills:versions delete \
2831 --skill-id skill_01AbCdEfGhIjKlMnOpQrStUv \
2832 --version 1759178010641129 >/dev/null
2833 
2834 # Step 2: Delete the Skill
2835 ant beta:skills delete \
2800 ant skills delete \
28362801 --skill-id skill_01AbCdEfGhIjKlMnOpQrStUv >/dev/null
28372802 ```
28382803 
from line 2804
28392804 ```python Python
28402805 client = anthropic.Anthropic()
28412806 
2842 # Step 1: Delete all versions
2843 for version in client.beta.skills.versions.list(
2844 skill_id="skill_01AbCdEfGhIjKlMnOpQrStUv"
2845 ):
2846 client.beta.skills.versions.delete(
2847 skill_id="skill_01AbCdEfGhIjKlMnOpQrStUv",
2848 version=version.version,
2849 )
2850 
2851 # Step 2: Delete the Skill
2852 client.beta.skills.delete(skill_id="skill_01AbCdEfGhIjKlMnOpQrStUv")
2807 client.skills.delete(skill_id="skill_01AbCdEfGhIjKlMnOpQrStUv")
28532808 ```
28542809 
28552810 ```typescript TypeScript
28562811 const client = new Anthropic();
28572812 
2858 // Step 1: Delete all versions
2859 for await (const version of client.beta.skills.versions.list(
2860 "skill_01AbCdEfGhIjKlMnOpQrStUv"
2861 )) {
2862 await client.beta.skills.versions.delete(version.version, {
2863 skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv"
2864 });
2865 }
2866 
2867 // Step 2: Delete the Skill
2868 await client.beta.skills.delete("skill_01AbCdEfGhIjKlMnOpQrStUv");
2813 await client.skills.delete("skill_01AbCdEfGhIjKlMnOpQrStUv");
28692814 ```
28702815 
28712816 ```csharp C#
2872 using Anthropic.Models.Beta.Skills.Versions;
2873 // ...
28742817 AnthropicClient client = new();
28752818 
2876 // Step 1: Delete all versions
2877 await foreach (var version in (await client.Beta.Skills.Versions.List("skill_01AbCdEfGhIjKlMnOpQrStUv")).Paginate())
2878 {
2879 await client.Beta.Skills.Versions.Delete(
2880 version.Version,
2881 new VersionDeleteParams { SkillID = "skill_01AbCdEfGhIjKlMnOpQrStUv" }
2882 );
2883 }
2884 
2885 // Step 2: Delete the Skill
2886 await client.Beta.Skills.Delete("skill_01AbCdEfGhIjKlMnOpQrStUv");
2819 await client.Skills.Delete("skill_01AbCdEfGhIjKlMnOpQrStUv");
28872820 ```
28882821 
28892822 ```go Go
28902823 client := anthropic.NewClient()
28912824 
2892 // Step 1: Delete all versions
2893 versions := client.Beta.Skills.Versions.ListAutoPaging(
2825 _, err := client.Skills.Delete(
28942826 context.TODO(),
28952827 "skill_01AbCdEfGhIjKlMnOpQrStUv",
2896 anthropic.BetaSkillVersionListParams{},
28972828 )
2898 
2899 for versions.Next() {
2900 version := versions.Current()
2901 _, err := client.Beta.Skills.Versions.Delete(
2902 context.TODO(),
2903 version.Version,
2904 anthropic.BetaSkillVersionDeleteParams{
2905 SkillID: "skill_01AbCdEfGhIjKlMnOpQrStUv",
2906 },
2907 )
2908 if err != nil {
2909 log.Fatal(err)
2910 }
2911 }
2912 if versions.Err() != nil {
2913 log.Fatal(versions.Err())
2914 }
2915 
2916 // Step 2: Delete the Skill
2917 _, err := client.Beta.Skills.Delete(
2918 context.TODO(),
2919 "skill_01AbCdEfGhIjKlMnOpQrStUv",
2920 anthropic.BetaSkillDeleteParams{},
2921 )
29222829 if err != nil {
29232830 log.Fatal(err)
29242831 }
from line 2832
29252832 ```
29262833 
29272834 ```java Java
2928 import com.anthropic.models.beta.skills.versions.VersionListPage;
2929 import com.anthropic.models.beta.skills.versions.VersionDeleteParams;
2930 // ...
29312835 void main() {
29322836 AnthropicClient client = AnthropicOkHttpClient.fromEnv();
29332837 
2934 // Step 1: Delete all versions
2935 VersionListPage versions = client.beta().skills().versions().list("skill_01AbCdEfGhIjKlMnOpQrStUv");
2936 
2937 for (var version : versions.autoPager()) {
2938 client.beta().skills().versions().delete(
2939 version.version(),
2940 VersionDeleteParams.builder()
2941 .skillId("skill_01AbCdEfGhIjKlMnOpQrStUv")
2942 .build()
2943 );
2944 }
2945 
2946 // Step 2: Delete the Skill
2947 client.beta().skills().delete("skill_01AbCdEfGhIjKlMnOpQrStUv");
2838 client.skills().delete("skill_01AbCdEfGhIjKlMnOpQrStUv");
29482839 }
29492840 ```
29502841 
from line 2842
29512842 ```php PHP
29522843 $client = new Client();
29532844 
2954 // Step 1: Delete all versions
2955 $versions = $client->beta->skills->versions->list(
2845 $client->skills->delete(
29562846 skillID: 'skill_01AbCdEfGhIjKlMnOpQrStUv',
29572847 );
2958 
2959 foreach ($versions->pagingEachItem() as $version) {
2960 $client->beta->skills->versions->delete(
2961 skillID: 'skill_01AbCdEfGhIjKlMnOpQrStUv',
2962 version: $version->version,
2963 );
2964 }
2965 
2966 // Step 2: Delete the Skill
2967 $client->beta->skills->delete(
2968 skillID: 'skill_01AbCdEfGhIjKlMnOpQrStUv',
2969 );
29702848 ```
29712849 
29722850 ```ruby Ruby
29732851 client = Anthropic::Client.new
29742852 
2975 # Step 1: Delete all versions
2976 client.beta.skills.versions.list("skill_01AbCdEfGhIjKlMnOpQrStUv").auto_paging_each do |version|
2977 client.beta.skills.versions.delete(
2978 version.version,
2979 skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv"
2980 )
2981 end
2982 
2983 # Step 2: Delete the Skill
2984 client.beta.skills.delete("skill_01AbCdEfGhIjKlMnOpQrStUv")
2853 client.skills.delete("skill_01AbCdEfGhIjKlMnOpQrStUv")
29852854 ```
29862855</CodeGroup>
29872856 
2988Attempting to delete a Skill with existing versions returns a 400 error.
2989 
29902857### Versioning
29912858 
29922859Skills support versioning to manage updates safely:
from line 2866
29992866 
30002867**Custom Skills:**
30012868 
3002* Auto-generated epoch timestamps: `1759178010641129`
2869* Auto-generated version IDs: `skver_01AbCdEfGhIjKlMnOpQrStUv`
30032870* Use `"latest"` to always get the most recent version
30042871* Create new versions when updating Skill files
30052872 
3006A new version is a complete snapshot, not a delta: upload the Skill's full file set each time, under the same top-level directory name used at creation. Files you omit are not carried over. The following examples re-upload the complete `financial_skill/` bundle from [Creating a Skill](https://platform.claude.com/docs/en/build-with-claude/skills-guide#creating-a-skill).
2873A new version is a complete snapshot, not a delta: upload the Skill's full file set each time. Files you omit are not carried over, and the `name` in the new version's `SKILL.md` must match the Skill's existing name. The following examples re-upload the complete `financial_skill/` bundle from [Creating a Skill](https://platform.claude.com/docs/en/build-with-claude/skills-guide#creating-a-skill).
30072874 
30082875<CodeGroup defaultLanguage="CLI">
30092876 ```bash cURL
from line 3769
39023769 
39033770### Request limits
39043771 
3905* **Maximum Skills per request:** 8
3772* **Maximum Skills per request:** 20
39063773 
39073774* **Maximum Skill upload size:** 30 MB (all files combined, uncompressed)
39083775 

managed-agents/events-and-streaming Changed · +15 / -5 lines

from line 2753
27532753 
27542754## Console observability
27552755 
2756The Claude Console provides a visual timeline view of your agent sessions. Navigate to the Claude Managed Agents section in the Console to see:
2756The Claude Console includes a session viewer for inspecting what an agent did without writing any code. In the Console sidebar, under **Managed Agents**, select **Sessions** to see every session in the workspace with its status, agent, token usage, cost, and creation time, then select a session to open it. The session viewer is only accessible to Developers and Admins. It shows:
27572757 
2758* **Session list:** All sessions with their status, creation time, and agent
2759* **Tracing view:** A chronological view of events (content, timestamps, token usage) within a session. Tracing views are only accessible to Developers and Admins.
2760* **Tool execution:** Details of each tool call and its result
2758* **Timeline minimap:** A zoomable overview of the session's activity over time, with one lane per thread in [multiagent](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration) sessions. Select a lane to view that thread, or select a mark to jump to its event.
2759 
2760* **Transcript:** The conversation grouped by model request, including thinking, tool calls with their inputs and results, and message text as it streams. You can filter the events and copy or download them as JSON.
2761 
2762* **Inspector:** A resizable side panel with details about the session, in five tabs:
2763 
2764 * **Session** shows the session's details and metadata, its cumulative cost over time, and spend against the session's [budget](https://platform.claude.com/docs/en/managed-agents/budgets) when one is set.
2765 * **Events** lists every raw event on the current thread in the order the server sent it; select an event to see its JSON. A message that streamed while the page was open also has a **Deltas** view of its [event deltas](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#event-deltas).
2766 * **Tools** lists the tools the session's agents are configured with, along with call counts, failures, and median duration; select a tool to see its calls and jump to one in the transcript.
2767 * **Resources** lists mounted [files](https://platform.claude.com/docs/en/managed-agents/files), [repositories](https://platform.claude.com/docs/en/managed-agents/github), and [memory stores](https://platform.claude.com/docs/en/managed-agents/memory) at their container paths, including the memories in each store and the changes this session made to them, plus files the agent wrote to `/mnt/session/outputs` and the [skills](https://platform.claude.com/docs/en/managed-agents/skills) attached to the session's agents.
2768 * **Threads** lists every thread with its status, context size, and cost. Select a thread to view its details, such as the agent, model, context usage, and cost.
2769 
2770Append `?event={event_id}` to a session URL to open the session at a specific event.
27612771 
27622772## Debugging tips
27632773 

managed-agents/memory Changed · +8 / -2 lines

from line 18
1818 
1919## Overview
2020 
21A **memory store** is a workspace-scoped collection of text documents optimized for Claude. When you attach a store to a session, it is mounted as a directory inside the session's sandbox. The agent reads and writes it with the same file tools it uses for the rest of the filesystem, and a note describing each mount is automatically added to the system prompt, telling the agent where to look. The [agent toolset](https://platform.claude.com/docs/en/managed-agents/tools) is required for these interactions; make sure to enable it during [agent creation](https://platform.claude.com/docs/en/managed-agents/agent-setup).
21A **memory store** is a workspace-scoped collection of text documents optimized for Claude. When you attach a store to a session, it is mounted as a directory inside the session's sandbox. The agent reads and writes it with the same file tools it uses for the rest of the filesystem, and a note describing each mount is automatically added to the system prompt, telling the agent where to look. The [agent toolset](https://platform.claude.com/docs/en/managed-agents/tools) is required for these interactions; make sure to enable it during [agent creation](https://platform.claude.com/docs/en/managed-agents/agent-setup). On [self-hosted sandboxes](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#use-memory-stores), that directory is not a live mount. Instead, the SDK's environment worker downloads each attached store into your sandbox before the agent's tools run and keeps that copy in sync with the store.
2222 
2323Each **memory** in a store is addressed by a path and can be read and edited directly through the API or the Claude Console, allowing for tuning, importing, and exporting.
2424 
from line 208
208208 
209209## Attach a memory store to a session
210210 
211Memory stores are attached in the session's `resources[]` array when the [session is created](https://platform.claude.com/docs/en/managed-agents/sessions#creating-a-session). Unlike file resources, memory stores can only be attached at session creation time; adding or removing one from a running session is not supported.
211Memory stores are attached in the session's `resources[]` array when the [session is created](https://platform.claude.com/docs/en/managed-agents/sessions#creating-a-session). Unlike file resources, memory stores can only be attached at session creation time; adding or removing one from a running session is not supported. You attach memory stores the same way for sessions on cloud and [self-hosted environments](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#use-memory-stores); self-hosted environments accept only `memory_store` resources.
212212 
213213Optionally include `instructions` to provide session-specific guidance for how the agent should use this store. It is shown to the agent alongside the store's `name` and `description`, and is capped at 4,096 characters.
214214 
from line 380
380380Each attached store is mounted inside the session's sandbox as a directory under `/mnt/memory/`. The directory name is the store's display name sanitized to a filesystem-safe slug (lowercased; non-alphanumeric runs become a single hyphen), so a store named "Demo Memory" mounts at `/mnt/memory/demo-memory/`. The exact path is returned in the `mount_path` field on the session's memory-store resource; read it from there rather than constructing it yourself. The agent reads and writes the store with the standard [agent toolset](https://platform.claude.com/docs/en/managed-agents/tools). Writes under the mount path are persisted back to the store and stay in sync across sessions that share it; writes to any other path under `/mnt/memory/` land in container-local scratch and are lost when the session ends. A short description of each mount (display name, mount path, access mode, store `description`, and any `instructions`) is automatically added to the system prompt.
381381 
382382`access` is enforced at the filesystem level: a `read_only` mount rejects writes, while writes to a `read_write` mount produce [memory versions](https://platform.claude.com/docs/en/managed-agents/memory#audit-memory-changes) attributed to the session.
383 
384<Note>
385 On [self-hosted sandboxes](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#use-memory-stores), each store's directory is a local copy that the SDK worker manages rather than a live mount. The worker reconciles each copy with its store after tool calls, at most once per sync interval (15 seconds by default), and once more when the session ends. The agent's `write` and `edit` tools change only the local copy; the worker uploads those changes at its next sync, so another session running on a self-hosted sandbox sees a change only after both workers have synced. Paths under `/mnt/memory/` outside the store directories are not scratch space there: the worker's file tools refuse to write to them, and anything a shell command writes there is never synced to a store.
386 
387 For a `read_only` store, the worker's `write` and `edit` tools refuse changes under that directory and the worker never uploads anything from it. For how the worker resolves write conflicts, and what the `bash` tool can still change in a read-only store's local copy, see [Read-only stores and conflicts](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#read-only-stores-and-conflicts).
388</Note>
383389 
384390The agent's reads and writes appear in the [event stream](https://platform.claude.com/docs/en/managed-agents/events-and-streaming) as ordinary `agent.tool_use` and `agent.tool_result` events for whichever tool touched the mount.
385391 

managed-agents/permission-policies Changed · +10 / -12 lines

from line 541
541541 },
542542 Configs =
543543 [
544 new()
544 new BetaManagedAgentsBashToolConfigParams
545545 {
546 Name = "bash",
547546 PermissionPolicy = new BetaManagedAgentsAlwaysAskPolicy { Type = "always_ask" },
548547 },
549548 ],
from line 561
562561 },
563562 },
564563 },
565 Configs: []anthropic.BetaManagedAgentsAgentToolConfigParams{{
566 Name: anthropic.BetaManagedAgentsAgentToolConfigParamsNameBash,
567 PermissionPolicy: anthropic.BetaManagedAgentsAgentToolConfigParamsPermissionPolicyUnion{
568 OfAlwaysAsk: &anthropic.BetaManagedAgentsAlwaysAskPolicyParam{
569 Type: anthropic.BetaManagedAgentsAlwaysAskPolicyTypeAlwaysAsk,
564 Configs: []anthropic.BetaManagedAgentsAgentToolConfigUnionParamsUnion{{
565 OfBetaManagedAgentsBashToolConfigs: &anthropic.BetaManagedAgentsBashToolConfigParams{
566 PermissionPolicy: anthropic.BetaManagedAgentsBashToolConfigParamsPermissionPolicyUnion{
567 OfAlwaysAsk: &anthropic.BetaManagedAgentsAlwaysAskPolicyParam{
568 Type: anthropic.BetaManagedAgentsAlwaysAskPolicyTypeAlwaysAsk,
569 },
570570 },
571571 },
572572 }},
from line 593
593593 .build()
594594 )
595595 .addConfig(
596 BetaManagedAgentsAgentToolConfigParams.builder()
597 .name(BetaManagedAgentsAgentToolConfigParams.Name.BASH)
596 BetaManagedAgentsBashToolConfigParams.builder()
598597 .permissionPolicy(
599598 BetaManagedAgentsAlwaysAskPolicy.builder()
600599 .type(BetaManagedAgentsAlwaysAskPolicy.Type.ALWAYS_ASK)
from line 607
608607 ```
609608 
610609 ```php PHP
611 use Anthropic\Beta\Agents\BetaManagedAgentsAgentToolConfigParams;
610 use Anthropic\Beta\Agents\BetaManagedAgentsBashToolConfigParams;
612611 use Anthropic\Beta\Agents\BetaManagedAgentsAgentToolset20260401Params;
613612 use Anthropic\Beta\Agents\BetaManagedAgentsAgentToolsetDefaultConfigParams;
614613 use Anthropic\Beta\Agents\BetaManagedAgentsAlwaysAllowPolicy;
from line 620
621620 permissionPolicy: BetaManagedAgentsAlwaysAllowPolicy::with(type: 'always_allow'),
622621 ),
623622 configs: [
624 BetaManagedAgentsAgentToolConfigParams::with(
625 name: 'bash',
623 BetaManagedAgentsBashToolConfigParams::with(
626624 permissionPolicy: BetaManagedAgentsAlwaysAskPolicy::with(type: 'always_ask'),
627625 ),
628626 ],

managed-agents/self-hosted-sandboxes Changed · +440 / -39 lines

## Use memory stores ### How the worker handles memory ### Prepare the host ### Run one sandbox per session ### Configure sync ### Read-only stores and conflicts ### Troubleshoot memory mounts

The two sides of this change are more than 400 edits apart, too far apart to line up, so this is the differ's own diff of it and the words inside a line are not marked.

from line 6
66 
77By default, Managed Agents executes tools and code inside [Anthropic-managed cloud sandboxes](https://platform.claude.com/docs/en/managed-agents/cloud-sandboxes-reference). Self-hosted sandboxes keep the orchestration on Anthropic's side but move tool execution into infrastructure you control, so the agent's code, filesystem, and network egress never leave your environment.
88 
9Tool execution stays on your host: the filesystem the agent reads and writes, the processes it spawns, and the network it can reach are all under your control. Tool inputs and outputs still flow to Anthropic's control plane (where Claude runs) so the model can see results and determine what to do next. See the [security model](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-security) for the full data-flow boundary.
9Tool execution stays on your host: the filesystem the agent reads and writes, the processes it spawns, and the network it can reach are all under your control. Tool inputs and outputs still flow to Anthropic's control plane (where Claude runs) so the model can see results and determine what to do next. The agent's [skills](https://platform.claude.com/docs/en/managed-agents/skills) and the contents of any [memory stores](https://platform.claude.com/docs/en/managed-agents/memory) attached to the session are stored by Anthropic and copied into your sandbox for the session; changes the agent makes to memory files sync back to the store. See the [security model](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-security) for the full data-flow boundary.
1010 
1111<Note>
1212 Self-hosted sandboxes support all Claude models available in Managed Agents, including Claude Opus 4.8 and Claude Opus 5. The model is configured on the [agent](https://platform.claude.com/docs/en/managed-agents/agent-setup), not the environment.
from line 14
1414 
1515## How it differs from cloud environments
1616 
17| | Cloud environment | Self-hosted sandbox |
18| ----------------------------- | --------------------------- | ------------------- |
19| Where tools run | Anthropic-managed sandboxes | Your infrastructure |
20| Network reach | Anthropic's egress controls | Your network policy |
21| File and GitHub repo mounting | Managed by Anthropic | Managed by you |
22| Lifecycle | Managed by Anthropic | Managed by you |
17| | Cloud environment | Self-hosted sandbox |
18| ----------------------------- | -------------------------------------- | --------------------------------------------------------- |
19| Where tools run | Anthropic-managed sandboxes | Your infrastructure |
20| Network reach | Anthropic's egress controls | Your network policy |
21| File and GitHub repo mounting | Managed by Anthropic | Managed by you |
22| Memory stores | Mounted by Anthropic at `/mnt/memory/` | Downloaded to `/mnt/memory/` and synced by the SDK worker |
23| Lifecycle | Managed by Anthropic | Managed by you |
2324 
2425Self-hosting is a good fit when the agent needs to operate on data that cannot leave your network boundary, reach internal services that are not publicly routable, or run under your organization's own compliance and audit controls.
2526 
from line 46
4546 
4647* **`/workspace`:** the system default working directory for tool execution and skill download. The CLI's `--workdir` flag defaults to the current directory; pass `--workdir /workspace` to match the system default. Skills are downloaded to `<workdir>/skills/<name>/`. If you use a different working directory, update your agent's system prompt so Claude can locate the skill files.
4748* **Outputs:** on self-hosted environments the session's system prompt omits the `/mnt/session/outputs` instruction used on Anthropic-managed sandboxes, so final deliverables land wherever the agent writes them in your sandbox filesystem, typically under the working directory.
49* **`/mnt/memory/`:** memory stores attached to the session are materialized here by the SDK worker, one directory per store at the store's `mount_path` (for example, `/mnt/memory/user-preferences/`). The worker creates these directories when it claims the session and removes them when the session ends; see [Use memory stores](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#use-memory-stores).
4850 
4951## Before you begin
5052 
from line 55
5355* **An existing agent.** If you don't have one, complete the [Quickstart](https://platform.claude.com/docs/en/managed-agents/quickstart) first and note its agent ID.
5456* **A Linux host** with `/bin/bash` at that exact path. The worker's bash tool invokes it directly, without consulting `PATH`. The TypeScript SDK additionally requires `unzip` and `tar` on the `PATH` and Node.js 22 or later; the Python and Go SDKs use their standard libraries for archive extraction and have no additional binary requirements.
5557* **The `ant` CLI or an Anthropic SDK** (Python, TypeScript, or Go) on the worker host.
56* **Two credentials:** an environment key (generated in the Console in the steps that follow) authenticates the worker to its queue; your Claude API key creates sessions and reads queue stats from outside the worker host. Key generation is Console-only.
58* **Credentials:** an environment key (generated in the Console in the steps that follow) authenticates the worker to its queue; your Claude API key creates sessions and reads queue stats from outside the worker host. Key generation is Console-only. Claimed work items also carry a per-session `secret` that the worker uses to mount [memory stores](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#use-memory-stores); you don't generate it, but in the sandbox-per-session pattern you forward it into the sandbox yourself (see [Run one sandbox per session](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#run-one-sandbox-per-session)).
59* **For memory stores, a prepared host.** If sessions on this environment will attach memory stores, prepare `/mnt/memory` on the worker host before you start the worker; see [Prepare the host](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#prepare-the-host).
5760 
5861<Note>
5962 On [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws), the worker authenticates with AWS IAM (SigV4) or an [API key generated in the AWS Console](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws#api-key-authentication), not an environment key. Attach the [`AnthropicSelfHostedEnvironmentAccess`](https://platform.claude.com/docs/en/api/claude-platform-on-aws-iam-actions#managed-policies) managed policy to the IAM principal your worker runs as. Environment keys generated in the Claude Console don't work with the Claude Platform on AWS endpoint.
63 
64 Memory stores cannot be attached to sessions on self-hosted environments on Claude Platform on AWS.
6065</Note>
6166 
6267<Steps>
from line 255
250255 ENTRYPOINT ["ant", "beta:worker", "run"]
251256 ```
252257 
253 Then write a spawn script that forwards session details into a fresh sandbox. The poller injects `ANTHROPIC_SESSION_ID`, `ANTHROPIC_WORK_ID`, `ANTHROPIC_ENVIRONMENT_ID`, and `ANTHROPIC_ENVIRONMENT_KEY` into the script's environment. `ANTHROPIC_BASE_URL` is optional and is passed through only if it was set on the poller host; it overrides the default API endpoint. In the example, `/host/outputs` is a host directory you choose; it is bind-mounted to the sandbox's working directory (`/workspace`) so you can retrieve session deliverables after the sandbox exits. On self-hosted environments the agent writes deliverables under the working directory rather than `/mnt/session/outputs` (see [Sandbox filesystem](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#sandbox-filesystem)), so mounting the working directory is what captures them; the mount also picks up the downloaded `skills/` tree and any intermediate files the agent creates.
258 Then write a spawn script that forwards session details into a fresh sandbox. The poller injects `ANTHROPIC_SESSION_ID`, `ANTHROPIC_WORK_ID`, `ANTHROPIC_ENVIRONMENT_ID`, and `ANTHROPIC_ENVIRONMENT_KEY` into the script's environment, and writes the claimed work item to the script's standard input as JSON, including the work item's per-session `secret` when Anthropic issued one. `ANTHROPIC_BASE_URL` is optional and is passed through only if it was set on the poller host; it overrides the default API endpoint. In the example, `/host/outputs` is a host directory you choose; it is bind-mounted to the sandbox's working directory (`/workspace`) so you can retrieve session deliverables after the sandbox exits. On self-hosted environments the agent writes deliverables under the working directory rather than `/mnt/session/outputs` (see [Sandbox filesystem](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#sandbox-filesystem)), so mounting the working directory is what captures them; the mount also picks up the downloaded `skills/` tree and any intermediate files the agent creates.
254259 
255260 ```bash
256261 #!/bin/bash
from line 268
263268 your-image
264269 ```
265270 
271 The `ant beta:worker run` entrypoint does not mount [memory stores](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#use-memory-stores). If sessions on this environment attach memory stores, keep the poller, but build the per-session image around the SDK worker and extend the spawn script to forward the work item's `secret` into the sandbox, as shown in [Run one sandbox per session](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#run-one-sandbox-per-session).
272 
266273 Start the poller pointing at the script:
267274 
268275 ```bash
from line 288
281288 <CodeGroup exclude="shell">
282289 ```python Python
283290 import asyncio
291 import contextlib
284292 import os
293 import signal
285294 from anthropic import AsyncAnthropic
286295 from anthropic.lib.environments import EnvironmentWorker
287296 
from line 299
290299 environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"]
291300 environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"]
292301 async with AsyncAnthropic(auth_token=environment_key) as client:
293 await EnvironmentWorker(
302 worker = EnvironmentWorker(
294303 client,
295304 environment_id=environment_id,
296305 environment_key=environment_key,
297306 workdir="/workspace",
298 ).run()
307 )
308 task = asyncio.create_task(worker.run())
309 # Cancelling the task, rather than killing the process, lets the worker stop its
310 # in-flight work item and upload changed memory files before it exits.
311 loop = asyncio.get_running_loop()
312 for signum in (signal.SIGINT, signal.SIGTERM):
313 loop.add_signal_handler(signum, task.cancel)
314 with contextlib.suppress(asyncio.CancelledError):
315 await task
299316 
300317 
301318 asyncio.run(main())
from line 326
309326 const environmentId = process.env.ANTHROPIC_ENVIRONMENT_ID!;
310327 const client = new Anthropic({ authToken: environmentKey });
311328 const controller = new AbortController();
329 // Aborting on either signal lets the worker upload changed memory files and remove its
330 // store directories before the process exits.
331 process.once("SIGINT", () => controller.abort());
312332 process.once("SIGTERM", () => controller.abort());
313333 
314334 await new EnvironmentWorker({
from line 413
393413 <Step title="Implement the webhook handler">
394414 `EnvironmentWorker` claims the work item, downloads skills, executes tool calls in the working directory, posts results back, and exits. Invoke it when `session.status_run_started` fires.
395415 
416 When you hand a claimed work item to `handle_item()` yourself, as this handler does, pass the work item's `secret` along as `work_secret` (`workSecret` in TypeScript, `WorkSecret` in Go) so the session can mount any [memory stores](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#use-memory-stores) attached to it. A handler like this one runs every claimed item in one process on one host, so two sessions that attach the same memory store cannot run through it at the same time (see [Prepare the host](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#prepare-the-host)); if your sessions share stores, launch [one sandbox per session](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#run-one-sandbox-per-session) instead.
417 
396418 <CodeGroup exclude="shell">
397419 ```python Python
420 import asyncio
398421 import os
422 import signal
399423 import anthropic
424 import standardwebhooks # installed by the anthropic[webhooks] extra
400425 
401426 environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"]
402427 environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"]
403428 client = anthropic.AsyncAnthropic(
404429 auth_token=environment_key,
405430 )
406 
407 
408 async def handle(raw: bytes, headers: dict[str, str]) -> dict:
409 event = client.beta.webhooks.unwrap(raw.decode(), headers=headers)
431 # Cancelled on SIGINT or SIGTERM (wired in handle) so an in-flight work item can upload
432 # changed memory files and remove its store directories before the process exits.
433 inflight: set[asyncio.Task[None]] = set()
434 
435 
436 def cancel_inflight() -> None:
437 for task in inflight:
438 task.cancel()
439 
440 
441 async def handle(raw: bytes, headers: dict[str, str]) -> tuple[dict[str, str], int]:
442 try:
443 event = client.beta.webhooks.unwrap(raw.decode(), headers=headers)
444 except standardwebhooks.WebhookVerificationError:
445 return {"error": "signature verification failed"}, 401
410446 if event.data.type != "session.status_run_started":
411 return {"status": "ignored"}
447 return {"status": "ignored"}, 200
448 loop = asyncio.get_running_loop()
449 for signum in (signal.SIGINT, signal.SIGTERM):
450 loop.add_signal_handler(signum, cancel_inflight)
451 task = asyncio.create_task(run_queued_work())
452 inflight.add(task)
453 task.add_done_callback(inflight.discard)
454 try:
455 await task
456 except asyncio.CancelledError:
457 return {"status": "shutting down"}, 503
458 return {"status": "ok"}, 200
459 
460 
461 async def run_queued_work() -> None:
412462 async for work in client.beta.environments.work.poller(
413463 environment_id=environment_id,
414464 environment_key=environment_key,
from line 472
422472 environment_id=environment_id,
423473 session_id=work.data.id,
424474 environment_key=environment_key,
475 # The per-session secret is what lets the worker mount the session's memory stores.
476 work_secret=work.secret,
425477 )
426 return {"status": "ok"}
427478 ```
428479 
429480 ```typescript TypeScript
from line 485
434485 const client = new Anthropic({
435486 authToken: environmentKey
436487 });
488 // Aborted on SIGINT or SIGTERM so an in-flight work item can upload changed memory
489 // files and remove its store directories before the process exits.
490 const shutdown = new AbortController();
491 process.once("SIGINT", () => shutdown.abort());
492 process.once("SIGTERM", () => shutdown.abort());
437493 
438494 export async function handle(req: Request): Promise<Response> {
439495 const body = await req.text();
from line 509
453509 blockMs: null,
454510 reclaimOlderThanMs: 2000,
455511 drain: true,
456 autoStop: false
512 autoStop: false,
513 signal: shutdown.signal
457514 })) {
458515 await client.beta.environments.work.worker({ workdir: "/workspace" }).handleItem({
459516 workId: work.id,
460517 environmentId,
461518 sessionId: work.data.id,
462 environmentKey
519 environmentKey,
520 // The per-session secret is what lets the worker mount the session's memory stores.
521 workSecret: work.secret ?? undefined,
522 signal: shutdown.signal
463523 });
464524 }
465525 return Response.json({ status: "ok" });
from line 537
477537 import (
478538 "context"
479539 "encoding/json"
540 "errors"
480541 "io"
481542 "log/slog"
482543 "net/http"
483544 "os"
545 "os/signal"
546 "syscall"
484547 
485548 "github.com/anthropics/anthropic-sdk-go"
486549 "github.com/anthropics/anthropic-sdk-go/lib/environments"
from line 561
498561 worker = environments.NewEnvironmentWorker(client, environments.EnvironmentWorkerOptions{
499562 Workdir: "/workspace",
500563 })
564 // Cancelled on SIGINT or SIGTERM (set in main) so an in-flight work item can
565 // upload changed memory files and remove its store directories before exit.
566 shutdown context.Context
501567 )
502568 
503569 func handle(w http.ResponseWriter, r *http.Request) {
from line 585
519585 // The Go SDK does not provide a RunOne convenience: drain pending items
520586 // with WorkPoller and run each one with HandleItem.
521587 // Detach from r.Context(): the session can outlive the webhook delivery timeout.
522 ctx := context.Background()
588 // The process-wide shutdown context still ends the item cleanly on SIGTERM.
589 ctx := shutdown
523590 poller := environments.NewWorkPoller(ctx, client, environments.WorkPollerOptions{
524591 EnvironmentID: environmentID,
525592 EnvironmentKey: environmentKey,
526593 BlockMs: param.Null[int64](),
527594 ReclaimOlderThanMs: param.NewOpt[int64](2000),
528595 Drain: true,
596 AutoStop: param.NewOpt(false),
529597 })
530598 defer poller.Close()
531599 for poller.Next() {
from line 603
535603 EnvironmentID: item.EnvironmentID,
536604 SessionID: item.Data.ID,
537605 EnvironmentKey: environmentKey,
606 // The per-session secret is what lets the worker mount the session's memory stores.
607 WorkSecret: item.Secret,
538608 }); err != nil {
539609 slog.Error("handle work item", "work_id", item.ID, "err", err)
540610 http.Error(w, "internal error", http.StatusInternalServerError)
from line 620
550620 }
551621 
552622 func main() {
623 ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
624 defer stop()
625 shutdown = ctx
626 
627 server := &http.Server{Addr: ":8080"}
553628 http.HandleFunc("POST /webhook", handle)
554 if err := http.ListenAndServe(":8080", nil); err != nil {
555 slog.Error("http server", "err", err)
556 os.Exit(1)
629 go func() {
630 if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
631 slog.Error("http server", "err", err)
632 os.Exit(1)
633 }
634 }()
635 // On a signal, stop accepting deliveries and return only after in-flight
636 // handlers, and therefore their work items' memory teardown, have finished.
637 <-ctx.Done()
638 if err := server.Shutdown(context.Background()); err != nil {
639 slog.Error("http shutdown", "err", err)
557640 }
558641 }
559642 
from line 669
586669* **`EnvironmentWorker`:** the out-of-the-box worker. Handles polling, setup, and execution end to end.
587670 
588671 * `.run()`: runs indefinitely, picking up sessions as they arrive.
589 * `.handle_item()`: handles a single claimed work item and exits. Pass the work, session, and environment identifiers explicitly, or let it read the `ANTHROPIC_*` variables that `ant beta:worker poll --on-work` sets for the process it spawns.
672 * `.handle_item()`: handles a single claimed work item and exits. Pass the work, session, and environment identifiers explicitly, or let it read the `ANTHROPIC_*` variables that `ant beta:worker poll --on-work` sets for the process it spawns. To let the session mount its [memory stores](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#use-memory-stores), also pass the work item's `secret` as `work_secret` (`workSecret` in TypeScript, `WorkSecret` in Go) or set `ANTHROPIC_WORK_SECRET`; `ant beta:worker poll --on-work` does not set that variable, so read the secret from the work item JSON it writes to your script's standard input, as shown in [Run one sandbox per session](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#run-one-sandbox-per-session).
673 * `memory_sync_interval` (`memorySyncIntervalMs` in TypeScript, `MemorySyncInterval` in Go) and `memory_sync_deletes` (`memoryRemoteDeletes`, `MemorySyncDeletes`): how often attached memory stores reconcile with the server while the session runs, and whether files the agent deletes locally are also deleted from the store. See [Configure sync](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#configure-sync) for units, defaults, and how to disable memory support.
590674 
591675* **`work.poller()`:** polls the work queue on your behalf and gives you each claimed session. Use this when you want to decide what happens for each session, for example launching a sandbox rather than running tools in-process.
592676 
593677 * `drain`: whether to stop polling once the queue is empty rather than waiting for new work.
594678 * `block_ms`: how long to wait for work to arrive before returning, in milliseconds. Must be between 1 and 999 (per-poll wait; the helper re-polls automatically). Pass `null` (`None` in Python, `param.Null[int64]()` in Go) for a non-blocking check; omitting the parameter uses the default 999 ms long-poll.
595679 * `reclaim_older_than_ms`: re-claim work items that were claimed but never acknowledged within this many milliseconds.
596 * `auto_stop`: whether to post a stop signal for each work item once your loop body finishes with it. The Go poller has no opt-out and always posts the stop signal, so block in the loop body until the session completes rather than detaching.
680 * `auto_stop` (`autoStop` in TypeScript, `AutoStop` in Go): whether to post a stop signal for each work item once your loop body finishes with it. Turn it off when the process you launch for the session, rather than the loop body, runs the work item to completion.
597681 
598682* **`client.beta.sessions.events.tool_runner()`:** runs tool calls for a single session, given the session ID and a tool list. Use when you've already claimed the work and only need the execution layer.
599683 
from line 703
619703 from anthropic import AsyncAnthropic
620704 from anthropic.types.beta.environments import BetaSelfHostedWork
621705 
706 SANDBOX_ENV = (
707 "ANTHROPIC_ENVIRONMENT_ID",
708 "ANTHROPIC_ENVIRONMENT_KEY",
709 "ANTHROPIC_WORK_ID",
710 "ANTHROPIC_SESSION_ID",
711 "ANTHROPIC_WORK_SECRET",
712 "ANTHROPIC_BASE_URL", # forwarded only when set on this host
713 )
714 
622715 
623716 async def launch_container(work: BetaSelfHostedWork) -> None:
624 # Replace with your own per-session sandbox launcher. Pass
625 # ANTHROPIC_ENVIRONMENT_KEY into the launched sandbox, never
626 # your API key.
627717 print(f"claimed session {work.data.id}")
718 # Replace `docker run` with your own sandbox launcher. Forward the environment
719 # key (never your API key) and the work item's per-session secret: the worker
720 # inside needs the secret to mount the session's memory stores.
721 env = os.environ | {
722 "ANTHROPIC_WORK_ID": work.id,
723 "ANTHROPIC_SESSION_ID": work.data.id,
724 "ANTHROPIC_WORK_SECRET": work.secret or "",
725 }
726 forward = [arg for name in SANDBOX_ENV for arg in ("-e", name)]
727 launcher = await asyncio.create_subprocess_exec(
728 "docker", "run", "--rm", "--detach", *forward, "your-sdk-worker-image", env=env
729 )
730 await launcher.wait()
628731 
629732 
630733 async def main() -> None:
from line 746
643746 ```
644747 
645748 ```typescript TypeScript
749 import { spawn } from "node:child_process";
750 import { once } from "node:events";
646751 import Anthropic from "@anthropic-ai/sdk";
647752 import { WorkPoller } from "@anthropic-ai/sdk/helpers/beta/environments";
648753 import type { BetaSelfHostedWork } from "@anthropic-ai/sdk/resources/beta/environments";
649754 
755 const SANDBOX_ENV = [
756 "ANTHROPIC_ENVIRONMENT_ID",
757 "ANTHROPIC_ENVIRONMENT_KEY",
758 "ANTHROPIC_WORK_ID",
759 "ANTHROPIC_SESSION_ID",
760 "ANTHROPIC_WORK_SECRET",
761 "ANTHROPIC_BASE_URL" // forwarded only when set on this host
762 ];
763 
650764 const environmentKey = process.env.ANTHROPIC_ENVIRONMENT_KEY!;
651765 const environmentId = process.env.ANTHROPIC_ENVIRONMENT_ID!;
652766 const client = new Anthropic({ authToken: environmentKey });
653767 
654768 async function launchContainer(work: BetaSelfHostedWork): Promise<void> {
655 // Replace with your own per-session sandbox launcher. Pass
656 // ANTHROPIC_ENVIRONMENT_KEY into the launched sandbox, never
657 // your API key.
658769 console.log(`claimed session ${work.data.id}`);
770 // Replace `docker run` with your own sandbox launcher. Forward the environment
771 // key (never your API key) and the work item's per-session secret: the worker
772 // inside needs the secret to mount the session's memory stores.
773 const env = {
774 ...process.env,
775 ANTHROPIC_WORK_ID: work.id,
776 ANTHROPIC_SESSION_ID: work.data.id,
777 ANTHROPIC_WORK_SECRET: work.secret ?? ""
778 };
779 const forward = SANDBOX_ENV.flatMap((name) => ["-e", name]);
780 const launcher = spawn(
781 "docker",
782 ["run", "--rm", "--detach", ...forward, "your-sdk-worker-image"],
783 { env, stdio: "inherit" }
784 );
785 await once(launcher, "close");
659786 }
660787 
661788 const poller = new WorkPoller({
from line 810
683810 "fmt"
684811 "log"
685812 "os"
813 "os/exec"
686814 
687815 "github.com/anthropics/anthropic-sdk-go"
688816 "github.com/anthropics/anthropic-sdk-go/lib/environments"
689817 "github.com/anthropics/anthropic-sdk-go/option"
818 "github.com/anthropics/anthropic-sdk-go/packages/param"
690819 )
691820 
692 func launchContainer(work *anthropic.BetaSelfHostedWork) {
693 // Replace with your own per-session sandbox launcher. The Go poller
694 // calls work.Stop when this function returns (it has no auto-stop
695 // opt-out), so block here until the session completes rather than
696 // detaching as the Python and TypeScript tabs do.
821 var sandboxEnv = []string{
822 "ANTHROPIC_ENVIRONMENT_ID",
823 "ANTHROPIC_ENVIRONMENT_KEY",
824 "ANTHROPIC_WORK_ID",
825 "ANTHROPIC_SESSION_ID",
826 "ANTHROPIC_WORK_SECRET",
827 "ANTHROPIC_BASE_URL", // forwarded only when set on this host
828 }
829 
830 func launchContainer(ctx context.Context, work *anthropic.BetaSelfHostedWork) error {
697831 fmt.Printf("claimed session %s\n", work.Data.ID)
832 // Replace `docker run` with your own sandbox launcher. Forward the environment
833 // key (never your API key) and the work item's per-session secret: the worker
834 // inside needs the secret to mount the session's memory stores.
835 args := []string{"run", "--rm", "--detach"}
836 for _, name := range sandboxEnv {
837 args = append(args, "-e", name)
838 }
839 launcher := exec.CommandContext(ctx, "docker", append(args, "your-sdk-worker-image")...)
840 launcher.Env = append(os.Environ(),
841 "ANTHROPIC_WORK_ID="+work.ID,
842 "ANTHROPIC_SESSION_ID="+work.Data.ID,
843 "ANTHROPIC_WORK_SECRET="+work.Secret,
844 )
845 launcher.Stdout, launcher.Stderr = os.Stdout, os.Stderr
846 return launcher.Run()
698847 }
699848 
700849 func main() {
from line 857
708857 poller := environments.NewWorkPoller(ctx, client, environments.WorkPollerOptions{
709858 EnvironmentID: environmentID,
710859 EnvironmentKey: environmentKey,
860 AutoStop: param.NewOpt(false), // the launched sandbox owns the stop call
711861 })
712862 defer poller.Close()
713863 
from line 865
715865 if err != nil {
716866 log.Fatal(err)
717867 }
718 launchContainer(work)
868 if err := launchContainer(ctx, work); err != nil {
869 log.Fatal(err)
870 }
719871 }
720872 }
721873 ```
from line 888
736888 ```
737889</CodeGroup>
738890 
739**`AgentToolContext`** is the execution context for tool calls. It defines the working directory and path policy, and can download the session's skills. **`beta_agent_toolset_20260401(env)`** takes an `AgentToolContext` and returns the standard tool implementations (`bash`, `read`, `write`, `edit`, `glob`, `grep`).
891Whatever launches the sandbox must forward the claimed work item's `secret` into it (for example as `ANTHROPIC_WORK_SECRET`) alongside the session, work, and environment identifiers, so the worker inside can mount the session's [memory stores](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#use-memory-stores); see [Run one sandbox per session](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#run-one-sandbox-per-session).
892 
893**`AgentToolContext`** is the execution context for tool calls. It defines the working directory and path policy, and can download the session's skills. The file tools (`read`, `write`, `edit`, `glob`, `grep`) are confined to the working directory plus any directories listed in `allowed_roots` (`allowedRoots` in TypeScript, `AllowedRoots` in Go), and `write` and `edit` additionally refuse paths under `read_only_roots` (`readOnlyRoots`, `ReadOnlyRoots`). `EnvironmentWorker` adds the session's memory store directories to these lists itself. The confinement is a guardrail for the file tools only, not a sandbox; it does not constrain `bash`. **`beta_agent_toolset_20260401(env)`** takes an `AgentToolContext` and returns the standard tool implementations (`bash`, `read`, `write`, `edit`, `glob`, `grep`).
740894 
741895**With `EnvironmentWorker`:** both are managed automatically. Pass a `tools` factory to customize the tool list:
742896 
from line 1097
9431097</CodeGroup>
9441098 
9451099<Note>
946 Self-hosted sandboxes don't support `resources` entries; a session that includes any resource on a self-hosted environment is rejected.
1100 Self-hosted sandboxes support `memory_store` resources only; see [Use memory stores](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#use-memory-stores). A session on a self-hosted environment that includes a `file` or `github_repository` resource is rejected with a 400 error:
1101 
1102 ```text wrap
1103 Environment env_... is a self-hosted environment. `resources` are not supported with self-hosted environments.
1104 ```
1105 
1106 [Deployments](https://platform.claude.com/docs/en/managed-agents/scheduled-deployments) that target a self-hosted environment follow the same rule.
9471107</Note>
9481108 
9491109See [Self-hosted worker](https://platform.claude.com/docs/en/managed-agents/reference#self-hosted-worker) in the reference for the full list of CLI flags, and [SDK helpers](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#sdk-helpers) for the SDK helper options.
1110 
1111## Use memory stores
1112 
1113Sessions on a self-hosted environment attach [memory stores](https://platform.claude.com/docs/en/managed-agents/memory) exactly as sessions on cloud environments do: list them in `resources` when you create the session, as shown in [Attach a memory store to a session](https://platform.claude.com/docs/en/managed-agents/memory#attach-a-memory-store-to-a-session). A session accepts up to 8 memory stores. On a self-hosted environment the SDK worker, rather than Anthropic's infrastructure, materializes each store for the agent, so memory stores there require `EnvironmentWorker` (or its `handle_item()` method) from the Python, TypeScript, or Go SDK.
1114 
1115The `ant` CLI worker (`ant beta:worker poll` and `ant beta:worker run`) does not mount memory stores. To combine the CLI poller with memory stores, run the SDK worker inside a per-session sandbox as described in [Run one sandbox per session](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#run-one-sandbox-per-session).
1116 
1117Memory stores cannot be attached to sessions on self-hosted environments on [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws).
1118 
1119### How the worker handles memory
1120 
1121When the worker claims a work item whose session has memory stores attached, it:
1122 
11231. Downloads each attached store to its `mount_path` on the worker host, authenticating with the work item's per-session `secret`. The `mount_path` is the same directory under `/mnt/memory/` that cloud sessions use (for example, `/mnt/memory/user-preferences/` for a store named "User Preferences"), and the session's system prompt describes it to the agent.
11242. Adds those directories to the file tools' allowed roots, and the directories of stores attached with `access: "read_only"` to their read-only roots, so the agent works on memories with the same `read`, `write`, `edit`, `glob`, and `grep` tools it uses in the working directory.
11253. Reconciles local and remote changes after tool calls, at most once per sync interval (15 seconds by default): memories that changed in the store are written to disk, and files the agent changed are uploaded to the store.
11264. Runs a final sync when the session ends, flushes any uploads still pending for up to 30 seconds, and then removes the directories it created. A worker that is cancelled while a session runs skips the final sync but still uploads changed files and removes the directories before it exits.
1127 
1128The memory store on Anthropic's side remains the source of truth. [Memory versions](https://platform.claude.com/docs/en/managed-agents/memory#audit-memory-changes), redaction, and viewing or editing memories in the Console work as they do for cloud sessions, and the agent's memory reads and writes appear in the [event stream](https://platform.claude.com/docs/en/managed-agents/events-and-streaming) as ordinary tool events. Because each worker syncs on an interval, a change written in one session becomes visible to another running session only after both have synced, typically well under a minute at the default interval; sessions on cloud sandboxes see each other's changes almost immediately.
1129 
1130Each store directory contains a marker file named `.anthropic-memory-store` that ties the directory to its store. Leave it in place: the worker does not sync a directory whose marker is missing or altered.
1131 
1132### Prepare the host
1133 
1134Memory stores on self-hosted sandboxes need a POSIX filesystem on the worker host (the Linux host from [Before you begin](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#before-you-begin)); Windows hosts are not supported, because the worker requires `O_NOFOLLOW` when it opens memory files. A case-sensitive filesystem is recommended, so that memory paths that differ only in case do not collide.
1135 
1136Before you start the worker, create the parent directory and make it writable by the user the worker runs as:
1137 
1138```bash
1139sudo mkdir -p /mnt/memory && sudo chown "$USER" /mnt/memory
1140```
1141 
1142Do not create the per-store directories yourself. The worker creates each store's `mount_path` directory (for example, `/mnt/memory/user-preferences`) when a session starts, refuses to start the session's work if something already exists at that path, and removes the directory when the session ends. Two operating rules follow:
1143 
1144* **Run one session per filesystem when sessions attach the same store.** Two sessions cannot mount the same store on one host at the same time, because both need the same path. Giving each session its own sandbox, as described in [Run one sandbox per session](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#run-one-sandbox-per-session), satisfies this rule.
1145* **Stop workers gracefully.** When you stop a worker while a session runs, `EnvironmentWorker` uploads the session's changed memory files and removes its store directories only if it is cancelled rather than killed: a killed process runs no teardown, and the worker does not install signal handlers itself. Wire SIGTERM and SIGINT to cancellation in the process that runs it: abort the `signal` you pass to the worker in TypeScript, cancel the context in Go, and in Python cancel the task that runs `run()` or `handle_item()` from a signal handler. Then stop workers with SIGTERM and give them at least 30 seconds to exit before any hard kill, because the final upload can take that long. If a worker is killed before its teardown runs, remove the leftover store directory under `/mnt/memory/` before the next session that attaches that store; any edits in it that had not synced are lost.
1146 
1147### Run one sandbox per session
1148 
1149The sandbox-per-session pattern in [Run a worker](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#run-a-worker) gives each session a fresh filesystem, which is what [Prepare the host](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#prepare-the-host) calls for when sessions attach the same store. Keep `ant beta:worker poll --on-work` (or the SDK's work poller) as the poller on the host.
1150 
1151The `ant beta:worker run` entrypoint shown there does not mount memory stores, so build the per-session image around the SDK worker instead: its entrypoint constructs `EnvironmentWorker` and calls `handle_item()` (`handleItem` in TypeScript, `HandleItem` in Go), which reads the session, work, and environment identifiers from the `ANTHROPIC_*` variables and the work item's per-session `secret` from `ANTHROPIC_WORK_SECRET`. You can also pass the secret explicitly as `work_secret` (`workSecret` in TypeScript, `WorkSecret` in Go).
1152 
1153<CodeGroup exclude="shell">
1154 ```python Python
1155 import asyncio
1156 import contextlib
1157 import os
1158 import signal
1159 from anthropic import AsyncAnthropic
1160 from anthropic.lib.environments import EnvironmentWorker
1161 
1162 
1163 async def main() -> None:
1164 async with AsyncAnthropic(auth_token=os.environ["ANTHROPIC_ENVIRONMENT_KEY"]) as client:
1165 worker = EnvironmentWorker(client, workdir="/workspace")
1166 # With no arguments, handle_item() reads the ANTHROPIC_* variables the spawn
1167 # script forwarded, including ANTHROPIC_WORK_SECRET.
1168 task = asyncio.create_task(worker.handle_item())
1169 # Cancelling the task when the container is stopped lets the worker upload
1170 # changed memory files and remove the store directories before it exits.
1171 loop = asyncio.get_running_loop()
1172 for signum in (signal.SIGINT, signal.SIGTERM):
1173 loop.add_signal_handler(signum, task.cancel)
1174 with contextlib.suppress(asyncio.CancelledError):
1175 await task
1176 
1177 
1178 asyncio.run(main())
1179 ```
1180 
1181 ```typescript TypeScript
1182 import Anthropic from "@anthropic-ai/sdk";
1183 import { EnvironmentWorker } from "@anthropic-ai/sdk/helpers/beta/environments";
1184 
1185 const client = new Anthropic({ authToken: process.env.ANTHROPIC_ENVIRONMENT_KEY });
1186 const controller = new AbortController();
1187 // Aborting when the container is stopped lets the worker upload changed memory
1188 // files and remove the store directories before it exits.
1189 process.once("SIGTERM", () => controller.abort());
1190 process.once("SIGINT", () => controller.abort());
1191 
1192 // With no arguments, handleItem() reads the ANTHROPIC_* variables the spawn
1193 // script forwarded, including ANTHROPIC_WORK_SECRET.
1194 await new EnvironmentWorker({
1195 client,
1196 workdir: "/workspace",
1197 signal: controller.signal
1198 }).handleItem();
1199 ```
1200 
1201 ```csharp C#
1202 // EnvironmentWorker is not currently available in the C# SDK.
1203 ```
1204 
1205 ```go Go
1206 package main
1207 
1208 import (
1209 "context"
1210 "log"
1211 "os"
1212 "os/signal"
1213 "syscall"
1214 
1215 "github.com/anthropics/anthropic-sdk-go"
1216 "github.com/anthropics/anthropic-sdk-go/lib/environments"
1217 "github.com/anthropics/anthropic-sdk-go/option"
1218 )
1219 
1220 func main() {
1221 // Cancelling the context when the container is stopped lets the worker upload
1222 // changed memory files and remove the store directories before it exits.
1223 ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
1224 defer stop()
1225 
1226 client := anthropic.NewClient(option.WithAuthToken(os.Getenv("ANTHROPIC_ENVIRONMENT_KEY")))
1227 worker := environments.NewEnvironmentWorker(client, environments.EnvironmentWorkerOptions{
1228 Workdir: "/workspace",
1229 })
1230 // With zero-value options, HandleItem reads the ANTHROPIC_* variables the spawn
1231 // script forwarded, including ANTHROPIC_WORK_SECRET.
1232 if err := worker.HandleItem(ctx, environments.HandleItemOptions{}); err != nil {
1233 log.Fatalf("worker: %v", err)
1234 }
1235 }
1236 
1237 ```
1238 
1239 ```java Java
1240 // EnvironmentWorker is not currently available in the Java SDK.
1241 ```
1242 
1243 ```php PHP
1244 // EnvironmentWorker is not currently available in the PHP SDK.
1245 ```
1246 
1247 ```ruby Ruby
1248 # EnvironmentWorker is not currently available in the Ruby SDK.
1249 ```
1250</CodeGroup>
1251 
1252`ant beta:worker poll --on-work` does not set `ANTHROPIC_WORK_SECRET` for the script it spawns, so the spawn script reads the secret from the work item JSON on its standard input and passes it into the sandbox:
1253 
1254```bash
1255#!/bin/bash
1256# spawn.sh: called once per claimed work item
1257# The claimed work item arrives as JSON on stdin. Its secret is the
1258# per-session credential that the memory store endpoints require.
1259ANTHROPIC_WORK_SECRET="$(jq -r '.secret // empty')"
1260export ANTHROPIC_WORK_SECRET
1261mkdir -p "/host/outputs/$ANTHROPIC_SESSION_ID"
1262exec docker run --rm \
1263 -e ANTHROPIC_SESSION_ID -e ANTHROPIC_ENVIRONMENT_KEY \
1264 -e ANTHROPIC_WORK_ID -e ANTHROPIC_ENVIRONMENT_ID -e ANTHROPIC_BASE_URL \
1265 -e ANTHROPIC_WORK_SECRET \
1266 -v "/host/outputs/$ANTHROPIC_SESSION_ID":/workspace \
1267 your-sdk-worker-image
1268```
1269 
1270If you claim work with the SDK's work poller instead, pass each claimed item's `secret` into the sandbox you launch in the same way. Pass it only into the sandbox that serves that session, and never log it.
1271 
1272The sandbox image also needs a writable `/mnt/memory` (see [Prepare the host](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#prepare-the-host)). Because each sandbox serves one session and is discarded afterward, no leftover directories need cleanup, and the memory directories do not need to be bind-mounted to the host: the worker uploads their contents to the store before the sandbox exits. If you stop a container before its session ends, send a signal that the entrypoint turns into cancellation (see [Prepare the host](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#prepare-the-host)) rather than killing it, so that upload still runs. Give the container time to finish the upload as well: Docker follows the stop signal with SIGKILL after 10 seconds by default, so raise that limit to at least the 30 seconds that Prepare the host calls for, with `--stop-timeout` on `docker run` or your orchestrator's termination grace period.
1273 
1274### Configure sync
1275 
1276Two `EnvironmentWorker` options control memory behavior:
1277 
1278* **`memory_sync_interval`** (Python, in seconds; `memorySyncIntervalMs` in TypeScript, in milliseconds; `MemorySyncInterval` in Go, a duration): how often attached stores reconcile with the server while the session runs. Defaults to 15 seconds; the minimum is 5 seconds. A shorter interval narrows the window in which another session sees stale memories, at the cost of more memory store requests. `None` in Python, `null` in TypeScript, or a negative duration in Go disables memory support entirely: the worker neither downloads nor syncs stores, and a session with memory stores attached runs without them even though its system prompt still describes them, so disable memory support only on workers whose sessions attach no memory stores. While memory support is enabled, a work item that arrives without a per-session `secret` for a session with attached stores fails rather than running without memory (see [Troubleshoot memory mounts](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#troubleshoot-memory-mounts)).
1279* **`memory_sync_deletes`** (`memoryRemoteDeletes` in TypeScript, `MemorySyncDeletes` in Go): whether a file the agent deletes locally is also deleted from the store. The value is one of `"enabled"` (the default), `"log_only"`, or `"disabled"` in Python and TypeScript, and one of the constants `environments.MemorySyncDeletesEnabled` (the zero value), `environments.MemorySyncDeletesLogOnly`, or `environments.MemorySyncDeletesDisabled` in Go. When enabled, the worker deletes the memory from the store once a later sync confirms the file is still gone; in log-only mode it runs the same checks but only logs what it would have deleted, which lets you watch what your workers would delete before you trust the enabled mode; when disabled, it never deletes from the store. Uploads and downloads are unaffected by this setting.
1280 
1281Set these options where you construct the worker, whether through the `EnvironmentWorker` constructor or, in Python and TypeScript, the `client.beta.environments.work.worker()` factory that the webhook handler uses.
1282 
1283For example, to sync every 10 seconds and only log the deletes the worker would have made:
1284 
1285<CodeGroup exclude="shell">
1286 ```python Python
1287 worker = EnvironmentWorker(
1288 client,
1289 environment_id=environment_id,
1290 environment_key=environment_key,
1291 workdir="/workspace",
1292 memory_sync_interval=10, # seconds
1293 memory_sync_deletes="log_only",
1294 )
1295 ```
1296 
1297 ```typescript TypeScript
1298 const worker = new EnvironmentWorker({
1299 client,
1300 environmentId,
1301 environmentKey,
1302 workdir: "/workspace",
1303 memorySyncIntervalMs: 10_000,
1304 memorySyncDeletes: "log_only"
1305 });
1306 ```
1307 
1308 ```csharp C#
1309 // EnvironmentWorker is not currently available in the C# SDK.
1310 ```
1311 
1312 ```go Go
1313 worker := environments.NewEnvironmentWorker(client, environments.EnvironmentWorkerOptions{
1314 EnvironmentID: environmentID,
1315 EnvironmentKey: environmentKey,
1316 Workdir: "/workspace",
1317 MemorySyncInterval: 10 * time.Second,
1318 MemorySyncDeletes: environments.MemorySyncDeletesLogOnly,
1319 })
1320 ```
1321 
1322 ```java Java
1323 // EnvironmentWorker is not currently available in the Java SDK.
1324 ```
1325 
1326 ```php PHP
1327 // EnvironmentWorker is not currently available in the PHP SDK.
1328 ```
1329 
1330 ```ruby Ruby
1331 # EnvironmentWorker is not currently available in the Ruby SDK.
1332 ```
1333</CodeGroup>
1334 
1335### Read-only stores and conflicts
1336 
1337For a store attached with `access: "read_only"`, the `write` and `edit` tools refuse to change files inside its directory, and the worker never uploads anything from it. Changes made through `bash` are not blocked locally: they are never synced to the store, and the next remote change to that memory overwrites them. If you need the local copy itself to stay unchanged during the session, disable the `bash` tool for that agent; do not mount the store path read-only, because the worker itself must create the directory and write the downloaded memories into it.
1338 
1339Conflicts resolve in favor of the store. When the agent changes a memory file that also changed in the store since the session last synced it, the worker keeps the store's version at the next sync, overwrites the local file with it, and logs a warning; the `write` and `edit` tools themselves succeed and no error reaches the agent. If the agent's change still applies, it can re-read the file after the sync and make the change again.
1340 
1341### Troubleshoot memory mounts
1342 
1343The worker logs mount and background sync failures rather than reporting them to the session; only read-only refusals reach the agent, as tool errors (see [Read-only stores and conflicts](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#read-only-stores-and-conflicts)). If a memory store cannot be mounted when the worker claims a session, the worker fails the work item: the session emits no error event and stays idle.
1344 
1345| Symptom | Cause | Fix |
1346| --------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1347| The worker log contains `the work item carried no sessions token` (in Go, the `ErrSessionMemoryNoToken` error) and the work item fails. | The work item's per-session `secret` did not reach the worker: memory stores on self-hosted sandboxes are not enabled for your organization, or your spawn script did not forward the secret into the sandbox. | In the sandbox-per-session pattern, forward `ANTHROPIC_WORK_SECRET` into the sandbox as shown in [Run one sandbox per session](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#run-one-sandbox-per-session). If the worker polls and runs sessions in one process and still logs this, contact support. |
1348| The worker log contains `something already exists at the memory store's path`. | A directory left over from a previous session, usually one whose worker was killed before its teardown ran. | Remove the leftover directory that the log line names. Edits in it that had not synced are lost. |
1349| The worker log contains `cannot create the memory store's folder` and `the worker host must make this mount path writable`. | The user the worker runs as cannot create directories under `/mnt/memory`. | Create `/mnt/memory` and `chown` it to that user; see [Prepare the host](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#prepare-the-host). |
1350| The session sits `idle` with a `requires_action` stop reason and no error event shortly after a worker claimed it. | The worker failed the work item because it could not mount a memory store, for one of the preceding reasons. | Fix the cause on the host, then send a [`user.interrupt`](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#integrating-events) event: the session's work is queued again and the next worker that claims it retries the mount. |
9501351 
9511352## Serve custom tools from your sandbox
9521353 
9531354 

managed-agents/tools Changed · +439 / -9 lines

### Restrict web search and web fetch domains #### Domain list rules #### When settings are validated #### Multiagent sessions, outcomes, and mid-session updates #### Differences from the Messages API tools

The two sides of this change are more than 400 edits apart, too far apart to line up, so this is the differ's own diff of it and the words inside a line are not marked.

from line 14
1414 
1515## Available tools
1616 
17The agent toolset includes the following tools. All are enabled by default when you include the toolset in your agent configuration. Use the values in the Name column to reference tools in the `configs` array.
17The agent toolset includes the following tools. All are enabled by default when you include the toolset in your agent configuration. Each entry in the `configs` array is identified by its `name`, using the values in the Name column, and accepts an optional `type` field with the same value. The `web_search` and `web_fetch` entries accept additional settings; see [Restrict web search and web fetch domains](https://platform.claude.com/docs/en/managed-agents/tools#restrict-web-search-and-web-fetch-domains).
1818 
1919| Tool | Name | Description |
2020| ---------- | ------------ | ---------------------------------------------- |
from line 32
3232## Configuring the toolset
3333 
3434Enable the full toolset with `agent_toolset_20260401` when creating an agent. Use the `configs` array to disable specific tools or override their settings. Each config entry can also set a `permission_policy` that controls whether the tool's calls are auto-approved or require confirmation. See [Permission policies](https://platform.claude.com/docs/en/managed-agents/permission-policies) for the available policy types.
35 
36Config entries for `web_search` and `web_fetch` also accept domain filters and other web settings; see [Restrict web search and web fetch domains](https://platform.claude.com/docs/en/managed-agents/tools#restrict-web-search-and-web-fetch-domains).
3537 
3638<CodeGroup defaultLanguage="CLI">
3739 ```bash cURL
from line 113
111113 Type = "agent_toolset_20260401",
112114 Configs =
113115 [
114 new() { Name = "web_fetch", Enabled = false },
116 new BetaManagedAgentsWebFetchToolConfigParams { Enabled = false },
115117 ],
116118 },
117119 ],
from line 129
127129 Tools: []anthropic.BetaAgentNewParamsToolUnion{{
128130 OfAgentToolset20260401: &anthropic.BetaManagedAgentsAgentToolset20260401Params{
129131 Type: anthropic.BetaManagedAgentsAgentToolset20260401ParamsTypeAgentToolset20260401,
130 Configs: []anthropic.BetaManagedAgentsAgentToolConfigParams{{
131 Name: anthropic.BetaManagedAgentsAgentToolConfigParamsNameWebFetch,
132 Enabled: anthropic.Bool(false),
132 Configs: []anthropic.BetaManagedAgentsAgentToolConfigUnionParamsUnion{{
133 OfBetaManagedAgentsWebFetchToolConfigs: &anthropic.BetaManagedAgentsWebFetchToolConfigParams{
134 Enabled: anthropic.Bool(false),
135 },
133136 }},
134137 },
135138 }},
from line 151
148151 .model(BetaManagedAgentsModel.CLAUDE_OPUS_5)
149152 .addTool(BetaManagedAgentsAgentToolset20260401Params.builder()
150153 .type(BetaManagedAgentsAgentToolset20260401Params.Type.AGENT_TOOLSET_20260401)
151 .addConfig(BetaManagedAgentsAgentToolConfigParams.builder()
152 .name(BetaManagedAgentsAgentToolConfigParams.Name.WEB_FETCH)
154 .addConfig(BetaManagedAgentsWebFetchToolConfigParams.builder()
153155 .enabled(false)
154156 .build())
155157 .build())
from line 159
157159 ```
158160 
159161 ```php PHP
160 use Anthropic\Beta\Agents\BetaManagedAgentsAgentToolConfigParams;
161162 use Anthropic\Beta\Agents\BetaManagedAgentsAgentToolset20260401Params;
163 use Anthropic\Beta\Agents\BetaManagedAgentsWebFetchToolConfigParams;
162164 
163165 $agent = $client->beta->agents->create(
164166 name: 'Coding Assistant',
from line 169
167169 BetaManagedAgentsAgentToolset20260401Params::with(
168170 type: 'agent_toolset_20260401',
169171 configs: [
170 BetaManagedAgentsAgentToolConfigParams::with(name: 'web_fetch', enabled: false),
172 BetaManagedAgentsWebFetchToolConfigParams::with(enabled: false),
171173 ],
172174 ),
173175 ],
from line 221
219221 ]
220222}
221223```
224 
225### Restrict web search and web fetch domains
226 
227To control which sites the agent's web tools can reach, set `allowed_domains` (the tool can reach only these hosts) or `blocked_domains` (the tool can never reach these hosts) on the `web_search` and `web_fetch` entries of the toolset's `configs` array. Each tool carries its own list, so `web_search` and `web_fetch` can have different restrictions. A listed domain covers that host and all of its subdomains. At runtime, a `web_fetch` call for a URL that its lists do not permit returns an error result to the agent (`is_error: true` on the `agent.tool_result` event, with content that names the error code `url_not_allowed`), and `web_search` omits results that its lists do not permit.
228 
229The following toolset limits `web_search` to two sites and localizes its results, and blocks one host for `web_fetch` while capping how much fetched content enters the context:
230 
231```json
232{
233 "type": "agent_toolset_20260401",
234 "configs": [
235 {
236 "type": "web_search",
237 "name": "web_search",
238 "allowed_domains": ["docs.example.com", "arxiv.org"],
239 "user_location": {
240 "type": "approximate",
241 "country": "US",
242 "timezone": "America/Los_Angeles"
243 }
244 },
245 {
246 "type": "web_fetch",
247 "name": "web_fetch",
248 "blocked_domains": ["ads.example.com"],
249 "max_content_tokens": 50000
250 }
251 ]
252}
253```
254 
255<Note>
256 In the Python, TypeScript, Go, Java, C#, Ruby, and PHP SDKs, each `configs` entry is typed per tool: a union with one member per built-in tool, discriminated by `type`. `type` is optional when you construct an entry (the server infers it from `name`) and always present on responses. This typing does not change the JSON that an entry serializes to, so a request whose entries set only `name`, `enabled`, and `permission_policy` is valid with or without `type`. In SDKs where you construct entries from typed values rather than plain dictionaries or hashes (Go, Java, C#, and PHP), the element type of `configs` is the union itself: build each entry from its per-tool member type.
257</Note>
258 
259The following request creates an agent with this toolset and prints the `configs` array from the response:
260 
261<CodeGroup defaultLanguage="CLI">
262 ```bash cURL
263 agent=$(curl -fsSL https://api.anthropic.com/v1/agents \
264 -H "x-api-key: $ANTHROPIC_API_KEY" \
265 -H "anthropic-version: 2023-06-01" \
266 -H "anthropic-beta: managed-agents-2026-04-01" \
267 -H "content-type: application/json" \
268 -d @- <<'EOF'
269 {
270 "name": "Research Agent",
271 "model": "claude-opus-5",
272 "tools": [
273 {
274 "type": "agent_toolset_20260401",
275 "configs": [
276 {
277 "type": "web_search",
278 "name": "web_search",
279 "allowed_domains": ["docs.example.com", "arxiv.org"],
280 "user_location": {
281 "type": "approximate",
282 "country": "US",
283 "timezone": "America/Los_Angeles"
284 }
285 },
286 {
287 "type": "web_fetch",
288 "name": "web_fetch",
289 "blocked_domains": ["ads.example.com"],
290 "max_content_tokens": 50000
291 }
292 ]
293 }
294 ]
295 }
296 EOF
297 )
298 jq '.tools[0].configs' <<< "$agent"
299 ```
300 
301 ```bash CLI
302 ant beta:agents create --transform tools.0.configs <<'YAML'
303 name: Research Agent
304 model: claude-opus-5
305 tools:
306 - type: agent_toolset_20260401
307 configs:
308 - type: web_search
309 name: web_search
310 allowed_domains: [docs.example.com, arxiv.org]
311 user_location:
312 type: approximate
313 country: US
314 timezone: America/Los_Angeles
315 - type: web_fetch
316 name: web_fetch
317 blocked_domains: [ads.example.com]
318 max_content_tokens: 50000
319 YAML
320 ```
321 
322 ```python Python
323 client = Anthropic()
324 
325 agent = client.beta.agents.create(
326 name="Research Agent",
327 model="claude-opus-5",
328 tools=[
329 {
330 "type": "agent_toolset_20260401",
331 "configs": [
332 {
333 "name": "web_search",
334 "allowed_domains": ["docs.example.com", "arxiv.org"],
335 "user_location": {
336 "type": "approximate",
337 "country": "US",
338 "timezone": "America/Los_Angeles",
339 },
340 },
341 {
342 "name": "web_fetch",
343 "blocked_domains": ["ads.example.com"],
344 "max_content_tokens": 50_000,
345 },
346 ],
347 }
348 ],
349 )
350 
351 for tool in agent.tools:
352 if tool.type == "agent_toolset_20260401":
353 print(json.dumps([config.to_dict() for config in tool.configs], indent=2))
354 ```
355 
356 ```typescript TypeScript
357 const client = new Anthropic();
358 
359 const agent = await client.beta.agents.create({
360 name: "Research Agent",
361 model: "claude-opus-5",
362 tools: [
363 {
364 type: "agent_toolset_20260401",
365 configs: [
366 {
367 name: "web_search",
368 allowed_domains: ["docs.example.com", "arxiv.org"],
369 user_location: {
370 type: "approximate",
371 country: "US",
372 timezone: "America/Los_Angeles"
373 }
374 },
375 {
376 name: "web_fetch",
377 blocked_domains: ["ads.example.com"],
378 max_content_tokens: 50_000
379 }
380 ]
381 }
382 ]
383 });
384 
385 for (const tool of agent.tools) {
386 if (tool.type === "agent_toolset_20260401") {
387 console.log(JSON.stringify(tool.configs, null, 2));
388 }
389 }
390 ```
391 
392 ```csharp C#
393 using Anthropic.Models.Beta.Agents;
394 
395 AnthropicClient client = new();
396 
397 var agent = await client.Beta.Agents.Create(new()
398 {
399 Name = "Research Agent",
400 Model = BetaManagedAgentsModel.ClaudeOpus5,
401 Tools =
402 [
403 new BetaManagedAgentsAgentToolset20260401Params
404 {
405 Type = BetaManagedAgentsAgentToolset20260401ParamsType.AgentToolset20260401,
406 Configs =
407 [
408 new BetaManagedAgentsWebSearchToolConfigParams
409 {
410 AllowedDomains = ["docs.example.com", "arxiv.org"],
411 UserLocation = new()
412 {
413 Country = "US",
414 Timezone = "America/Los_Angeles",
415 },
416 },
417 new BetaManagedAgentsWebFetchToolConfigParams
418 {
419 BlockedDomains = ["ads.example.com"],
420 MaxContentTokens = 50_000,
421 },
422 ],
423 },
424 ],
425 });
426 
427 JsonSerializerOptions jsonOptions = new() { WriteIndented = true };
428 foreach (var tool in agent.Tools)
429 {
430 if (tool.TryPickBetaManagedAgentsAgentToolset20260401(out var toolset))
431 {
432 Console.WriteLine(JsonSerializer.Serialize(toolset.Configs, jsonOptions));
433 }
434 }
435 ```
436 
437 ```go Go
438 client := anthropic.NewClient()
439 ctx := context.Background()
440 
441 agent, err := client.Beta.Agents.New(ctx, anthropic.BetaAgentNewParams{
442 Name: "Research Agent",
443 Model: anthropic.BetaManagedAgentsModelConfigParams{
444 ID: anthropic.BetaManagedAgentsModelClaudeOpus5,
445 },
446 Tools: []anthropic.BetaAgentNewParamsToolUnion{{
447 OfAgentToolset20260401: &anthropic.BetaManagedAgentsAgentToolset20260401Params{
448 Type: anthropic.BetaManagedAgentsAgentToolset20260401ParamsTypeAgentToolset20260401,
449 Configs: []anthropic.BetaManagedAgentsAgentToolConfigUnionParamsUnion{
450 {OfBetaManagedAgentsWebSearchToolConfigs: &anthropic.BetaManagedAgentsWebSearchToolConfigParams{
451 AllowedDomains: []string{"docs.example.com", "arxiv.org"},
452 UserLocation: anthropic.BetaManagedAgentsUserLocationParam{
453 Country: anthropic.String("US"),
454 Timezone: anthropic.String("America/Los_Angeles"),
455 },
456 }},
457 {OfBetaManagedAgentsWebFetchToolConfigs: &anthropic.BetaManagedAgentsWebFetchToolConfigParams{
458 BlockedDomains: []string{"ads.example.com"},
459 MaxContentTokens: anthropic.Int(50000),
460 }},
461 },
462 },
463 }},
464 })
465 if err != nil {
466 panic(err)
467 }
468 
469 for _, tool := range agent.Tools {
470 switch toolset := tool.AsAny().(type) {
471 case anthropic.BetaManagedAgentsAgentToolset20260401:
472 configs := make([]json.RawMessage, len(toolset.Configs))
473 for i, config := range toolset.Configs {
474 configs[i] = json.RawMessage(config.RawJSON())
475 }
476 output, err := json.MarshalIndent(configs, "", " ")
477 if err != nil {
478 panic(err)
479 }
480 fmt.Println(string(output))
481 }
482 }
483 ```
484 
485 ```java Java
486 import com.anthropic.models.beta.agents.AgentCreateParams;
487 import com.anthropic.models.beta.agents.BetaManagedAgentsAgentToolset20260401Params;
488 import com.anthropic.models.beta.agents.BetaManagedAgentsModel;
489 import com.anthropic.models.beta.agents.BetaManagedAgentsUserLocation;
490 import com.anthropic.models.beta.agents.BetaManagedAgentsWebFetchToolConfigParams;
491 import com.anthropic.models.beta.agents.BetaManagedAgentsWebSearchToolConfigParams;
492 
493 void main() {
494 var client = AnthropicOkHttpClient.fromEnv();
495 
496 var agent = client.beta().agents().create(AgentCreateParams.builder()
497 .name("Research Agent")
498 .model(BetaManagedAgentsModel.CLAUDE_OPUS_5)
499 .addTool(BetaManagedAgentsAgentToolset20260401Params.builder()
500 .type(BetaManagedAgentsAgentToolset20260401Params.Type.AGENT_TOOLSET_20260401)
501 .addConfig(BetaManagedAgentsWebSearchToolConfigParams.builder()
502 .allowedDomains(List.of("docs.example.com", "arxiv.org"))
503 .userLocation(BetaManagedAgentsUserLocation.builder()
504 .country("US")
505 .timezone("America/Los_Angeles")
506 .build())
507 .build())
508 .addConfig(BetaManagedAgentsWebFetchToolConfigParams.builder()
509 .blockedDomains(List.of("ads.example.com"))
510 .maxContentTokens(50_000)
511 .build())
512 .build())
513 .build());
514 
515 for (var tool : agent.tools()) {
516 if (tool.isAgentToolset20260401()) {
517 var configs = tool.asAgentToolset20260401().configs();
518 IO.println(ObjectMappers.jsonMapper().valueToTree(configs));
519 }
520 }
521 }
522 ```
523 
524 ```php PHP
525 use Anthropic\Beta\Agents\BetaManagedAgentsAgentToolset20260401;
526 use Anthropic\Beta\Agents\BetaManagedAgentsAgentToolset20260401Params;
527 use Anthropic\Beta\Agents\BetaManagedAgentsUserLocation;
528 use Anthropic\Beta\Agents\BetaManagedAgentsWebFetchToolConfigParams;
529 use Anthropic\Beta\Agents\BetaManagedAgentsWebSearchToolConfigParams;
530 // ...
531 
532 $client = new Client();
533 
534 $agent = $client->beta->agents->create(
535 name: 'Research Agent',
536 model: 'claude-opus-5',
537 tools: [
538 BetaManagedAgentsAgentToolset20260401Params::with(
539 type: 'agent_toolset_20260401',
540 configs: [
541 BetaManagedAgentsWebSearchToolConfigParams::with(
542 allowedDomains: ['docs.example.com', 'arxiv.org'],
543 userLocation: BetaManagedAgentsUserLocation::with(
544 country: 'US',
545 timezone: 'America/Los_Angeles',
546 ),
547 ),
548 BetaManagedAgentsWebFetchToolConfigParams::with(
549 blockedDomains: ['ads.example.com'],
550 maxContentTokens: 50_000,
551 ),
552 ],
553 ),
554 ],
555 );
556 
557 foreach ($agent->tools as $tool) {
558 if ($tool instanceof BetaManagedAgentsAgentToolset20260401) {
559 echo json_encode($tool->configs, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), PHP_EOL;
560 }
561 }
562 ```
563 
564 ```ruby Ruby
565 client = Anthropic::Client.new
566 
567 agent = client.beta.agents.create(
568 name: "Research Agent",
569 model: "claude-opus-5",
570 tools: [
571 {
572 type: :agent_toolset_20260401,
573 configs: [
574 {
575 name: :web_search,
576 allowed_domains: ["docs.example.com", "arxiv.org"],
577 user_location: {type: :approximate, country: "US", timezone: "America/Los_Angeles"}
578 },
579 {
580 name: :web_fetch,
581 blocked_domains: ["ads.example.com"],
582 max_content_tokens: 50_000
583 }
584 ]
585 }
586 ]
587 )
588 
589 case agent.tools.first
590 in Anthropic::Models::Beta::BetaManagedAgentsAgentToolset20260401 => toolset
591 puts JSON.pretty_generate(toolset.configs.map(&:to_h))
592 end
593 ```
594</CodeGroup>
595 
596In the Claude Console, set allowed or blocked domains from the `web_search` and `web_fetch` rows of the **Built-in tools** card on the agent form; set `max_content_tokens` and `user_location` in the **Raw** view of the agent's configuration.
597 
598In addition to `enabled` and `permission_policy`, the web tool entries accept the following settings:
599 
600| Setting | Applies to | Description |
601| -------------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
602| `allowed_domains` | `web_search`, `web_fetch` | The only hosts the tool can reach. Cannot be combined with `blocked_domains` on the same entry. |
603| `blocked_domains` | `web_search`, `web_fetch` | Hosts the tool cannot reach. |
604| `max_content_tokens` | `web_fetch` | Caps the amount of fetched page content included in the context. Must be a positive integer. See [content limits](https://platform.claude.com/docs/en/agents-and-tools/tool-use/web-fetch-tool#content-limits). |
605| `user_location` | `web_search` | Localizes search results. An object with the same fields as the Messages API [`user_location`](https://platform.claude.com/docs/en/agents-and-tools/tool-use/web-search-tool#localization) parameter. |
606 
607<Note>
608 An environment's [`networking`](https://platform.claude.com/docs/en/managed-agents/environments#networking) settings control the sandbox's own outbound traffic. They do not affect `web_search` or `web_fetch`, which run on Anthropic's servers whether the environment is a cloud or self-hosted sandbox. The per-tool `allowed_domains` and `blocked_domains` lists are the way to restrict what these tools can reach.
609</Note>
610 
611<Note>
612 Organization-level web search and web fetch settings in the Claude Console apply to the Messages API and do not apply to Managed Agents sessions. To restrict an agent's web tools, configure `allowed_domains` or `blocked_domains` on its toolset instead.
613</Note>
614 
615#### Domain list rules
616 
617* Set either `allowed_domains` or `blocked_domains` on an entry, not both. An entry that sets both is rejected.
618* Each list holds 1 to 64 domains, each 1 to 255 characters. An empty list is rejected: to apply no restriction, omit the field or send `null`.
619* Each domain is a registrable domain name, or a subdomain of one, written as a plain hostname: ASCII letters, digits, hyphens, underscores, and dots, with no scheme, port, credentials, wildcard, or whitespace, no label that begins or ends with a hyphen, and no path other than the optional `web_search` path suffix described later in this list. Use `example.com`, not `https://example.com`, `example.com:443`, or `*.example.com`. Hostnames are compared without regard to case, and a single trailing `/` is ignored.
620* A listed domain matches that host and its subdomains: `example.com` covers `docs.example.com`, but `docs.example.com` does not cover `example.com` or `api.example.com`. A leading `www.` is a subdomain like any other, so `www.example.com` does not cover `example.com`; list the bare domain to cover both.
621* IP addresses are not accepted in any form, whether IPv4, IPv6, bracketed, or numeric shorthand such as `127.1`. List the site's domain name instead.
622* A bare top-level domain or registry suffix such as `com`, `co.uk`, or `gov.uk` is rejected, and so is a single-label name such as `intranet`. List a full domain such as `example.co.uk`.
623* `localhost` and hosts ending in `.localhost`, `.local`, `.internal`, `.localdomain`, or `.invalid` are rejected.
624* Use the `xn--` (Punycode) form for internationalized domain names; a domain that contains non-ASCII characters is rejected.
625* A `web_fetch` domain cannot include a path: use `example.com`, not `example.com/*`. A `web_search` domain can carry a path suffix such as `example.com/blog`, in which the path cannot contain spaces, `?`, `#`, or any of the characters `$ , | ^ !`. Prefer plain hostnames for `web_search` too, because the search provider matches path suffixes as URL patterns rather than as strict host rules.
626* Duplicate domains within a list are rejected. `www.example.com` and `example.com` count as different domains; see the earlier matching rule for what each covers.
627 
628#### When settings are validated
629 
630Format and limit violations are rejected with a 400 `invalid_request_error` when you [create an agent](https://platform.claude.com/docs/en/managed-agents/agent-setup#create-an-agent) or [update an agent](https://platform.claude.com/docs/en/managed-agents/agent-setup#update-an-agent), and when you create or update a session that supplies `tools`. For example, the message for an entry that sets both lists includes `Only one of allowed_domains or blocked_domains may be set.`, and the message for an empty list includes `allowed_domains: Empty list of domains is ambiguous. Provide at least one domain or null.` The message for a domain that breaks a format rule names its list and zero-based position, for example `allowed_domains.0: IP addresses are not supported; provide a plain hostname like "example.com"`.
631 
632The same requests also reject three settings that depend on the search and fetch providers: a domain in `allowed_domains` that Anthropic's crawler is not permitted to access, a `user_location.country` that the search provider does not support (the message ends in `user_location.country: not a country the search provider supports`), and a `user_location.timezone` that is not a valid IANA name. The session checks the configuration again when it first initializes the tool; if a setting that was accepted earlier is no longer valid at that point, the session emits a [`session.error`](https://platform.claude.com/docs/en/managed-agents/events-and-streaming) event and returns to `idle` without retrying. Fix the setting by [updating the session's tools](https://platform.claude.com/docs/en/managed-agents/session-operations#updating-the-agent-configuration), update the agent as well so that new sessions start with the corrected configuration, then send a new `user.message` to continue.
633 
634#### Multiagent sessions, outcomes, and mid-session updates
635 
636In a [multiagent session](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration), every domain list that applies to a thread is enforced at the same time: an agent in the roster of the coordinator is bound by its own `allowed_domains` and `blocked_domains`, by those of any agent that called it, and by the coordinator's current lists.
637 
638* Allowlists combine to the domains that all of them cover, and blocklists add together, so a roster agent can narrow what a tool reaches but never widen it. For example, a roster agent that sets `blocked_domains` keeps the coordinator's `allowed_domains` and blocks those hosts within it, and a roster agent that sets its own `allowed_domains` can reach only the hosts that both its list and the coordinator's list cover.
639* If the combined allowlists have no domain in common, the tool stays available to that agent but every call fails with a `url_not_allowed` error stating that no domain is permitted, and the tool description tells the model so. Keep each roster agent's allowlist inside the coordinator's to avoid this.
640* `max_content_tokens` and `user_location` are not combined: a thread uses the value from its own tool configuration if set, otherwise from the agent that called it, otherwise from the coordinator's current configuration.
641* A `{"type": "self"}` roster entry has no web settings of its own and follows the coordinator's current settings.
642* The grader in [outcome-driven sessions](https://platform.claude.com/docs/en/managed-agents/define-outcomes) runs without `web_search` and `web_fetch`, regardless of these settings.
643* You can change the lists on an idle session by [updating its tools](https://platform.claude.com/docs/en/managed-agents/session-operations#updating-the-agent-configuration). The new lists apply to the rest of the session; in a multiagent session, every thread applies them from its next turn, while a roster agent's own lists stay as its agent definition set them when the session was created.
644 
645#### Differences from the Messages API tools
646 
647These settings use the same `allowed_domains` and `blocked_domains` vocabulary as [domain filtering](https://platform.claude.com/docs/en/agents-and-tools/tool-use/server-tools#domain-filtering) on the Messages API server tools, with the following differences on Managed Agents:
648 
649* Each list is capped at 64 domains.
650* Domains listed for `web_fetch` cannot include a path.
651* `max_uses`, `citations`, and `cache_control` are not available on the toolset.
222652 
223653## Custom tools
224654 
225655 

release-notes/overview Changed · +8 / -0 lines

from line 14
1414 
1515* The [Admin API](https://platform.claude.com/docs/en/api/admin) user-management endpoints for **Claude Enterprise** (claude.ai) organizations (members, invites, groups, and custom roles) are now generally available. The `anthropic-beta: ce-user-management-2026-07-13` header is no longer required on group and custom-role requests; requests that still send it are accepted unchanged. See [User management](https://platform.claude.com/docs/en/manage-claude/user-management).
1616 
17- The [Files API](https://platform.claude.com/docs/en/build-with-claude/files) is now generally available on the Claude API. Requests to the `/v1/files` endpoints, and Messages API requests that reference an uploaded file, no longer require the `files-api-2025-04-14` beta header. Requests sent without the header use the GA response format: [file expiration](https://platform.claude.com/docs/en/build-with-claude/files#file-expiration) (set `expires_in_seconds` when you upload a file; file objects report `expires_at`), and `page` and `next_page` [pagination](https://platform.claude.com/docs/en/api/overview#pagination) plus an `ids[]` filter when you [list files](https://platform.claude.com/docs/en/build-with-claude/files#list-files). Storage is 1 TB per organization and the rate limit is 500 requests per minute. `/v1/files` requests that still send the beta header keep working and return the previous response format.
18 
19* [Agent Skills](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview) and the Skills API (`/v1/skills`) are now generally available on the Claude API. Requests no longer require the `skills-2025-10-02` beta header, including Messages API requests that load Skills through the `container` parameter. Requests that still send the header continue to work unchanged. See [Using Agent Skills with the API](https://platform.claude.com/docs/en/build-with-claude/skills-guide).
20 
21- You can now restrict which sites a Claude Managed Agents agent's `web_search` and `web_fetch` tools can reach. Set `allowed_domains` or `blocked_domains` on the tool's entry in the `agent_toolset_20260401` `configs` array; `web_fetch` also accepts `max_content_tokens` and `web_search` accepts `user_location`. Each `configs` entry is identified by its `name` and typed by an optional `type`, and requests that pass only `name`, `enabled`, and `permission_policy` continue to work; in the typed SDKs, `configs` entries become per-tool types. See [Restrict web search and web fetch domains](https://platform.claude.com/docs/en/managed-agents/tools#restrict-web-search-and-web-fetch-domains).
22- Claude Managed Agents sessions that run in a [self-hosted sandbox](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes) can now attach [memory stores](https://platform.claude.com/docs/en/managed-agents/memory). The Python, TypeScript, and Go SDK workers download each attached store into the sandbox at its `mount_path` and sync the agent's changes back to the store. See [Use memory stores](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#use-memory-stores).
23- The session viewer in the Claude Console has been redesigned with a timeline minimap, a transcript grouped by model request, and an Inspector panel for session details and cost, raw events, per-tool statistics, mounted resources, and per-thread activity. See [Console observability](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#console-observability).
24 
1725### August 18, 2026
1826 
1927* Workbench is now [**Playground**](https://platform.claude.com/playground) in the Claude Console. Playground supports every Messages API parameter and includes templates that demonstrate API features such as code execution and web search. It shows the full SDK request and the API response for each run, to help you understand the API and build with it. For more, see the [Claude Help Center](https://support.claude.com/en/articles/8606378-how-do-i-use-playground) or try it at [platform.claude.com/playground](https://platform.claude.com/playground).

agents-and-tools/agent-skills/enterprise Changed · +1 / -1 lines

from line 115
115115 
116116As a general guideline, limit the number of Skills loaded simultaneously to maintain reliable recall accuracy. Each Skill's metadata (name and description) competes for attention in the system prompt. With too many Skills active, Claude may fail to select the right Skill or miss relevant ones entirely. Use your evaluation suite to measure recall accuracy as you add Skills, and stop adding when performance degrades.
117117 
118Note that API requests support a maximum of 8 Skills for each request (see [Using Skills with the API](https://platform.claude.com/docs/en/build-with-claude/skills-guide)). If a role requires more Skills than a single request supports, consider consolidating narrow Skills into broader ones or routing requests to different Skill sets based on task type.
118Note that API requests support a maximum of 20 Skills for each request (see [Using Skills with the API](https://platform.claude.com/docs/en/build-with-claude/skills-guide)). If a role requires more Skills than a single request supports, consider consolidating narrow Skills into broader ones or routing requests to different Skill sets based on task type.
119119 
120120### Start specific, consolidate later
121121 

agents-and-tools/tool-use/code-execution-tool Changed · +1 / -1 lines

from line 278
278278To analyze your own data files (such as CSV, Excel, or images), upload them through the Files API and reference them in your request:
279279 
280280<Note>
281 Using the Files API with code execution requires the Files API beta header: `"anthropic-beta": "files-api-2025-04-14"`
281 This workflow doesn't require a beta header: uploading and downloading files through the Files API and referencing them in `container_upload` blocks are all generally available. The examples on this page send `anthropic-beta: files-api-2025-04-14`, which the API accepts but doesn't require.
282282</Note>
283283 
284284The Python environment can process various file types uploaded through the Files API, including:

agents-and-tools/tool-use/server-tools Changed · +4 / -0 lines

from line 1071
10711071 Unicode characters in domain names can bypass domain filters through homograph attacks: `аmazon.com` (with a Cyrillic `а`) looks identical to `amazon.com` but is a different domain. Use ASCII-only domain names in allow and block lists, and audit existing entries for non-ASCII characters.
10721072</Warning>
10731073 
1074[Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview) uses the same `allowed_domains` and `blocked_domains` fields on the `web_search` and `web_fetch` entries of the agent toolset. On Managed Agents, each list holds at most 64 entries, domains listed for `web_fetch` cannot include a path, and fields specific to the Messages API tools, such as `max_uses`, `citations`, and `cache_control`, are not available. See [Restrict web search and web fetch domains](https://platform.claude.com/docs/en/managed-agents/tools#restrict-web-search-and-web-fetch-domains) for the full rules.
1075 
1076Organization-level web search and web fetch settings in the Claude Console apply to Messages API requests only; they do not apply to Managed Agents sessions, which use only the per-tool lists on the agent toolset.
1077 
10741078## Dynamic filtering with code execution
10751079 
10761080The `_20260209` and later versions of web search and web fetch use code execution internally to apply dynamic filters against search results.

agents-and-tools/tool-use/web-fetch-tool Changed · +4 / -0 lines

from line 446
446446 
447447For domain filtering with `allowed_domains` and `blocked_domains`, see [Server tools](https://platform.claude.com/docs/en/agents-and-tools/tool-use/server-tools#domain-filtering).
448448 
449On [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview), set these fields on the `web_fetch` entry of the agent toolset, where each listed domain must be a plain hostname with no path; see [Restrict web search and web fetch domains](https://platform.claude.com/docs/en/managed-agents/tools#restrict-web-search-and-web-fetch-domains).
450 
449451### Content limits
450452 
451453The `max_content_tokens` parameter limits the amount of content included in the context. If the fetched content exceeds this limit, the tool truncates it. This helps control token usage when fetching large documents. The limit applies to text content, not to binary content such as PDFs.
from line 455
453455<Note>
454456 The `max_content_tokens` parameter limit is approximate. The actual number of input tokens used can vary by a small amount.
455457</Note>
458 
459On Claude Managed Agents, the `web_fetch` entry of the agent toolset also accepts `max_content_tokens`; see [Restrict web search and web fetch domains](https://platform.claude.com/docs/en/managed-agents/tools#restrict-web-search-and-web-fetch-domains).
456460 
457461### Cache bypass
458462 

build-with-claude/citations Changed · +2 / -2 lines

from line 740
740740 
741741 <Tab title="Files API">
742742 <Note>
743 Files API document sources are in beta. These examples use the beta client path; see [Files API](https://platform.claude.com/docs/en/build-with-claude/files) for upload details.
743 These examples reference the uploaded file as a `document` source. They use the SDK `beta` client path and send the `anthropic-beta: files-api-2025-04-14` header, which the API accepts but does not require. See [Files API](https://platform.claude.com/docs/en/build-with-claude/files) for upload details.
744744 </Note>
745745 
746746 <CodeGroup>
from line 1571
15711571 
15721572 <Tab title="Files API">
15731573 <Note>
1574 Files API document sources are in beta. These examples use the beta client path; see [Files API](https://platform.claude.com/docs/en/build-with-claude/files) for upload details.
1574 These examples reference the uploaded file as a `document` source. They use the SDK `beta` client path and send the `anthropic-beta: files-api-2025-04-14` header, which the API accepts but does not require. See [Files API](https://platform.claude.com/docs/en/build-with-claude/files) for upload details.
15751575 </Note>
15761576 
15771577 <CodeGroup>

build-with-claude/claude-platform-on-aws Changed · +2 / -1 lines

from line 550
550550 
551551[Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview) is available on Claude Platform on AWS, including [agents](https://platform.claude.com/docs/en/managed-agents/agent-setup), [environments](https://platform.claude.com/docs/en/managed-agents/environments), [sessions](https://platform.claude.com/docs/en/managed-agents/sessions), [credential vaults](https://platform.claude.com/docs/en/managed-agents/vaults), [memory stores](https://platform.claude.com/docs/en/managed-agents/memory), [webhooks](https://platform.claude.com/docs/en/managed-agents/webhooks), [multiagent orchestration](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration), and [self-hosted sandboxes](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes).
552552 
553Session behavior on Claude Platform on AWS differs from first-party Claude Managed Agents in one way:
553Session behavior on Claude Platform on AWS differs from first-party Claude Managed Agents in two ways:
554554 
555555* **Autonomous-session reauthentication:** A session can run autonomously, without any [user events](https://platform.claude.com/docs/en/managed-agents/reference#event-types), for up to 6 hours. After 6 hours, the session requires reauthentication before it continues. To reauthenticate, send any user-role event to the session (see [Events and streaming](https://platform.claude.com/docs/en/managed-agents/events-and-streaming)). First-party Claude Managed Agents has no autonomous-session runtime limit.
556* **[Memory stores on self-hosted environments](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#use-memory-stores):** A session that runs on a self-hosted environment cannot attach memory stores; a session that includes one is rejected at creation. Sessions on cloud environments attach memory stores as usual. On first-party Claude Managed Agents, sessions on both cloud and self-hosted environments can attach memory stores.
556557 
557558### Features not supported
558559 

build-with-claude/pdf-support Changed · +1 / -1 lines

from line 704
704704 
705705#### Option 3: Files API
706706 
707For PDFs you'll use repeatedly, or when you want to avoid encoding overhead, use the [Files API](https://platform.claude.com/docs/en/build-with-claude/files) (beta):
707For PDFs you'll use repeatedly, or when you want to avoid encoding overhead, use the [Files API](https://platform.claude.com/docs/en/build-with-claude/files). These examples send the `anthropic-beta: files-api-2025-04-14` header, which the API accepts but doesn't require:
708708 
709709<CodeGroup>
710710 ```bash cURL

manage-claude/api-and-data-retention Changed · +1 / -1 lines

from line 183
183183| [Data residency](https://platform.claude.com/docs/en/manage-claude/data-residency) | `/v1/messages` (with `inference_geo`) | <Eligible>Yes</Eligible> | <Eligible>Yes</Eligible> | |
184184| [Effort](https://platform.claude.com/docs/en/build-with-claude/effort) | `/v1/messages` (with `effort`) | <Eligible>Yes</Eligible> | <Eligible>Yes</Eligible> | |
185185| [Fast mode](https://platform.claude.com/docs/en/build-with-claude/fast-mode) | `/v1/messages` (with `speed: "fast"`) | <Eligible>Yes</Eligible> | <Eligible>Yes</Eligible> | Same Messages API endpoint with faster inference. ZDR applies regardless of speed setting. |
186| [Files API](https://platform.claude.com/docs/en/build-with-claude/files) | `/v1/files` | <Eligible status="no">No</Eligible> | <Eligible status="no">No</Eligible> | Files retained until explicitly deleted. See [Files API](https://platform.claude.com/docs/en/build-with-claude/files#data-retention). |
186| [Files API](https://platform.claude.com/docs/en/build-with-claude/files) | `/v1/files` | <Eligible status="no">No</Eligible> | <Eligible status="no">No</Eligible> | Files retained until explicitly deleted or they reach their configured expiration. See [Files API](https://platform.claude.com/docs/en/build-with-claude/files#data-retention). |
187187| [Fine-grained tool streaming](https://platform.claude.com/docs/en/agents-and-tools/tool-use/fine-grained-tool-streaming) | `/v1/messages` | <Eligible>Yes</Eligible> | <Eligible>Yes</Eligible> | |
188188| [MCP connector](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector) | `/v1/messages` (with `mcp_servers`) | <Eligible status="no">No</Eligible> | <Eligible status="no">No</Eligible> | Data retained per standard policy. See [MCP connector](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector#data-retention). |
189189| [MCP tunnels](https://platform.claude.com/docs/en/agents-and-tools/mcp-tunnels/overview) | `/v1/tunnels` | <Eligible status="no">No</Eligible> | <Eligible status="no">No</Eligible> | Research preview. See [MCP tunnels security](https://platform.claude.com/docs/en/agents-and-tools/mcp-tunnels/security) for the data-flow boundary and subprocessor details. |

manage-claude/data-residency Changed · +1 / -1 lines

from line 10
1010* **Workspace geo:** Controls where data is stored at rest and where endpoint processing (such as image transcoding and code execution) happens. Configured at the workspace level in the [Claude Console](https://platform.claude.com).
1111 
1212<Note>
13 [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview) supports geographic pinning at the agent level: `inference_geo` on an [agent's model configuration](https://platform.claude.com/docs/en/managed-agents/agent-setup#pin-the-inference-geo) pins the geography that serves model requests for sessions running that agent, with [per-session overrides](https://platform.claude.com/docs/en/managed-agents/sessions#pin-the-inference-geo-for-a-session) at session create. Agents without a pin follow the workspace's default inference geo on each request. Managed Agents also respects the Workspace geo configured in Console, and with [self-hosted sandboxes](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes), tool execution and the sandbox filesystem stay on infrastructure you control.
13 [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview) supports geographic pinning at the agent level: `inference_geo` on an [agent's model configuration](https://platform.claude.com/docs/en/managed-agents/agent-setup#pin-the-inference-geo) pins the geography that serves model requests for sessions running that agent, with [per-session overrides](https://platform.claude.com/docs/en/managed-agents/sessions#pin-the-inference-geo-for-a-session) at session create. Agents without a pin follow the workspace's default inference geo on each request. Managed Agents also respects the Workspace geo configured in Console, and with [self-hosted sandboxes](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes), tool execution and the sandbox filesystem stay on infrastructure you control; the contents of attached [memory stores](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#use-memory-stores) remain stored by Anthropic and are copied to your sandbox for the session.
1414</Note>
1515 
1616## Inference geo

manage-claude/workspaces Changed · +2 / -2 lines

from line 13
1313Key characteristics:
1414 
1515* **Workspace identifiers** use the `wrkspc_` prefix (for example, `wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ`)
16* **Maximum 100 workspaces** per organization (archived workspaces don't count)
16* **Maximum 100 workspaces** per organization by default (archived workspaces don't count); contact your account team if you need more
1717* **Default Workspace** has a `wrkspc_` ID like any other workspace (returned in the [`anthropic-workspace-id` response header](https://platform.claude.com/docs/en/manage-claude/workspaces#identify-the-workspace-behind-an-api-response) and accepted by [Get Workspace](https://platform.claude.com/docs/en/api/admin/workspaces/retrieve)), but it doesn't appear in [List Workspaces](https://platform.claude.com/docs/en/api/admin/workspaces/list) results, and API keys, usage reports, and cost reports show `null` for its `workspace_id`
1818* **API keys** are scoped to a single workspace and can only access resources within that workspace
1919 
from line 477
477477 </Accordion>
478478 
479479 <Accordion title="Are there limits on workspaces?">
480 Yes, you can have a maximum of 100 workspaces per organization. Archived workspaces do not count toward this limit.
480 Yes. Each organization can have up to 100 workspaces by default, and archived workspaces don't count toward this limit. If you need more, contact your account team.
481481 </Accordion>
482482 
483483 <Accordion title="How do organization roles affect workspace access?">

managed-agents/define-outcomes Changed · +1 / -1 lines

from line 55
5555Pass the rubric as inline text on `user.define_outcome` (see [Create a session with an outcome](https://platform.claude.com/docs/en/managed-agents/define-outcomes#create-a-session-with-an-outcome)), or upload it through the Files API for reuse across sessions.
5656 
5757<Note>
58 Uploading through the Files API requires a beta header that grants Files API access. Your Managed Agents beta header grants this on its own, so you don't need to send `files-api-2025-04-14` alongside it. The curl example passes its headers explicitly.
58 Uploading through the Files API doesn't require a beta header. The cURL example sends the `managed-agents-2026-04-01` header it uses throughout this walkthrough, which the Files API also accepts.
5959</Note>
6060 
6161<CodeGroup>
Feedback