Source Intelligence
Sweep 28 Aug 2026 · 00:00Z Build v2.1.250 478 read Stable v2.1.236 Latest v2.1.250 Next v2.1.250 Feeds RSS JSON llms.txt

DisclaimerUnofficial, and not affiliated with Anthropic. Nearly all of this is read straight out of what ships: npm bundles, captured prompts, published docs. Anthropic's own notes go in verbatim, marked as theirs. The rest is my reading, and every entry carries the strings behind it. If one looks wrong, vote it down and say why.

Capture

One read of Claude Developer Platform

34 pages moved out of 567 read.

corpus-hash api-20260819T220710Z

managed-agents/reference Changed · +2 / -0 lines

from line 103
 | `--max-idle`           | How long to wait after the session goes idle with an `end_turn` [stop reason](https://platform.claude.com/docs/en/api/handling-stop-reasons) before shutting down. Defaults to `60s`. |
 | `--log-format`         | Log output format. Use `json` for structured log ingestion. Defaults to `text`.                                                                                                       |
 
+The CLI worker does not mount [memory stores](https://platform.claude.com/docs/en/managed-agents/memory): a session that attaches one still runs, but the agent finds nothing at the store's `mount_path` and no changes sync back to the store. To use memory stores in sessions on a self-hosted environment, run the SDK worker instead; see [Use memory stores](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#use-memory-stores).
+
 ## Supported MCP server types
 
 Claude Managed Agents connects to [remote MCP servers](https://platform.claude.com/docs/en/agents-and-tools/remote-mcp-servers) that expose an HTTP endpoint, or to private MCP servers through [MCP tunnels](https://platform.claude.com/docs/en/agents-and-tools/mcp-tunnels/overview). The server should support the MCP protocol's streamable HTTP transport; servers that only support the deprecated SSE transport still work through an automatic fallback. See [MCP connector](https://platform.claude.com/docs/en/managed-agents/mcp-connector) for declaring servers on an agent.

managed-agents/migration Changed · +1 / -0 lines

from line 598
 
 * **System prompt and model:** Same fields, now on the agent definition.
 * **Custom tools:** Still declared with JSON Schema. Execution moves from inline handling to responding to `agent.custom_tool_use` events. See [Session event stream](https://platform.claude.com/docs/en/managed-agents/events-and-streaming).
+* **Web search and web fetch settings:** Same `allowed_domains`, `blocked_domains`, `max_content_tokens`, and `user_location` fields, now set once on the `web_search` and `web_fetch` entries of the agent toolset's `configs` array instead of on every request. The `max_uses`, `citations`, and `cache_control` fields 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).
 * **Context:** You can still inject context through the system prompt, [file resources](https://platform.claude.com/docs/en/managed-agents/files), or [skills](https://platform.claude.com/docs/en/managed-agents/skills).
 
 ## From the Claude Agent SDK

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

from line 237
   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.
 </Note>
 
+These 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).
+
 Provide the web search tool in your API request:
 
 <CodeGroup>
from line 448
 
 For 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.
 
+On [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).
+
 ### Localization
 
 The `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
 * `region`: The region or state
 * `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.
 * `timezone`: The [IANA timezone ID](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).
+
+On 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).
 
 ### Response inclusion
 

managed-agents/environments Changed · +1 / -1 lines

from line 383
 
 ### Networking
 
-The `networking` field controls the sandbox's outbound network access. It does not affect the allowed domains for the `web_search` or `web_fetch` tools.
+The `networking` field controls the sandbox's outbound network access. It does not affect the `web_search` or `web_fetch` tools, which run on Anthropic's servers; to restrict the sites those tools can reach, set `allowed_domains` or `blocked_domains` on the tool's entry in 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).
 
 | Mode           | Description                                                                                                                                                  |
 | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |

api/overview Changed · +3 / -3 lines

from line 29
 * **[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`)
 * **[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`)
 * **[Models API](https://platform.claude.com/docs/en/api/models/list)**: List available Claude models and their details (`GET /v1/models`)
+* **[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`)
+* **[Skills API](https://platform.claude.com/docs/en/api/skills/create-skill)**: Create and manage custom agent skills (`POST /v1/skills`, `GET /v1/skills`)
 
 **Beta:**
 
-* **[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`)
-* **[Skills API](https://platform.claude.com/docs/en/api/skills/create-skill)**: Create and manage custom agent skills (`POST /v1/skills`, `GET /v1/skills`)
 * **[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`)
 * **[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`)
 * **[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
 Every 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.
 
 <Note>
-  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.
+  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.
 </Note>
 
 ## Rate limits and availability

managed-agents/session-operations Changed · +1 / -1 lines

from line 23
 
 ## Updating the agent configuration
 
-You can update a session's `agent.tools` and `agent.mcp_servers`, including permission policies, mid-session without creating a new agent version. Updates are session-local and do not propagate back to the underlying agent.
+You can update a session's `agent.tools` and `agent.mcp_servers`, including permission policies and per-tool web settings such as [domain filters](https://platform.claude.com/docs/en/managed-agents/tools#restrict-web-search-and-web-fetch-domains), mid-session without creating a new agent version. Updates are session-local and do not propagate back to the underlying agent. Updated `allowed_domains` and `blocked_domains` apply to the rest of the session.
 
 Only the agent's `tools` and `mcp_servers` can change after a session is created. To run a session with `model`, `system`, or `skills` values other than the agent's, use [agent configuration overrides](https://platform.claude.com/docs/en/managed-agents/sessions#override-agent-configuration-for-a-session) when you create the session. The agent's model configuration, including its [`inference_geo`](https://platform.claude.com/docs/en/manage-claude/data-residency) pin, also can't change mid-session: set the pin when you save the agent, or set or clear it for a single session with a `model` override when you create it. The agent's configured `system` field is fixed for the session's lifetime. On models that support it, you can still append system-level guidance mid-session by sending a [`system.message` event](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#sending-system-messages).
 

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

from line 149
 
 The 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).
 
-**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:
-
-* `skills-2025-10-02` - Enables Skills functionality
-
-Add 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.
+**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.
 
 Use 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.
 

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

from line 183
 | [Data residency](https://platform.claude.com/docs/en/manage-claude/data-residency)                                         | `/v1/messages` (with `inference_geo`)            | <Eligible>Yes</Eligible>                                | <Eligible>Yes</Eligible>            |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
 | [Effort](https://platform.claude.com/docs/en/build-with-claude/effort)                                                     | `/v1/messages` (with `effort`)                   | <Eligible>Yes</Eligible>                                | <Eligible>Yes</Eligible>            |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
 | [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.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
-| [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).                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
+| [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).                                                                                                                                                                                                                                                                                                                                                                                                                                  |
 | [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>            |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
 | [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).                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
 | [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
 * **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).
 
 <Note>
-  [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.
+  [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.
 </Note>
 
 ## Inference geo

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

from line 550
 
 [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).
 
-Session behavior on Claude Platform on AWS differs from first-party Claude Managed Agents in one way:
+Session behavior on Claude Platform on AWS differs from first-party Claude Managed Agents in two ways:
 
 * **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.
+* **[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.
 
 ### Features not supported
 

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

from line 704
 
 #### Option 3: Files API
 
-For 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):
+For 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:
 
 <CodeGroup>
   ```bash cURL

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

from line 740
 
   <Tab title="Files API">
     <Note>
-      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.
+      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.
     </Note>
 
     <CodeGroup>
from line 1571
 
   <Tab title="Files API">
     <Note>
-      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.
+      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.
     </Note>
 
     <CodeGroup>

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

from line 446
 
 For 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).
 
+On [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).
+
 ### Content limits
 
 The `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
 <Note>
   The `max_content_tokens` parameter limit is approximate. The actual number of input tokens used can vary by a small amount.
 </Note>
+
+On 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).
 
 ### Cache bypass
 

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

from line 1071
   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.
 </Warning>
 
+[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.
+
+Organization-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.
+
 ## Dynamic filtering with code execution
 
 The `_20260209` and later versions of web search and web fetch use code execution internally to apply dynamic filters against search results.

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

from line 364
 * **`skill_id: "pptx"`:** The PowerPoint Skill identifier
 * **`version: "latest"`:** The Skill version set to the most recently published
 * **`tools`:** Enables code execution (required for Skills)
-* **Beta header:** `skills-2025-10-02`
 
 <Note>
-  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`.
+  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.
+
+  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.
 </Note>
 
 When 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.

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

from line 13
 Key characteristics:
 
 * **Workspace identifiers** use the `wrkspc_` prefix (for example, `wrkspc_01JwQvzr7rXLA5AGx3HKfFUJ`)
-* **Maximum 100 workspaces** per organization (archived workspaces don't count)
+* **Maximum 100 workspaces** per organization by default (archived workspaces don't count); contact your account team if you need more
 * **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`
 * **API keys** are scoped to a single workspace and can only access resources within that workspace
 
from line 477
   </Accordion>
 
   <Accordion title="Are there limits on workspaces?">
-    Yes, you can have a maximum of 100 workspaces per organization. Archived workspaces do not count toward this limit.
+    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.
   </Accordion>
 
   <Accordion title="How do organization roles affect workspace access?">

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

from line 278
 To analyze your own data files (such as CSV, Excel, or images), upload them through the Files API and reference them in your request:
 
 <Note>
-  Using the Files API with code execution requires the Files API beta header: `"anthropic-beta": "files-api-2025-04-14"`
+  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.
 </Note>
 
 The Python environment can process various file types uploaded through the Files API, including:

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

from line 55
 Pass 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.
 
 <Note>
-  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.
+  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.
 </Note>
 
 <CodeGroup>

managed-agents/skills Changed · +1 / -1 lines

from line 21
 
 A custom skill is a directory containing a `SKILL.md` file plus any supporting files, uploaded to your workspace as a zip archive or as individual files. Creating the skill returns the `skill_*` ID you reference when attaching it to an agent. Anthropic pre-built skills are already available in every workspace and don't require this step. To use only pre-built skills, skip to [Attach skills to an agent](https://platform.claude.com/docs/en/managed-agents/skills#attach-skills-to-an-agent).
 
-When you call the Skills API directly with cURL, pass the `anthropic-beta: skills-2025-10-02` header explicitly. The CLI and SDKs send it automatically.
+The Skills API doesn't require a beta header. The cURL example still sends `anthropic-beta: skills-2025-10-02`, and the CLI and SDK `beta` commands add it automatically; requests that include it continue to work unchanged.
 
 These examples omit the optional `display_title` field, so the skill's title is derived from `SKILL.md`. An explicitly passed `display_title` must be unique among the custom skills in your workspace.
 

managed-agents/mcp-connector Changed · +1 / -1 lines

from line 237
 
 ## Configure which MCP tools are available
 
-The `mcp_toolset` entry supports the same `default_config` and `configs` shape as the built-in agent toolset, applied to the tools the MCP server exposes. The `name` in each `configs` entry is the bare tool name as reported by the server.
+The `mcp_toolset` entry supports a `default_config` object and a `configs` array, applied to the tools the MCP server exposes. Each `configs` entry accepts only `name`, `enabled`, and `permission_policy`. Unlike entries in the built-in agent toolset, MCP tool entries do not take a `type` field, and the [web settings](https://platform.claude.com/docs/en/managed-agents/tools#restrict-web-search-and-web-fetch-domains) available on `web_search` and `web_fetch` do not apply to MCP tools. The `name` in each `configs` entry is the bare tool name as reported by the server.
 
 By default all tools exposed by the MCP server are enabled. To enable only specific tools, set `default_config.enabled` to `false` and explicitly enable the tools you want:
 

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

### Files API

from line 193
 | Create endpoints (for example, agents, sessions, and environments) | 300 requests per minute   |
 | Read endpoints (for example, retrieve, list, and stream)           | 1,200 requests per minute |
 
+### Files API
+
+[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.
+
 ### Fast mode rate limits
 
 When 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).

managed-agents/overview Changed · +1 / -1 lines

from line 83
 
 * **Bash:** Run shell commands in the sandbox
 * **File operations:** Read, write, edit, glob, and grep files in the sandbox
-* **Web search and fetch:** Search the web and retrieve content from URLs
+* **Web search and fetch:** Search the web and retrieve content from URLs, optionally restricted to an allowlist or blocklist of domains
 * **MCP servers:** Connect to external tool providers
 
 See [Tools](https://platform.claude.com/docs/en/managed-agents/tools) for the full list and configuration options.

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

### File expiration

from line 5
 ---
 
 ## Compatibility
-- Status: Beta
-- [Beta header](https://platform.claude.com/docs/en/api/beta-headers): `files-api-2025-04-14`
 - [ZDR](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention): not eligible
-- Platforms: Claude API (beta), Claude Platform on AWS (beta), Microsoft Foundry (beta) [1]; not available on Amazon Bedrock, Google Cloud
+- Platforms: Claude API, Claude Platform on AWS (beta), Microsoft Foundry (beta) [1]; not available on Amazon Bedrock, Google Cloud
 1. 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).
 
 The 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.
 
-<Note>
-  Reach out through the [feedback form](https://forms.gle/tisHyierGwgN4DUE9) to share your experience with the Files API.
-</Note>
-
 ## File type support
 
 Referencing 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
 ## How to use the Files API
 
 <Note>
-  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.
+  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:
+
+  * **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.
+  * **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.
 </Note>
 
 ### Uploading a file
from line 162
   "mime_type": "application/pdf",
   "size_bytes": 1024000,
   "created_at": "2025-01-01T00:00:00Z",
-  "downloadable": false
+  "downloadable": false,
+  "expires_at": null
 }
 ```
 
from line 699
 
 #### List files
 
-Retrieve 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`:
+Retrieve 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`:
 
 <CodeGroup>
   ```bash cURL
from line 769
   ```
 </CodeGroup>
 
+To 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`.
+
+The `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).
+
 #### Get file metadata
 
 Retrieve information about a specific file:
from line 988
 
 * 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))
 * Files cannot be modified or renamed after upload. To change a file's content, upload a new file and delete the old one
-* Files persist until you delete them with the `DELETE /v1/files/{file_id}` endpoint
+* Files persist until you delete them with the `DELETE /v1/files/{file_id}` endpoint or they reach their `expires_at`
 * Deleted files cannot be recovered
 * Files are inaccessible through the API shortly after deletion, but they may persist in active Messages API calls and associated tool uses
 * 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)
+
+### File expiration
+
+To 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.
+
+When a file reaches its `expires_at`:
+
+* Downloading its content (`GET /v1/files/{file_id}/content`) returns a 404 error
+* A Messages request that references the file fails before inference
+* Its metadata (`GET /v1/files/{file_id}`) remains readable for up to 30 days, with `expires_at` in the past
+* It continues to appear in list responses during that window; compare `expires_at` to the current time to filter expired files
+
+Deleting an expired file with `DELETE /v1/files/{file_id}` removes its metadata immediately instead of waiting for the 30-day window to elapse.
+
+<Note>
+  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}`.
+</Note>
 
 ### Audit logging
 

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

from line 82
 
 | Feature                                                                                                                  | Description                                                                                                                                                                                                           | ZDR              | Availability                                                                   |
 | ------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------ |
-| [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 />†      |
+| [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 />†          |
 | [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 />  |
 | [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 />†      |
 | [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
 
 Manage files and assets for use with Claude.
 
-| Feature                                                                  | Description                                                                                                                       | ZDR              | Availability                                                              |
-| ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------- |
-| [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 />† |
+| Feature                                                                  | Description                                                                                                                       | ZDR              | Availability                                                          |
+| ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- | ---------------- | --------------------------------------------------------------------- |
+| [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 />† |
 
 \* **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).
 

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

from line 47
 | ------------------ | ------------------------------------------ | ------------------------------------------------------------------------------------------------------ |
 | **Type value**     | `anthropic`                                | `custom`                                                                                               |
 | **Skill IDs**      | Short names: `pptx`, `xlsx`, `docx`, `pdf` | Generated: `skill_01AbCdEfGhIjKlMnOpQrStUv`                                                            |
-| **Version format** | Date-based: `20251013` or `latest`         | Epoch timestamp: `1759178010641129` or `latest`                                                        |
+| **Version format** | Date-based: `20251013` or `latest`         | Version ID: `skver_01AbCdEfGhIjKlMnOpQrStUv` or `latest`                                               |
 | **Management**     | Pre-built and maintained by Anthropic      | Upload and manage through the [Skills API](https://platform.claude.com/docs/en/api/beta/skills/create) |
 | **Availability**   | Available to all users                     | Private to your workspace                                                                              |
 
from line 58
 To use Skills, you need:
 
 1. **Claude API key** from the [Claude Console](https://platform.claude.com/settings/keys)
+2. **[Code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool)** enabled in your requests
 
-2. **Beta headers:**
+Skills 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.
 
-   * `code-execution-2025-08-25` - Enables code execution (required for Skills)
-   * `skills-2025-10-02` - Enables Skills API
-   * `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
-
-3. **[Code execution tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool)** enabled in your requests
-
 Skills 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).
 
 ***
from line 70
 
 ### Container parameter
 
-Skills are specified using the `container` parameter in the Messages API. You can include up to 8 Skills for each request.
+Skills are specified using the `container` parameter in the Messages API. You can include up to 20 Skills for each request.
 
 The 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:
 
from line 2251
 
 Upload 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.
 
-Files 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.
+Files 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.
 
 <CodeGroup defaultLanguage="CLI">
   ```bash cURL
from line 2521
 
 **Requirements:**
 
-* Must include a `SKILL.md` file at the top level
+* Must include a `SKILL.md` file at the upload root (or at the top of a single enclosing folder)
 
-* All files must specify a common root directory in their paths
+* `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
 
-* The top-level directory name must match the `name` in `SKILL.md` frontmatter (case and underscore insensitive: `Financial_Skill` matches `financial-skill`)
-
-* `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
-
 * Total upload size must be under 30 MB (uncompressed)
 
 * YAML frontmatter requirements:
from line 2787
 
 ### Deleting a Skill
 
-To delete a Skill, you must first delete all its versions:
+Deleting 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.
 
 <CodeGroup defaultLanguage="CLI">
   ```bash cURL
-  # Step 1: List the versions, then delete each one
-  curl "https://api.anthropic.com/v1/skills/skill_01AbCdEfGhIjKlMnOpQrStUv/versions" \
-    -H "x-api-key: $ANTHROPIC_API_KEY" \
-    -H "anthropic-version: 2023-06-01" \
-    -H "anthropic-beta: skills-2025-10-02"
-
-  # Repeat for each version the list returned
-  curl -X DELETE "https://api.anthropic.com/v1/skills/skill_01AbCdEfGhIjKlMnOpQrStUv/versions/1759178010641129" \
-    -H "x-api-key: $ANTHROPIC_API_KEY" \
-    -H "anthropic-version: 2023-06-01" \
-    -H "anthropic-beta: skills-2025-10-02"
-
-  # Step 2: Delete the Skill
   curl -X DELETE "https://api.anthropic.com/v1/skills/skill_01AbCdEfGhIjKlMnOpQrStUv" \
     -H "x-api-key: $ANTHROPIC_API_KEY" \
-    -H "anthropic-version: 2023-06-01" \
-    -H "anthropic-beta: skills-2025-10-02"
+    -H "anthropic-version: 2023-06-01"
   ```
 
   ```bash CLI
-  # Step 1: List the versions, then delete each one
-  ant beta:skills:versions list \
-    --skill-id skill_01AbCdEfGhIjKlMnOpQrStUv \
-    --transform version \
-    --raw-output
-
-  # Repeat for each version id the list returned
-  ant beta:skills:versions delete \
-    --skill-id skill_01AbCdEfGhIjKlMnOpQrStUv \
-    --version 1759178010641129 >/dev/null
-
-  # Step 2: Delete the Skill
-  ant beta:skills delete \
+  ant skills delete \
     --skill-id skill_01AbCdEfGhIjKlMnOpQrStUv >/dev/null
   ```
 
from line 2804
   ```python Python
   client = anthropic.Anthropic()
 
-  # Step 1: Delete all versions
-  for version in client.beta.skills.versions.list(
-      skill_id="skill_01AbCdEfGhIjKlMnOpQrStUv"
-  ):
-      client.beta.skills.versions.delete(
-          skill_id="skill_01AbCdEfGhIjKlMnOpQrStUv",
-          version=version.version,
-      )
-
-  # Step 2: Delete the Skill
-  client.beta.skills.delete(skill_id="skill_01AbCdEfGhIjKlMnOpQrStUv")
+  client.skills.delete(skill_id="skill_01AbCdEfGhIjKlMnOpQrStUv")
   ```
 
   ```typescript TypeScript
   const client = new Anthropic();
 
-  // Step 1: Delete all versions
-  for await (const version of client.beta.skills.versions.list(
-    "skill_01AbCdEfGhIjKlMnOpQrStUv"
-  )) {
-    await client.beta.skills.versions.delete(version.version, {
-      skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv"
-    });
-  }
-
-  // Step 2: Delete the Skill
-  await client.beta.skills.delete("skill_01AbCdEfGhIjKlMnOpQrStUv");
+  await client.skills.delete("skill_01AbCdEfGhIjKlMnOpQrStUv");
   ```
 
   ```csharp C#
-  using Anthropic.Models.Beta.Skills.Versions;
-  // ...
   AnthropicClient client = new();
 
-  // Step 1: Delete all versions
-  await foreach (var version in (await client.Beta.Skills.Versions.List("skill_01AbCdEfGhIjKlMnOpQrStUv")).Paginate())
-  {
-      await client.Beta.Skills.Versions.Delete(
-          version.Version,
-          new VersionDeleteParams { SkillID = "skill_01AbCdEfGhIjKlMnOpQrStUv" }
-      );
-  }
-
-  // Step 2: Delete the Skill
-  await client.Beta.Skills.Delete("skill_01AbCdEfGhIjKlMnOpQrStUv");
+  await client.Skills.Delete("skill_01AbCdEfGhIjKlMnOpQrStUv");
   ```
 
   ```go Go
   client := anthropic.NewClient()
 
-  // Step 1: Delete all versions
-  versions := client.Beta.Skills.Versions.ListAutoPaging(
+  _, err := client.Skills.Delete(
   	context.TODO(),
   	"skill_01AbCdEfGhIjKlMnOpQrStUv",
-  	anthropic.BetaSkillVersionListParams{},
   )
-
-  for versions.Next() {
-  	version := versions.Current()
-  	_, err := client.Beta.Skills.Versions.Delete(
-  		context.TODO(),
-  		version.Version,
-  		anthropic.BetaSkillVersionDeleteParams{
-  			SkillID: "skill_01AbCdEfGhIjKlMnOpQrStUv",
-  		},
-  	)
-  	if err != nil {
-  		log.Fatal(err)
-  	}
-  }
-  if versions.Err() != nil {
-  	log.Fatal(versions.Err())
-  }
-
-  // Step 2: Delete the Skill
-  _, err := client.Beta.Skills.Delete(
-  	context.TODO(),
-  	"skill_01AbCdEfGhIjKlMnOpQrStUv",
-  	anthropic.BetaSkillDeleteParams{},
-  )
   if err != nil {
   	log.Fatal(err)
   }
from line 2832
   ```
 
   ```java Java
-  import com.anthropic.models.beta.skills.versions.VersionListPage;
-  import com.anthropic.models.beta.skills.versions.VersionDeleteParams;
-  // ...
   void main() {
       AnthropicClient client = AnthropicOkHttpClient.fromEnv();
 
-      // Step 1: Delete all versions
-      VersionListPage versions = client.beta().skills().versions().list("skill_01AbCdEfGhIjKlMnOpQrStUv");
-
-      for (var version : versions.autoPager()) {
-          client.beta().skills().versions().delete(
-              version.version(),
-              VersionDeleteParams.builder()
-                  .skillId("skill_01AbCdEfGhIjKlMnOpQrStUv")
-                  .build()
-          );
-      }
-
-      // Step 2: Delete the Skill
-      client.beta().skills().delete("skill_01AbCdEfGhIjKlMnOpQrStUv");
+      client.skills().delete("skill_01AbCdEfGhIjKlMnOpQrStUv");
   }
   ```
 
from line 2842
   ```php PHP
   $client = new Client();
 
-  // Step 1: Delete all versions
-  $versions = $client->beta->skills->versions->list(
+  $client->skills->delete(
       skillID: 'skill_01AbCdEfGhIjKlMnOpQrStUv',
   );
-
-  foreach ($versions->pagingEachItem() as $version) {
-      $client->beta->skills->versions->delete(
-          skillID: 'skill_01AbCdEfGhIjKlMnOpQrStUv',
-          version: $version->version,
-      );
-  }
-
-  // Step 2: Delete the Skill
-  $client->beta->skills->delete(
-      skillID: 'skill_01AbCdEfGhIjKlMnOpQrStUv',
-  );
   ```
 
   ```ruby Ruby
   client = Anthropic::Client.new
 
-  # Step 1: Delete all versions
-  client.beta.skills.versions.list("skill_01AbCdEfGhIjKlMnOpQrStUv").auto_paging_each do |version|
-    client.beta.skills.versions.delete(
-      version.version,
-      skill_id: "skill_01AbCdEfGhIjKlMnOpQrStUv"
-    )
-  end
-
-  # Step 2: Delete the Skill
-  client.beta.skills.delete("skill_01AbCdEfGhIjKlMnOpQrStUv")
+  client.skills.delete("skill_01AbCdEfGhIjKlMnOpQrStUv")
   ```
 </CodeGroup>
 
-Attempting to delete a Skill with existing versions returns a 400 error.
-
 ### Versioning
 
 Skills support versioning to manage updates safely:
from line 2866
 
 **Custom Skills:**
 
-* Auto-generated epoch timestamps: `1759178010641129`
+* Auto-generated version IDs: `skver_01AbCdEfGhIjKlMnOpQrStUv`
 * Use `"latest"` to always get the most recent version
 * Create new versions when updating Skill files
 
-A 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).
+A 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).
 
 <CodeGroup defaultLanguage="CLI">
   ```bash cURL
from line 3769
 
 ### Request limits
 
-* **Maximum Skills per request:** 8
+* **Maximum Skills per request:** 20
 
 * **Maximum Skill upload size:** 30 MB (all files combined, uncompressed)
 

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

from line 2753
 
 ## Console observability
 
-The Claude Console provides a visual timeline view of your agent sessions. Navigate to the Claude Managed Agents section in the Console to see:
+The 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:
 
-* **Session list:** All sessions with their status, creation time, and agent
-* **Tracing view:** A chronological view of events (content, timestamps, token usage) within a session. Tracing views are only accessible to Developers and Admins.
-* **Tool execution:** Details of each tool call and its result
+* **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.
+
+* **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.
+
+* **Inspector:** A resizable side panel with details about the session, in five tabs:
+
+  * **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.
+  * **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).
+  * **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.
+  * **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.
+  * **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.
+
+Append `?event={event_id}` to a session URL to open the session at a specific event.
 
 ## Debugging tips
 

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

from line 18
 
 ## Overview
 
-A **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).
+A **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.
 
 Each **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.
 
from line 208
 
 ## Attach a memory store to a session
 
-Memory 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.
+Memory 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.
 
 Optionally 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.
 
from line 380
 Each 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.
 
 `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.
+
+<Note>
+  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.
+
+  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).
+</Note>
 
 The 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.
 

managed-agents/scheduled-deployments Changed · +1 / -1 lines

from line 16
 
 When creating a deployment, you pass the [session configurations](https://platform.claude.com/docs/en/managed-agents/sessions) required for execution, in addition to a `schedule`.
 
-* Deployments require [agent configuration](https://platform.claude.com/docs/en/managed-agents/agent-setup) and [environment configuration](https://platform.claude.com/docs/en/managed-agents/environments), and optionally accept [files](https://platform.claude.com/docs/en/managed-agents/files), [GitHub](https://platform.claude.com/docs/en/managed-agents/github), [memory stores](https://platform.claude.com/docs/en/managed-agents/memory), and [vaults](https://platform.claude.com/docs/en/managed-agents/vaults).
+* Deployments require [agent configuration](https://platform.claude.com/docs/en/managed-agents/agent-setup) and [environment configuration](https://platform.claude.com/docs/en/managed-agents/environments), and optionally accept [files](https://platform.claude.com/docs/en/managed-agents/files), [GitHub](https://platform.claude.com/docs/en/managed-agents/github), [memory stores](https://platform.claude.com/docs/en/managed-agents/memory), and [vaults](https://platform.claude.com/docs/en/managed-agents/vaults). A deployment that targets a [self-hosted environment](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#use-memory-stores) can attach memory stores; `file` and `github_repository` resources require a cloud environment. The Claude Console deployment form does not currently offer memory stores for self-hosted environments; attach them through the API or an SDK instead.
 * Deployments also require at least one initial event, a `user.message` or `user.define_outcome`, that starts each session's work.
 * In the `schedule`, you define a cron `expression` and a `timezone`. Maximum granularity supported is at the minute level.
 

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

from line 541
           },
           Configs =
           [
-              new()
+              new BetaManagedAgentsBashToolConfigParams
               {
-                  Name = "bash",
                   PermissionPolicy = new BetaManagedAgentsAlwaysAskPolicy { Type = "always_ask" },
               },
           ],
from line 561
   				},
   			},
   		},
-  		Configs: []anthropic.BetaManagedAgentsAgentToolConfigParams{{
-  			Name: anthropic.BetaManagedAgentsAgentToolConfigParamsNameBash,
-  			PermissionPolicy: anthropic.BetaManagedAgentsAgentToolConfigParamsPermissionPolicyUnion{
-  				OfAlwaysAsk: &anthropic.BetaManagedAgentsAlwaysAskPolicyParam{
-  					Type: anthropic.BetaManagedAgentsAlwaysAskPolicyTypeAlwaysAsk,
+  		Configs: []anthropic.BetaManagedAgentsAgentToolConfigUnionParamsUnion{{
+  			OfBetaManagedAgentsBashToolConfigs: &anthropic.BetaManagedAgentsBashToolConfigParams{
+  				PermissionPolicy: anthropic.BetaManagedAgentsBashToolConfigParamsPermissionPolicyUnion{
+  					OfAlwaysAsk: &anthropic.BetaManagedAgentsAlwaysAskPolicyParam{
+  						Type: anthropic.BetaManagedAgentsAlwaysAskPolicyTypeAlwaysAsk,
+  					},
   				},
   			},
   		}},
from line 593
                       .build()
               )
               .addConfig(
-                  BetaManagedAgentsAgentToolConfigParams.builder()
-                      .name(BetaManagedAgentsAgentToolConfigParams.Name.BASH)
+                  BetaManagedAgentsBashToolConfigParams.builder()
                       .permissionPolicy(
                           BetaManagedAgentsAlwaysAskPolicy.builder()
                               .type(BetaManagedAgentsAlwaysAskPolicy.Type.ALWAYS_ASK)
from line 607
   ```
 
   ```php PHP
-  use Anthropic\Beta\Agents\BetaManagedAgentsAgentToolConfigParams;
+  use Anthropic\Beta\Agents\BetaManagedAgentsBashToolConfigParams;
   use Anthropic\Beta\Agents\BetaManagedAgentsAgentToolset20260401Params;
   use Anthropic\Beta\Agents\BetaManagedAgentsAgentToolsetDefaultConfigParams;
   use Anthropic\Beta\Agents\BetaManagedAgentsAlwaysAllowPolicy;
from line 620
               permissionPolicy: BetaManagedAgentsAlwaysAllowPolicy::with(type: 'always_allow'),
           ),
           configs: [
-              BetaManagedAgentsAgentToolConfigParams::with(
-                  name: 'bash',
+              BetaManagedAgentsBashToolConfigParams::with(
                   permissionPolicy: BetaManagedAgentsAlwaysAskPolicy::with(type: 'always_ask'),
               ),
           ],

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 too far apart to line up, so this is the differ's own diff of it.

from line 6
 
 By 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.
 
-Tool 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.
+Tool 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.
 
 <Note>
   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
 
 ## How it differs from cloud environments
 
-|                               | Cloud environment           | Self-hosted sandbox |
-| ----------------------------- | --------------------------- | ------------------- |
-| Where tools run               | Anthropic-managed sandboxes | Your infrastructure |
-| Network reach                 | Anthropic's egress controls | Your network policy |
-| File and GitHub repo mounting | Managed by Anthropic        | Managed by you      |
-| Lifecycle                     | Managed by Anthropic        | Managed by you      |
+|                               | Cloud environment                      | Self-hosted sandbox                                       |
+| ----------------------------- | -------------------------------------- | --------------------------------------------------------- |
+| Where tools run               | Anthropic-managed sandboxes            | Your infrastructure                                       |
+| Network reach                 | Anthropic's egress controls            | Your network policy                                       |
+| File and GitHub repo mounting | Managed by Anthropic                   | Managed by you                                            |
+| Memory stores                 | Mounted by Anthropic at `/mnt/memory/` | Downloaded to `/mnt/memory/` and synced by the SDK worker |
+| Lifecycle                     | Managed by Anthropic                   | Managed by you                                            |
 
 Self-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.
 
from line 46
 
 * **`/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.
 * **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.
+* **`/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).
 
 ## Before you begin
 
from line 55
 * **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.
 * **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.
 * **The `ant` CLI or an Anthropic SDK** (Python, TypeScript, or Go) on the worker host.
-* **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.
+* **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)).
+* **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).
 
 <Note>
   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.
+
+  Memory stores cannot be attached to sessions on self-hosted environments on Claude Platform on AWS.
 </Note>
 
 <Steps>
from line 255
         ENTRYPOINT ["ant", "beta:worker", "run"]
         ```
 
-        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.
+        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.
 
         ```bash
         #!/bin/bash
from line 268
           your-image
         ```
 
+        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).
+
         Start the poller pointing at the script:
 
         ```bash
from line 288
         <CodeGroup exclude="shell">
           ```python Python
           import asyncio
+          import contextlib
           import os
+          import signal
           from anthropic import AsyncAnthropic
           from anthropic.lib.environments import EnvironmentWorker
 
from line 299
               environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"]
               environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"]
               async with AsyncAnthropic(auth_token=environment_key) as client:
-                  await EnvironmentWorker(
+                  worker = EnvironmentWorker(
                       client,
                       environment_id=environment_id,
                       environment_key=environment_key,
                       workdir="/workspace",
-                  ).run()
+                  )
+                  task = asyncio.create_task(worker.run())
+                  # Cancelling the task, rather than killing the process, lets the worker stop its
+                  # in-flight work item and upload changed memory files before it exits.
+                  loop = asyncio.get_running_loop()
+                  for signum in (signal.SIGINT, signal.SIGTERM):
+                      loop.add_signal_handler(signum, task.cancel)
+                  with contextlib.suppress(asyncio.CancelledError):
+                      await task
 
 
           asyncio.run(main())
from line 326
           const environmentId = process.env.ANTHROPIC_ENVIRONMENT_ID!;
           const client = new Anthropic({ authToken: environmentKey });
           const controller = new AbortController();
+          // Aborting on either signal lets the worker upload changed memory files and remove its
+          // store directories before the process exits.
+          process.once("SIGINT", () => controller.abort());
           process.once("SIGTERM", () => controller.abort());
 
           await new EnvironmentWorker({
from line 413
       <Step title="Implement the webhook handler">
         `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.
 
+        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.
+
         <CodeGroup exclude="shell">
           ```python Python
+          import asyncio
           import os
+          import signal
           import anthropic
+          import standardwebhooks  # installed by the anthropic[webhooks] extra
 
           environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"]
           environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"]
           client = anthropic.AsyncAnthropic(
               auth_token=environment_key,
           )
-
-
-          async def handle(raw: bytes, headers: dict[str, str]) -> dict:
-              event = client.beta.webhooks.unwrap(raw.decode(), headers=headers)
+          # Cancelled on SIGINT or SIGTERM (wired in handle) so an in-flight work item can upload
+          # changed memory files and remove its store directories before the process exits.
+          inflight: set[asyncio.Task[None]] = set()
+
+
+          def cancel_inflight() -> None:
+              for task in inflight:
+                  task.cancel()
+
+
+          async def handle(raw: bytes, headers: dict[str, str]) -> tuple[dict[str, str], int]:
+              try:
+                  event = client.beta.webhooks.unwrap(raw.decode(), headers=headers)
+              except standardwebhooks.WebhookVerificationError:
+                  return {"error": "signature verification failed"}, 401
               if event.data.type != "session.status_run_started":
-                  return {"status": "ignored"}
+                  return {"status": "ignored"}, 200
+              loop = asyncio.get_running_loop()
+              for signum in (signal.SIGINT, signal.SIGTERM):
+                  loop.add_signal_handler(signum, cancel_inflight)
+              task = asyncio.create_task(run_queued_work())
+              inflight.add(task)
+              task.add_done_callback(inflight.discard)
+              try:
+                  await task
+              except asyncio.CancelledError:
+                  return {"status": "shutting down"}, 503
+              return {"status": "ok"}, 200
+
+
+          async def run_queued_work() -> None:
               async for work in client.beta.environments.work.poller(
                   environment_id=environment_id,
                   environment_key=environment_key,
from line 472
                       environment_id=environment_id,
                       session_id=work.data.id,
                       environment_key=environment_key,
+                      # The per-session secret is what lets the worker mount the session's memory stores.
+                      work_secret=work.secret,
                   )
-              return {"status": "ok"}
           ```
 
           ```typescript TypeScript
from line 485
           const client = new Anthropic({
             authToken: environmentKey
           });
+          // Aborted on SIGINT or SIGTERM so an in-flight work item can upload changed memory
+          // files and remove its store directories before the process exits.
+          const shutdown = new AbortController();
+          process.once("SIGINT", () => shutdown.abort());
+          process.once("SIGTERM", () => shutdown.abort());
 
           export async function handle(req: Request): Promise<Response> {
             const body = await req.text();
from line 509
               blockMs: null,
               reclaimOlderThanMs: 2000,
               drain: true,
-              autoStop: false
+              autoStop: false,
+              signal: shutdown.signal
             })) {
               await client.beta.environments.work.worker({ workdir: "/workspace" }).handleItem({
                 workId: work.id,
                 environmentId,
                 sessionId: work.data.id,
-                environmentKey
+                environmentKey,
+                // The per-session secret is what lets the worker mount the session's memory stores.
+                workSecret: work.secret ?? undefined,
+                signal: shutdown.signal
               });
             }
             return Response.json({ status: "ok" });
from line 537
           import (
           	"context"
           	"encoding/json"
+          	"errors"
           	"io"
           	"log/slog"
           	"net/http"
           	"os"
+          	"os/signal"
+          	"syscall"
 
           	"github.com/anthropics/anthropic-sdk-go"
           	"github.com/anthropics/anthropic-sdk-go/lib/environments"
from line 561
           	worker = environments.NewEnvironmentWorker(client, environments.EnvironmentWorkerOptions{
           		Workdir: "/workspace",
           	})
+          	// Cancelled on SIGINT or SIGTERM (set in main) so an in-flight work item can
+          	// upload changed memory files and remove its store directories before exit.
+          	shutdown context.Context
           )
 
           func handle(w http.ResponseWriter, r *http.Request) {
from line 585
           	// The Go SDK does not provide a RunOne convenience: drain pending items
           	// with WorkPoller and run each one with HandleItem.
           	// Detach from r.Context(): the session can outlive the webhook delivery timeout.
-          	ctx := context.Background()
+          	// The process-wide shutdown context still ends the item cleanly on SIGTERM.
+          	ctx := shutdown
           	poller := environments.NewWorkPoller(ctx, client, environments.WorkPollerOptions{
           		EnvironmentID:      environmentID,
           		EnvironmentKey:     environmentKey,
           		BlockMs:            param.Null[int64](),
           		ReclaimOlderThanMs: param.NewOpt[int64](2000),
           		Drain:              true,
+          		AutoStop:           param.NewOpt(false),
           	})
           	defer poller.Close()
           	for poller.Next() {
from line 603
           			EnvironmentID:  item.EnvironmentID,
           			SessionID:      item.Data.ID,
           			EnvironmentKey: environmentKey,
+          			// The per-session secret is what lets the worker mount the session's memory stores.
+          			WorkSecret: item.Secret,
           		}); err != nil {
           			slog.Error("handle work item", "work_id", item.ID, "err", err)
           			http.Error(w, "internal error", http.StatusInternalServerError)
from line 620
           }
 
           func main() {
+          	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
+          	defer stop()
+          	shutdown = ctx
+
+          	server := &http.Server{Addr: ":8080"}
           	http.HandleFunc("POST /webhook", handle)
-          	if err := http.ListenAndServe(":8080", nil); err != nil {
-          		slog.Error("http server", "err", err)
-          		os.Exit(1)
+          	go func() {
+          		if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
+          			slog.Error("http server", "err", err)
+          			os.Exit(1)
+          		}
+          	}()
+          	// On a signal, stop accepting deliveries and return only after in-flight
+          	// handlers, and therefore their work items' memory teardown, have finished.
+          	<-ctx.Done()
+          	if err := server.Shutdown(context.Background()); err != nil {
+          		slog.Error("http shutdown", "err", err)
           	}
           }
 
from line 669
 * **`EnvironmentWorker`:** the out-of-the-box worker. Handles polling, setup, and execution end to end.
 
   * `.run()`: runs indefinitely, picking up sessions as they arrive.
-  * `.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.
+  * `.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).
+  * `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.
 
 * **`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.
 
   * `drain`: whether to stop polling once the queue is empty rather than waiting for new work.
   * `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.
   * `reclaim_older_than_ms`: re-claim work items that were claimed but never acknowledged within this many milliseconds.
-  * `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.
+  * `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.
 
 * **`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.
 
from line 703
   from anthropic import AsyncAnthropic
   from anthropic.types.beta.environments import BetaSelfHostedWork
 
+  SANDBOX_ENV = (
+      "ANTHROPIC_ENVIRONMENT_ID",
+      "ANTHROPIC_ENVIRONMENT_KEY",
+      "ANTHROPIC_WORK_ID",
+      "ANTHROPIC_SESSION_ID",
+      "ANTHROPIC_WORK_SECRET",
+      "ANTHROPIC_BASE_URL",  # forwarded only when set on this host
+  )
+
 
   async def launch_container(work: BetaSelfHostedWork) -> None:
-      # Replace with your own per-session sandbox launcher. Pass
-      # ANTHROPIC_ENVIRONMENT_KEY into the launched sandbox, never
-      # your API key.
       print(f"claimed session {work.data.id}")
+      # Replace `docker run` with your own sandbox launcher. Forward the environment
+      # key (never your API key) and the work item's per-session secret: the worker
+      # inside needs the secret to mount the session's memory stores.
+      env = os.environ | {
+          "ANTHROPIC_WORK_ID": work.id,
+          "ANTHROPIC_SESSION_ID": work.data.id,
+          "ANTHROPIC_WORK_SECRET": work.secret or "",
+      }
+      forward = [arg for name in SANDBOX_ENV for arg in ("-e", name)]
+      launcher = await asyncio.create_subprocess_exec(
+          "docker", "run", "--rm", "--detach", *forward, "your-sdk-worker-image", env=env
+      )
+      await launcher.wait()
 
 
   async def main() -> None:
from line 746
   ```
 
   ```typescript TypeScript
+  import { spawn } from "node:child_process";
+  import { once } from "node:events";
   import Anthropic from "@anthropic-ai/sdk";
   import { WorkPoller } from "@anthropic-ai/sdk/helpers/beta/environments";
   import type { BetaSelfHostedWork } from "@anthropic-ai/sdk/resources/beta/environments";
 
+  const SANDBOX_ENV = [
+    "ANTHROPIC_ENVIRONMENT_ID",
+    "ANTHROPIC_ENVIRONMENT_KEY",
+    "ANTHROPIC_WORK_ID",
+    "ANTHROPIC_SESSION_ID",
+    "ANTHROPIC_WORK_SECRET",
+    "ANTHROPIC_BASE_URL" // forwarded only when set on this host
+  ];
+
   const environmentKey = process.env.ANTHROPIC_ENVIRONMENT_KEY!;
   const environmentId = process.env.ANTHROPIC_ENVIRONMENT_ID!;
   const client = new Anthropic({ authToken: environmentKey });
 
   async function launchContainer(work: BetaSelfHostedWork): Promise<void> {
-    // Replace with your own per-session sandbox launcher. Pass
-    // ANTHROPIC_ENVIRONMENT_KEY into the launched sandbox, never
-    // your API key.
     console.log(`claimed session ${work.data.id}`);
+    // Replace `docker run` with your own sandbox launcher. Forward the environment
+    // key (never your API key) and the work item's per-session secret: the worker
+    // inside needs the secret to mount the session's memory stores.
+    const env = {
+      ...process.env,
+      ANTHROPIC_WORK_ID: work.id,
+      ANTHROPIC_SESSION_ID: work.data.id,
+      ANTHROPIC_WORK_SECRET: work.secret ?? ""
+    };
+    const forward = SANDBOX_ENV.flatMap((name) => ["-e", name]);
+    const launcher = spawn(
+      "docker",
+      ["run", "--rm", "--detach", ...forward, "your-sdk-worker-image"],
+      { env, stdio: "inherit" }
+    );
+    await once(launcher, "close");
   }
 
   const poller = new WorkPoller({
from line 810
   	"fmt"
   	"log"
   	"os"
+  	"os/exec"
 
   	"github.com/anthropics/anthropic-sdk-go"
   	"github.com/anthropics/anthropic-sdk-go/lib/environments"
   	"github.com/anthropics/anthropic-sdk-go/option"
+  	"github.com/anthropics/anthropic-sdk-go/packages/param"
   )
 
-  func launchContainer(work *anthropic.BetaSelfHostedWork) {
-  	// Replace with your own per-session sandbox launcher. The Go poller
-  	// calls work.Stop when this function returns (it has no auto-stop
-  	// opt-out), so block here until the session completes rather than
-  	// detaching as the Python and TypeScript tabs do.
+  var sandboxEnv = []string{
+  	"ANTHROPIC_ENVIRONMENT_ID",
+  	"ANTHROPIC_ENVIRONMENT_KEY",
+  	"ANTHROPIC_WORK_ID",
+  	"ANTHROPIC_SESSION_ID",
+  	"ANTHROPIC_WORK_SECRET",
+  	"ANTHROPIC_BASE_URL", // forwarded only when set on this host
+  }
+
+  func launchContainer(ctx context.Context, work *anthropic.BetaSelfHostedWork) error {
   	fmt.Printf("claimed session %s\n", work.Data.ID)
+  	// Replace `docker run` with your own sandbox launcher. Forward the environment
+  	// key (never your API key) and the work item's per-session secret: the worker
+  	// inside needs the secret to mount the session's memory stores.
+  	args := []string{"run", "--rm", "--detach"}
+  	for _, name := range sandboxEnv {
+  		args = append(args, "-e", name)
+  	}
+  	launcher := exec.CommandContext(ctx, "docker", append(args, "your-sdk-worker-image")...)
+  	launcher.Env = append(os.Environ(),
+  		"ANTHROPIC_WORK_ID="+work.ID,
+  		"ANTHROPIC_SESSION_ID="+work.Data.ID,
+  		"ANTHROPIC_WORK_SECRET="+work.Secret,
+  	)
+  	launcher.Stdout, launcher.Stderr = os.Stdout, os.Stderr
+  	return launcher.Run()
   }
 
   func main() {
from line 857
   	poller := environments.NewWorkPoller(ctx, client, environments.WorkPollerOptions{
   		EnvironmentID:  environmentID,
   		EnvironmentKey: environmentKey,
+  		AutoStop:       param.NewOpt(false), // the launched sandbox owns the stop call
   	})
   	defer poller.Close()
 
from line 865
   		if err != nil {
   			log.Fatal(err)
   		}
-  		launchContainer(work)
+  		if err := launchContainer(ctx, work); err != nil {
+  			log.Fatal(err)
+  		}
   	}
   }
   ```
from line 888
   ```
 </CodeGroup>
 
-**`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`).
+Whatever 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).
+
+**`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`).
 
 **With `EnvironmentWorker`:** both are managed automatically. Pass a `tools` factory to customize the tool list:
 
from line 1097
 </CodeGroup>
 
 <Note>
-  Self-hosted sandboxes don't support `resources` entries; a session that includes any resource on a self-hosted environment is rejected.
+  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:
+
+  ```text wrap
+  Environment env_... is a self-hosted environment. `resources` are not supported with self-hosted environments.
+  ```
+
+  [Deployments](https://platform.claude.com/docs/en/managed-agents/scheduled-deployments) that target a self-hosted environment follow the same rule.
 </Note>
 
 See [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.
+
+## Use memory stores
+
+Sessions 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.
+
+The `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).
+
+Memory 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).
+
+### How the worker handles memory
+
+When the worker claims a work item whose session has memory stores attached, it:
+
+1. 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.
+2. 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.
+3. 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.
+4. 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.
+
+The 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.
+
+Each 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.
+
+### Prepare the host
+
+Memory 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.
+
+Before you start the worker, create the parent directory and make it writable by the user the worker runs as:
+
+```bash
+sudo mkdir -p /mnt/memory && sudo chown "$USER" /mnt/memory
+```
+
+Do 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:
+
+* **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.
+* **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.
+
+### Run one sandbox per session
+
+The 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.
+
+The `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).
+
+<CodeGroup exclude="shell">
+  ```python Python
+  import asyncio
+  import contextlib
+  import os
+  import signal
+  from anthropic import AsyncAnthropic
+  from anthropic.lib.environments import EnvironmentWorker
+
+
+  async def main() -> None:
+      async with AsyncAnthropic(auth_token=os.environ["ANTHROPIC_ENVIRONMENT_KEY"]) as client:
+          worker = EnvironmentWorker(client, workdir="/workspace")
+          # With no arguments, handle_item() reads the ANTHROPIC_* variables the spawn
+          # script forwarded, including ANTHROPIC_WORK_SECRET.
+          task = asyncio.create_task(worker.handle_item())
+          # Cancelling the task when the container is stopped lets the worker upload
+          # changed memory files and remove the store directories before it exits.
+          loop = asyncio.get_running_loop()
+          for signum in (signal.SIGINT, signal.SIGTERM):
+              loop.add_signal_handler(signum, task.cancel)
+          with contextlib.suppress(asyncio.CancelledError):
+              await task
+
+
+  asyncio.run(main())
+  ```
+
+  ```typescript TypeScript
+  import Anthropic from "@anthropic-ai/sdk";
+  import { EnvironmentWorker } from "@anthropic-ai/sdk/helpers/beta/environments";
+
+  const client = new Anthropic({ authToken: process.env.ANTHROPIC_ENVIRONMENT_KEY });
+  const controller = new AbortController();
+  // Aborting when the container is stopped lets the worker upload changed memory
+  // files and remove the store directories before it exits.
+  process.once("SIGTERM", () => controller.abort());
+  process.once("SIGINT", () => controller.abort());
+
+  // With no arguments, handleItem() reads the ANTHROPIC_* variables the spawn
+  // script forwarded, including ANTHROPIC_WORK_SECRET.
+  await new EnvironmentWorker({
+    client,
+    workdir: "/workspace",
+    signal: controller.signal
+  }).handleItem();
+  ```
+
+  ```csharp C#
+  // EnvironmentWorker is not currently available in the C# SDK.
+  ```
+
+  ```go Go
+  package main
+
+  import (
+  	"context"
+  	"log"
+  	"os"
+  	"os/signal"
+  	"syscall"
+
+  	"github.com/anthropics/anthropic-sdk-go"
+  	"github.com/anthropics/anthropic-sdk-go/lib/environments"
+  	"github.com/anthropics/anthropic-sdk-go/option"
+  )
+
+  func main() {
+  	// Cancelling the context when the container is stopped lets the worker upload
+  	// changed memory files and remove the store directories before it exits.
+  	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
+  	defer stop()
+
+  	client := anthropic.NewClient(option.WithAuthToken(os.Getenv("ANTHROPIC_ENVIRONMENT_KEY")))
+  	worker := environments.NewEnvironmentWorker(client, environments.EnvironmentWorkerOptions{
+  		Workdir: "/workspace",
+  	})
+  	// With zero-value options, HandleItem reads the ANTHROPIC_* variables the spawn
+  	// script forwarded, including ANTHROPIC_WORK_SECRET.
+  	if err := worker.HandleItem(ctx, environments.HandleItemOptions{}); err != nil {
+  		log.Fatalf("worker: %v", err)
+  	}
+  }
+
+  ```
+
+  ```java Java
+  // EnvironmentWorker is not currently available in the Java SDK.
+  ```
+
+  ```php PHP
+  // EnvironmentWorker is not currently available in the PHP SDK.
+  ```
+
+  ```ruby Ruby
+  # EnvironmentWorker is not currently available in the Ruby SDK.
+  ```
+</CodeGroup>
+
+`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:
+
+```bash
+#!/bin/bash
+# spawn.sh: called once per claimed work item
+# The claimed work item arrives as JSON on stdin. Its secret is the
+# per-session credential that the memory store endpoints require.
+ANTHROPIC_WORK_SECRET="$(jq -r '.secret // empty')"
+export ANTHROPIC_WORK_SECRET
+mkdir -p "/host/outputs/$ANTHROPIC_SESSION_ID"
+exec docker run --rm \
+  -e ANTHROPIC_SESSION_ID -e ANTHROPIC_ENVIRONMENT_KEY \
+  -e ANTHROPIC_WORK_ID -e ANTHROPIC_ENVIRONMENT_ID -e ANTHROPIC_BASE_URL \
+  -e ANTHROPIC_WORK_SECRET \
+  -v "/host/outputs/$ANTHROPIC_SESSION_ID":/workspace \
+  your-sdk-worker-image
+```
+
+If 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.
+
+The 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.
+
+### Configure sync
+
+Two `EnvironmentWorker` options control memory behavior:
+
+* **`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)).
+* **`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.
+
+Set 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.
+
+For example, to sync every 10 seconds and only log the deletes the worker would have made:
+
+<CodeGroup exclude="shell">
+  ```python Python
+  worker = EnvironmentWorker(
+      client,
+      environment_id=environment_id,
+      environment_key=environment_key,
+      workdir="/workspace",
+      memory_sync_interval=10,  # seconds
+      memory_sync_deletes="log_only",
+  )
+  ```
+
+  ```typescript TypeScript
+  const worker = new EnvironmentWorker({
+    client,
+    environmentId,
+    environmentKey,
+    workdir: "/workspace",
+    memorySyncIntervalMs: 10_000,
+    memorySyncDeletes: "log_only"
+  });
+  ```
+
+  ```csharp C#
+  // EnvironmentWorker is not currently available in the C# SDK.
+  ```
+
+  ```go Go
+  worker := environments.NewEnvironmentWorker(client, environments.EnvironmentWorkerOptions{
+  	EnvironmentID:      environmentID,
+  	EnvironmentKey:     environmentKey,
+  	Workdir:            "/workspace",
+  	MemorySyncInterval: 10 * time.Second,
+  	MemorySyncDeletes:  environments.MemorySyncDeletesLogOnly,
+  })
+  ```
+
+  ```java Java
+  // EnvironmentWorker is not currently available in the Java SDK.
+  ```
+
+  ```php PHP
+  // EnvironmentWorker is not currently available in the PHP SDK.
+  ```
+
+  ```ruby Ruby
+  # EnvironmentWorker is not currently available in the Ruby SDK.
+  ```
+</CodeGroup>
+
+### Read-only stores and conflicts
+
+For 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.
+
+Conflicts 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.
+
+### Troubleshoot memory mounts
+
+The 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.
+
+| Symptom                                                                                                                                 | Cause                                                                                                                                                                                                          | Fix                                                                                                                                                                                                                                                                                                                              |
+| --------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| 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. |
+| 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.                                                                                                                                                                                                                                 |
+| 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).                                                                                                                                                             |
+| 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.                                                                            |
 
 ## Serve custom tools from your sandbox
 
 

managed-agents/self-hosted-sandboxes-security Changed · +3 / -0 lines

from line 12
 * **Network egress controls.** Your sandbox's network access is determined by your VPC and firewall rules. Without egress restrictions, a compromised tool execution can reach arbitrary external hosts. Restrict outbound traffic to only the endpoints your tools require.
 * **Service key storage and rotation.** The environment service key (`ANTHROPIC_ENVIRONMENT_KEY`) authorizes polling your environment's work queue and submitting results back to sessions. Store it in a secrets manager, not in environment files or sandbox images. Rotate it immediately if you suspect exposure.
 * **Isolating untrusted workloads.** The environment service key is scoped to one environment's work queue. If you run untrusted code inside your sandbox, consider provisioning a separate workspace and environment for each trust boundary. This limits each key to a single user's sessions instead of a shared pool.
+* **Per-session credentials.** Each work item your worker claims can carry a per-session `secret`, which the SDK worker uses in place of the environment service key. Access to [memory stores](https://platform.claude.com/docs/en/managed-agents/memory) requires the `secret`: the memory store endpoints reject the environment key (see [Use memory stores](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#use-memory-stores)). Pass the `secret` only into the sandbox that serves that session, keep it out of images and shared volumes, and never log it.
 * **Tool-execution blast radius.** Tools run inside your sandbox with whatever permissions your process has. Apply least privilege to the process user and mount only the directories your tools require.
 * **Log retention and session content.** Conversation content and tool outputs pass through your worker and stay in your environment. You are responsible for retaining, redacting, or deleting that data in compliance with your own policies. Anthropic has no visibility into what your worker does with session content once delivered.
+* **Memory store contents.** [Memory stores](https://platform.claude.com/docs/en/managed-agents/memory) remain hosted by Anthropic, including their version history. When a session attaches one, the worker keeps a working copy under `/mnt/memory/` in your sandbox for the session's duration and syncs changes back. The worker deletes that copy when the session ends, but a worker that exits without running its teardown leaves it behind. Cleaning up leftover copies, the permissions on that path, and isolation between sessions that share a filesystem are your responsibility.
+* **Read-only memory stores.** A store attached with `read_only` access is protected from upload, not from local modification. The worker's `write` and `edit` tools refuse to write under its directory, nothing there syncs back, and the memory store endpoints reject writes to it made with the session's `secret`. Other processes in the sandbox, including commands the agent runs through the `bash` tool, can still change the local copy, and later tool calls in that session read the changed copy until that memory next changes in the store. If the agent must not be able to alter even its local view of such a store, disable the `bash` tool for that agent.
 
 ## What Anthropic cannot do for you
 

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 too far apart to line up, so this is the differ's own diff of it.

from line 14
 
 ## Available tools
 
-The 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.
+The 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).
 
 | Tool       | Name         | Description                                    |
 | ---------- | ------------ | ---------------------------------------------- |
from line 32
 ## Configuring the toolset
 
 Enable 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.
+
+Config 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).
 
 <CodeGroup defaultLanguage="CLI">
   ```bash cURL
from line 113
               Type = "agent_toolset_20260401",
               Configs =
               [
-                  new() { Name = "web_fetch", Enabled = false },
+                  new BetaManagedAgentsWebFetchToolConfigParams { Enabled = false },
               ],
           },
       ],
from line 129
   	Tools: []anthropic.BetaAgentNewParamsToolUnion{{
   		OfAgentToolset20260401: &anthropic.BetaManagedAgentsAgentToolset20260401Params{
   			Type: anthropic.BetaManagedAgentsAgentToolset20260401ParamsTypeAgentToolset20260401,
-  			Configs: []anthropic.BetaManagedAgentsAgentToolConfigParams{{
-  				Name:    anthropic.BetaManagedAgentsAgentToolConfigParamsNameWebFetch,
-  				Enabled: anthropic.Bool(false),
+  			Configs: []anthropic.BetaManagedAgentsAgentToolConfigUnionParamsUnion{{
+  				OfBetaManagedAgentsWebFetchToolConfigs: &anthropic.BetaManagedAgentsWebFetchToolConfigParams{
+  					Enabled: anthropic.Bool(false),
+  				},
   			}},
   		},
   	}},
from line 151
       .model(BetaManagedAgentsModel.CLAUDE_OPUS_5)
       .addTool(BetaManagedAgentsAgentToolset20260401Params.builder()
           .type(BetaManagedAgentsAgentToolset20260401Params.Type.AGENT_TOOLSET_20260401)
-          .addConfig(BetaManagedAgentsAgentToolConfigParams.builder()
-              .name(BetaManagedAgentsAgentToolConfigParams.Name.WEB_FETCH)
+          .addConfig(BetaManagedAgentsWebFetchToolConfigParams.builder()
               .enabled(false)
               .build())
           .build())
from line 159
   ```
 
   ```php PHP
-  use Anthropic\Beta\Agents\BetaManagedAgentsAgentToolConfigParams;
   use Anthropic\Beta\Agents\BetaManagedAgentsAgentToolset20260401Params;
+  use Anthropic\Beta\Agents\BetaManagedAgentsWebFetchToolConfigParams;
 
   $agent = $client->beta->agents->create(
       name: 'Coding Assistant',
from line 169
           BetaManagedAgentsAgentToolset20260401Params::with(
               type: 'agent_toolset_20260401',
               configs: [
-                  BetaManagedAgentsAgentToolConfigParams::with(name: 'web_fetch', enabled: false),
+                  BetaManagedAgentsWebFetchToolConfigParams::with(enabled: false),
               ],
           ),
       ],
from line 221
   ]
 }
 ```
+
+### Restrict web search and web fetch domains
+
+To 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.
+
+The 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:
+
+```json
+{
+  "type": "agent_toolset_20260401",
+  "configs": [
+    {
+      "type": "web_search",
+      "name": "web_search",
+      "allowed_domains": ["docs.example.com", "arxiv.org"],
+      "user_location": {
+        "type": "approximate",
+        "country": "US",
+        "timezone": "America/Los_Angeles"
+      }
+    },
+    {
+      "type": "web_fetch",
+      "name": "web_fetch",
+      "blocked_domains": ["ads.example.com"],
+      "max_content_tokens": 50000
+    }
+  ]
+}
+```
+
+<Note>
+  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.
+</Note>
+
+The following request creates an agent with this toolset and prints the `configs` array from the response:
+
+<CodeGroup defaultLanguage="CLI">
+  ```bash cURL
+  agent=$(curl -fsSL https://api.anthropic.com/v1/agents \
+    -H "x-api-key: $ANTHROPIC_API_KEY" \
+    -H "anthropic-version: 2023-06-01" \
+    -H "anthropic-beta: managed-agents-2026-04-01" \
+    -H "content-type: application/json" \
+    -d @- <<'EOF'
+  {
+    "name": "Research Agent",
+    "model": "claude-opus-5",
+    "tools": [
+      {
+        "type": "agent_toolset_20260401",
+        "configs": [
+          {
+            "type": "web_search",
+            "name": "web_search",
+            "allowed_domains": ["docs.example.com", "arxiv.org"],
+            "user_location": {
+              "type": "approximate",
+              "country": "US",
+              "timezone": "America/Los_Angeles"
+            }
+          },
+          {
+            "type": "web_fetch",
+            "name": "web_fetch",
+            "blocked_domains": ["ads.example.com"],
+            "max_content_tokens": 50000
+          }
+        ]
+      }
+    ]
+  }
+  EOF
+  )
+  jq '.tools[0].configs' <<< "$agent"
+  ```
+
+  ```bash CLI
+  ant beta:agents create --transform tools.0.configs <<'YAML'
+  name: Research Agent
+  model: claude-opus-5
+  tools:
+    - type: agent_toolset_20260401
+      configs:
+        - type: web_search
+          name: web_search
+          allowed_domains: [docs.example.com, arxiv.org]
+          user_location:
+            type: approximate
+            country: US
+            timezone: America/Los_Angeles
+        - type: web_fetch
+          name: web_fetch
+          blocked_domains: [ads.example.com]
+          max_content_tokens: 50000
+  YAML
+  ```
+
+  ```python Python
+  client = Anthropic()
+
+  agent = client.beta.agents.create(
+      name="Research Agent",
+      model="claude-opus-5",
+      tools=[
+          {
+              "type": "agent_toolset_20260401",
+              "configs": [
+                  {
+                      "name": "web_search",
+                      "allowed_domains": ["docs.example.com", "arxiv.org"],
+                      "user_location": {
+                          "type": "approximate",
+                          "country": "US",
+                          "timezone": "America/Los_Angeles",
+                      },
+                  },
+                  {
+                      "name": "web_fetch",
+                      "blocked_domains": ["ads.example.com"],
+                      "max_content_tokens": 50_000,
+                  },
+              ],
+          }
+      ],
+  )
+
+  for tool in agent.tools:
+      if tool.type == "agent_toolset_20260401":
+          print(json.dumps([config.to_dict() for config in tool.configs], indent=2))
+  ```
+
+  ```typescript TypeScript
+  const client = new Anthropic();
+
+  const agent = await client.beta.agents.create({
+    name: "Research Agent",
+    model: "claude-opus-5",
+    tools: [
+      {
+        type: "agent_toolset_20260401",
+        configs: [
+          {
+            name: "web_search",
+            allowed_domains: ["docs.example.com", "arxiv.org"],
+            user_location: {
+              type: "approximate",
+              country: "US",
+              timezone: "America/Los_Angeles"
+            }
+          },
+          {
+            name: "web_fetch",
+            blocked_domains: ["ads.example.com"],
+            max_content_tokens: 50_000
+          }
+        ]
+      }
+    ]
+  });
+
+  for (const tool of agent.tools) {
+    if (tool.type === "agent_toolset_20260401") {
+      console.log(JSON.stringify(tool.configs, null, 2));
+    }
+  }
+  ```
+
+  ```csharp C#
+  using Anthropic.Models.Beta.Agents;
+
+  AnthropicClient client = new();
+
+  var agent = await client.Beta.Agents.Create(new()
+  {
+      Name = "Research Agent",
+      Model = BetaManagedAgentsModel.ClaudeOpus5,
+      Tools =
+      [
+          new BetaManagedAgentsAgentToolset20260401Params
+          {
+              Type = BetaManagedAgentsAgentToolset20260401ParamsType.AgentToolset20260401,
+              Configs =
+              [
+                  new BetaManagedAgentsWebSearchToolConfigParams
+                  {
+                      AllowedDomains = ["docs.example.com", "arxiv.org"],
+                      UserLocation = new()
+                      {
+                          Country = "US",
+                          Timezone = "America/Los_Angeles",
+                      },
+                  },
+                  new BetaManagedAgentsWebFetchToolConfigParams
+                  {
+                      BlockedDomains = ["ads.example.com"],
+                      MaxContentTokens = 50_000,
+                  },
+              ],
+          },
+      ],
+  });
+
+  JsonSerializerOptions jsonOptions = new() { WriteIndented = true };
+  foreach (var tool in agent.Tools)
+  {
+      if (tool.TryPickBetaManagedAgentsAgentToolset20260401(out var toolset))
+      {
+          Console.WriteLine(JsonSerializer.Serialize(toolset.Configs, jsonOptions));
+      }
+  }
+  ```
+
+  ```go Go
+  client := anthropic.NewClient()
+  ctx := context.Background()
+
+  agent, err := client.Beta.Agents.New(ctx, anthropic.BetaAgentNewParams{
+  	Name: "Research Agent",
+  	Model: anthropic.BetaManagedAgentsModelConfigParams{
+  		ID: anthropic.BetaManagedAgentsModelClaudeOpus5,
+  	},
+  	Tools: []anthropic.BetaAgentNewParamsToolUnion{{
+  		OfAgentToolset20260401: &anthropic.BetaManagedAgentsAgentToolset20260401Params{
+  			Type: anthropic.BetaManagedAgentsAgentToolset20260401ParamsTypeAgentToolset20260401,
+  			Configs: []anthropic.BetaManagedAgentsAgentToolConfigUnionParamsUnion{
+  				{OfBetaManagedAgentsWebSearchToolConfigs: &anthropic.BetaManagedAgentsWebSearchToolConfigParams{
+  					AllowedDomains: []string{"docs.example.com", "arxiv.org"},
+  					UserLocation: anthropic.BetaManagedAgentsUserLocationParam{
+  						Country:  anthropic.String("US"),
+  						Timezone: anthropic.String("America/Los_Angeles"),
+  					},
+  				}},
+  				{OfBetaManagedAgentsWebFetchToolConfigs: &anthropic.BetaManagedAgentsWebFetchToolConfigParams{
+  					BlockedDomains:   []string{"ads.example.com"},
+  					MaxContentTokens: anthropic.Int(50000),
+  				}},
+  			},
+  		},
+  	}},
+  })
+  if err != nil {
+  	panic(err)
+  }
+
+  for _, tool := range agent.Tools {
+  	switch toolset := tool.AsAny().(type) {
+  	case anthropic.BetaManagedAgentsAgentToolset20260401:
+  		configs := make([]json.RawMessage, len(toolset.Configs))
+  		for i, config := range toolset.Configs {
+  			configs[i] = json.RawMessage(config.RawJSON())
+  		}
+  		output, err := json.MarshalIndent(configs, "", "  ")
+  		if err != nil {
+  			panic(err)
+  		}
+  		fmt.Println(string(output))
+  	}
+  }
+  ```
+
+  ```java Java
+  import com.anthropic.models.beta.agents.AgentCreateParams;
+  import com.anthropic.models.beta.agents.BetaManagedAgentsAgentToolset20260401Params;
+  import com.anthropic.models.beta.agents.BetaManagedAgentsModel;
+  import com.anthropic.models.beta.agents.BetaManagedAgentsUserLocation;
+  import com.anthropic.models.beta.agents.BetaManagedAgentsWebFetchToolConfigParams;
+  import com.anthropic.models.beta.agents.BetaManagedAgentsWebSearchToolConfigParams;
+
+  void main() {
+      var client = AnthropicOkHttpClient.fromEnv();
+
+      var agent = client.beta().agents().create(AgentCreateParams.builder()
+          .name("Research Agent")
+          .model(BetaManagedAgentsModel.CLAUDE_OPUS_5)
+          .addTool(BetaManagedAgentsAgentToolset20260401Params.builder()
+              .type(BetaManagedAgentsAgentToolset20260401Params.Type.AGENT_TOOLSET_20260401)
+              .addConfig(BetaManagedAgentsWebSearchToolConfigParams.builder()
+                  .allowedDomains(List.of("docs.example.com", "arxiv.org"))
+                  .userLocation(BetaManagedAgentsUserLocation.builder()
+                      .country("US")
+                      .timezone("America/Los_Angeles")
+                      .build())
+                  .build())
+              .addConfig(BetaManagedAgentsWebFetchToolConfigParams.builder()
+                  .blockedDomains(List.of("ads.example.com"))
+                  .maxContentTokens(50_000)
+                  .build())
+              .build())
+          .build());
+
+      for (var tool : agent.tools()) {
+          if (tool.isAgentToolset20260401()) {
+              var configs = tool.asAgentToolset20260401().configs();
+              IO.println(ObjectMappers.jsonMapper().valueToTree(configs));
+          }
+      }
+  }
+  ```
+
+  ```php PHP
+  use Anthropic\Beta\Agents\BetaManagedAgentsAgentToolset20260401;
+  use Anthropic\Beta\Agents\BetaManagedAgentsAgentToolset20260401Params;
+  use Anthropic\Beta\Agents\BetaManagedAgentsUserLocation;
+  use Anthropic\Beta\Agents\BetaManagedAgentsWebFetchToolConfigParams;
+  use Anthropic\Beta\Agents\BetaManagedAgentsWebSearchToolConfigParams;
+  // ...
+
+  $client = new Client();
+
+  $agent = $client->beta->agents->create(
+      name: 'Research Agent',
+      model: 'claude-opus-5',
+      tools: [
+          BetaManagedAgentsAgentToolset20260401Params::with(
+              type: 'agent_toolset_20260401',
+              configs: [
+                  BetaManagedAgentsWebSearchToolConfigParams::with(
+                      allowedDomains: ['docs.example.com', 'arxiv.org'],
+                      userLocation: BetaManagedAgentsUserLocation::with(
+                          country: 'US',
+                          timezone: 'America/Los_Angeles',
+                      ),
+                  ),
+                  BetaManagedAgentsWebFetchToolConfigParams::with(
+                      blockedDomains: ['ads.example.com'],
+                      maxContentTokens: 50_000,
+                  ),
+              ],
+          ),
+      ],
+  );
+
+  foreach ($agent->tools as $tool) {
+      if ($tool instanceof BetaManagedAgentsAgentToolset20260401) {
+          echo json_encode($tool->configs, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), PHP_EOL;
+      }
+  }
+  ```
+
+  ```ruby Ruby
+  client = Anthropic::Client.new
+
+  agent = client.beta.agents.create(
+    name: "Research Agent",
+    model: "claude-opus-5",
+    tools: [
+      {
+        type: :agent_toolset_20260401,
+        configs: [
+          {
+            name: :web_search,
+            allowed_domains: ["docs.example.com", "arxiv.org"],
+            user_location: {type: :approximate, country: "US", timezone: "America/Los_Angeles"}
+          },
+          {
+            name: :web_fetch,
+            blocked_domains: ["ads.example.com"],
+            max_content_tokens: 50_000
+          }
+        ]
+      }
+    ]
+  )
+
+  case agent.tools.first
+  in Anthropic::Models::Beta::BetaManagedAgentsAgentToolset20260401 => toolset
+    puts JSON.pretty_generate(toolset.configs.map(&:to_h))
+  end
+  ```
+</CodeGroup>
+
+In 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.
+
+In addition to `enabled` and `permission_policy`, the web tool entries accept the following settings:
+
+| Setting              | Applies to                | Description                                                                                                                                                                                                     |
+| -------------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `allowed_domains`    | `web_search`, `web_fetch` | The only hosts the tool can reach. Cannot be combined with `blocked_domains` on the same entry.                                                                                                                 |
+| `blocked_domains`    | `web_search`, `web_fetch` | Hosts the tool cannot reach.                                                                                                                                                                                    |
+| `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). |
+| `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.           |
+
+<Note>
+  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.
+</Note>
+
+<Note>
+  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.
+</Note>
+
+#### Domain list rules
+
+* Set either `allowed_domains` or `blocked_domains` on an entry, not both. An entry that sets both is rejected.
+* 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`.
+* 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.
+* 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.
+* 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.
+* 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`.
+* `localhost` and hosts ending in `.localhost`, `.local`, `.internal`, `.localdomain`, or `.invalid` are rejected.
+* Use the `xn--` (Punycode) form for internationalized domain names; a domain that contains non-ASCII characters is rejected.
+* 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.
+* 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.
+
+#### When settings are validated
+
+Format 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"`.
+
+The 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.
+
+#### Multiagent sessions, outcomes, and mid-session updates
+
+In 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.
+
+* 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.
+* 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.
+* `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.
+* A `{"type": "self"}` roster entry has no web settings of its own and follows the coordinator's current settings.
+* 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.
+* 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.
+
+#### Differences from the Messages API tools
+
+These 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:
+
+* Each list is capped at 64 domains.
+* Domains listed for `web_fetch` cannot include a path.
+* `max_uses`, `citations`, and `cache_control` are not available on the toolset.
 
 ## Custom tools
 
 

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

from line 14
 
 * 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).
 
+- 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.
+
+* [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).
+
+- 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).
+- 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).
+- 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).
+
 ### August 18, 2026
 
 * 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
 
 As 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.
 
-Note 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.
+Note 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.
 
 ### Start specific, consolidate later