Follow Discord
Sweep 27 Oct 2026 · 19:04Z Build v2.1.312 531 read Stable v2.1.308 Latest v2.1.312 Next v2.1.312 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One capture · api

One read of Claude Developer Platformapi-20261027T185806Z

260 pages moved out of 821 read.

Pages moved 260 significant first
Pages read 821 in this capture
Captured 18:58 UTC
Corpus hash 23cb04cc4921 corpus-hash

What this read moved

201-225 of 260, page 9 of 11

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

managed-agents/permission-policies Changed · +7 / -7 lines

from line 26
2626 
2727## Set a policy for a toolset
2828 
29You set permission policies in the agent's `tools` (csharp, go: `Tools`) configuration when you create the agent, and you can change them later by [updating the agent](https://platform.claude.com/docs/en/managed-agents/agent-setup#update-an-agent). Running sessions keep the toolset configuration they were created with. Updates apply to sessions created afterward.
29You set permission policies in the agent’s `tools` (csharp, go: `Tools`) configuration when you create the agent, and you can change them later by [updating the agent](https://platform.claude.com/docs/en/managed-agents/agent-setup#update-an-agent). Running sessions keep the toolset configuration they were created with. Updates apply to sessions created afterward.
3030 
3131### Agent toolset permissions
3232 
from line 632
632632 
633633## Let the server evaluate each call with `auto`
634634 
635With the `auto` permission policy, the server evaluates each call before it runs. Because the evaluation considers the tool, the call's input, and the session's content up to that point, the server can treat two calls to the same tool differently. Each call has one of three outcomes:
635With the `auto` permission policy, the server evaluates each call before it runs. Because the evaluation considers the tool, the call’s input, and the session’s content up to that point, the server can treat two calls to the same tool differently. Each call has one of three outcomes:
636636 
637637* **The call runs.** When the server determines that the call is safe, the tool runs as it would under `always_allow`.
638638* **The call is denied.** When the server evaluates the call as high-risk, the tool does not run. The agent receives an error tool result with the content `Permission to use {tool_name} has been denied.` and `is_error: true`. The session keeps running, and your client cannot override the denial.
639639* **The call pauses for your approval.** When the server reaches no determination, the session pauses as it does under `always_ask`. See [Respond to confirmation requests](https://platform.claude.com/docs/en/managed-agents/permission-policies#respond-to-confirmation-requests).
640640 
641To turn on `auto`, set `permission_policy` to `{"type": "auto"}`. It goes in the same two places as the other policies: a toolset's [`default_config` (java, php: `defaultConfig`; csharp, go: `DefaultConfig`)](https://platform.claude.com/docs/en/managed-agents/permission-policies#set-a-policy-for-a-toolset) for the whole toolset, or a [`configs` (csharp, go: `Configs`) entry](https://platform.claude.com/docs/en/managed-agents/permission-policies#override-an-individual-tool-policy) for one tool. The agent toolset and MCP toolsets both accept it. No toolset uses `auto` by default.
641To turn on `auto`, set `permission_policy` to `{"type": "auto"}`. It goes in the same two places as the other policies: a toolset’s [`default_config` (java, php: `defaultConfig`; csharp, go: `DefaultConfig`)](https://platform.claude.com/docs/en/managed-agents/permission-policies#set-a-policy-for-a-toolset) for the whole toolset, or a [`configs` (csharp, go: `Configs`) entry](https://platform.claude.com/docs/en/managed-agents/permission-policies#override-an-individual-tool-policy) for one tool. The agent toolset and MCP toolsets both accept it. No toolset uses `auto` by default.
642642 
643643The following example sets `auto` as the default for the agent toolset and for the `github` MCP toolset, and overrides `bash` to `always_ask`:
644644 
from line 958
958958 ```
959959</CodeGroup>
960960 
961What you post in `user.message` events counts as your intent, and it can lead the server to allow a call it would otherwise deny. The server does not read intent from a tool result, a fetched webpage, an MCP server's response, or a message between [session threads](https://platform.claude.com/docs/en/managed-agents/session-threads#tool-permissions-and-custom-tools). It assesses that content but does not take instructions from it. The server evaluates some calls as high-risk no matter who asks. If you relay untrusted end-user input in `user.message` events, the server reads that input as your intent too, and it can get a call allowed. Configure `always_ask` on the tools you would not let that end user run without review.
961What you post in `user.message` events counts as your intent, and it can lead the server to allow a call it would otherwise deny. The server does not read intent from a tool result, a fetched webpage, an MCP server’s response, or a message between [session threads](https://platform.claude.com/docs/en/managed-agents/session-threads#tool-permissions-and-custom-tools). It assesses that content but does not take instructions from it. The server evaluates some calls as high-risk no matter who asks. If you relay untrusted end-user input in `user.message` events, the server reads that input as your intent too, and it can get a call allowed. Configure `always_ask` on the tools you would not let that end user run without review.
962962 
963963<Warning>
964 `auto` is not a human checkpoint. If the server determines that a call is safe, the call runs before anyone sees it, and its effects might not be reversible. If a person must review a tool's calls before they run, configure `always_ask` on that tool.
964 `auto` is not a human checkpoint. If the server determines that a call is safe, the call runs before anyone sees it, and its effects might not be reversible. If a person must review a tool’s calls before they run, configure `always_ask` on that tool.
965965</Warning>
966966 
967967## See how each call was evaluated
968968 
969Under any permission policy, each `agent.tool_use` and `agent.mcp_tool_use` event carries `evaluated_permission`, the outcome of the call's permission check: `"allow"`, `"ask"`, or `"deny"`. Most events also carry an `evaluation` object whose `type` names the policy that produced that outcome. Under `auto`, the object also records the server's determination, plus a `reason_code` when the outcome is `ask` or `deny`.
969Under any permission policy, each `agent.tool_use` and `agent.mcp_tool_use` event carries `evaluated_permission`, the outcome of the call’s permission check: `"allow"`, `"ask"`, or `"deny"`. Most events also carry an `evaluation` object whose `type` names the policy that produced that outcome. Under `auto`, the object also records the server’s determination, plus a `reason_code` when the outcome is `ask` or `deny`.
970970 
971971For example, when `bash` is under `auto` and the server evaluates a call as high-risk, the denied call appears on the event stream as follows:
972972 
from line 1000
10001000| `{"type": "auto", "evaluated_permission": {"type": "ask", "reason_code": "indeterminate"}}` | `"ask"` | Under `auto`, the server reached no determination, so the call paused for your approval. |
10011001| `{"type": "auto", "evaluated_permission": {"type": "deny", "reason_code": "high_risk"}}` | `"deny"` | Under `auto`, the server evaluated the call as high-risk and denied it. |
10021002 
1003When `evaluation.type` is `"auto"`, its nested `evaluated_permission.type` repeats the event's top-level `evaluated_permission`, so you can read the outcome from either field. A `reason_code` is a value for your client to branch on and keep in audit records, not text to display to end users.
1003When `evaluation.type` is `"auto"`, its nested `evaluated_permission.type` repeats the event’s top-level `evaluated_permission`, so you can read the outcome from either field. A `reason_code` is a value for your client to branch on and keep in audit records, not text to display to end users.
10041004 
10051005`evaluation` is absent in two cases. When the agent names a tool that is not enabled in the session, the server denies the call without evaluating a policy: the event carries `evaluated_permission: "deny"` and no `evaluation`. Events recorded before `evaluation` was introduced also omit it: read those as `always_allow` when `evaluated_permission` is `"allow"` and as `always_ask` when it is `"ask"`.
10061006 

managed-agents/quickstart Changed · +15 / -15 lines

## What’s happening ## What's happening

from line 45
4545 For Linux environments, download the release binary directly.
4646 
4747 ```bash
48 VERSION=2.3.0
48 VERSION=2.4.0
4949 OS=$(uname -s | tr '[:upper:]' '[:lower:]')
5050 case $(uname -m) in
5151 x86_64) ARCH=amd64 ;;
from line 65
6565 go install github.com/anthropics/anthropic-cli/v2/cmd/ant@latest
6666 ```
6767 
68 The binary is placed in `$(go env GOPATH)/bin`. Add it to your `PATH` if it isn't already:
68 The binary is placed in `$(go env GOPATH)/bin`. Add it to your `PATH` if it isn’t already:
6969 
7070 ```bash
7171 export PATH="$PATH:$(go env GOPATH)/bin"
from line 155
155155 }'
156156 ```
157157 
158 Save the returned `agent.id`. You'll reference it in every session you create.
158 Save the returned `agent.id`. You’ll reference it in every session you create.
159159 </CodeGroupItem>
160160 
161161 <CodeGroupItem>
from line 176
176176 ```
177177 </File>
178178 
179 [`ant apply`](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/apply) prints the agent's ID and records it in `claude-lock.json`. You'll reference it in every session you create.
179 [`ant apply`](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/apply) prints the agent’s ID and records it in `claude-lock.json`. You’ll reference it in every session you create.
180180 </CodeGroupItem>
181181 
182182 <CodeGroupItem>
from line 197
197197 print(f"Agent ID: {agent.id}, version: {agent.version}")
198198 ```
199199 
200 Save the returned `agent.id`. You'll reference it in every session you create.
200 Save the returned `agent.id`. You’ll reference it in every session you create.
201201 </CodeGroupItem>
202202 
203203 <CodeGroupItem>
from line 216
216216 console.log(`Agent ID: ${agent.id}, version: ${agent.version}`);
217217 ```
218218 
219 Save the returned `agent.id`. You'll reference it in every session you create.
219 Save the returned `agent.id`. You’ll reference it in every session you create.
220220 </CodeGroupItem>
221221 
222222 <CodeGroupItem>
from line 240
240240 Console.WriteLine($"Agent ID: {agent.ID}, version: {agent.Version}");
241241 ```
242242 
243 Save the returned `agent.id`. You'll reference it in every session you create.
243 Save the returned `agent.id`. You’ll reference it in every session you create.
244244 </CodeGroupItem>
245245 
246246 <CodeGroupItem>
from line 275
275275 fmt.Printf("Agent ID: %s, version: %d\n", agent.ID, agent.Version)
276276 ```
277277 
278 Save the returned `agent.id`. You'll reference it in every session you create.
278 Save the returned `agent.id`. You’ll reference it in every session you create.
279279 </CodeGroupItem>
280280 
281281 <CodeGroupItem>
from line 305
305305 IO.println("Agent ID: " + agent.id() + ", version: " + agent.version());
306306 ```
307307 
308 Save the returned `agent.id`. You'll reference it in every session you create.
308 Save the returned `agent.id`. You’ll reference it in every session you create.
309309 </CodeGroupItem>
310310 
311311 <CodeGroupItem>
from line 327
327327 echo "Agent ID: {$agent->id}, version: {$agent->version}\n";
328328 ```
329329 
330 Save the returned `agent.id`. You'll reference it in every session you create.
330 Save the returned `agent.id`. You’ll reference it in every session you create.
331331 </CodeGroupItem>
332332 
333333 <CodeGroupItem>
from line 346
346346 puts "Agent ID: #{agent.id}, version: #{agent.version}"
347347 ```
348348 
349 Save the returned `agent.id`. You'll reference it in every session you create.
349 Save the returned `agent.id`. You’ll reference it in every session you create.
350350 </CodeGroupItem>
351351 </CodeGroup>
352352 
from line 393
393393 ```
394394 </File>
395395 
396 [`ant apply`](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/apply) records the environment's ID in `claude-lock.json` too. To create the agent and the environment with one command, pass both files: `ant apply coding-assistant.md environment.yaml`.
396 [`ant apply`](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/apply) records the environment’s ID in `claude-lock.json` too. To create the agent and the environment with one command, pass both files: `ant apply coding-assistant.md environment.yaml`.
397397 </CodeGroupItem>
398398 
399399 <CodeGroupItem>
from line 900
900900 </Step>
901901</Steps>
902902 
903## What's happening
903## What’s happening
904904 
905905When you send a user event, Claude Managed Agents:
906906 
9071. **Provisions a sandbox:** Your environment configuration determines how it's built.
9071. **Provisions a sandbox:** Your environment configuration determines how it’s built.
9089082. **Runs the agent loop:** Claude determines which tools to use based on your message.
9099093. **Runs tools:** File writes, bash commands, and other tool calls run inside the sandbox.
9109104. **Streams events:** You receive real-time updates as the agent works.
from line 916
916916 
917917<CardGroup cols={3}>
918918 <Card title="Chat SDK" icon="github-logo" href="https://github.com/anthropics/claude-quickstarts/tree/main/managed-agents/chat-sdk">
919 A research analyst in a browser chat built with Vercel's Chat SDK. Each conversation is one persistent session that streams its reply while a live feed shows the tool calls. Swapping the Chat SDK adapter moves the same handler to Slack, Teams, Discord, or WhatsApp.
919 A research analyst in a browser chat built with Vercel’s Chat SDK. Each conversation is one persistent session that streams its reply while a live feed shows the tool calls. Swapping the Chat SDK adapter moves the same handler to Slack, Teams, Discord, or WhatsApp.
920920 </Card>
921921 
922922 <Card title="assistant-ui" icon="github-logo" href="https://github.com/anthropics/claude-quickstarts/tree/main/managed-agents/assistant-ui">

managed-agents/reference Changed · +15 / -15 lines

from line 14
1414 
1515## Event types
1616 
17Persisted event type strings follow a `{domain}.{action}` naming convention; the stream-only event deltas (see the **Event deltas** tab) are the exception. See [Session event stream](https://platform.claude.com/docs/en/managed-agents/events-and-streaming) for sending, streaming, and listing events. Webhook event types are listed separately in [Subscribe to webhooks](https://platform.claude.com/docs/en/managed-agents/webhooks#supported-event-types), and some of their names differ from the stream's (for example, `session.status_idled` rather than `session.status_idle`).
17Persisted event type strings follow a `{domain}.{action}` naming convention; the stream-only event deltas (see the **Event deltas** tab) are the exception. See [Session event stream](https://platform.claude.com/docs/en/managed-agents/events-and-streaming) for sending, streaming, and listing events. Webhook event types are listed separately in [Subscribe to webhooks](https://platform.claude.com/docs/en/managed-agents/webhooks#supported-event-types), and some of their names differ from the stream’s (for example, `session.status_idled` rather than `session.status_idle`).
1818 
1919<Tabs>
2020 <Tab title="User events">
from line 55
5555 | `session.deleted` | Session was deleted. Ends any active event stream; no further events are emitted for this session. |
5656 | `session.updated` | Session update request changed at least one field. Includes only the fields that changed. Updates apply on the next turn. |
5757 | `session.error` | An error occurred during processing. Includes a typed `error` (csharp, go: `Error`) object with a `retry_status` (java, php: `retryStatus`; csharp, go: `RetryStatus`). |
58 | `session.usage` | Snapshot of the session's cumulative usage and tracked list cost. Carries the session's usage totals and, if the session has one, its [budget](https://platform.claude.com/docs/en/managed-agents/budgets). |
59 | `session.thread_created` | A [multiagent](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration) thread was created. It includes `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`): the run's ID for a [workflow run's thread](https://platform.claude.com/docs/en/managed-agents/workflow-runs#a-runs-threads), and `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) for any other thread. |
58 | `session.usage` | Snapshot of the session’s cumulative usage and tracked list cost. Carries the session’s usage totals and, if the session has one, its [budget](https://platform.claude.com/docs/en/managed-agents/budgets). |
59 | `session.thread_created` | A [multiagent](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration) thread was created. It includes `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`): the run’s ID for a [workflow run’s thread](https://platform.claude.com/docs/en/managed-agents/workflow-runs#a-runs-threads), and `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) for any other thread. |
6060 | `session.thread_status_running` | A session thread began executing. Every session emits this for its primary thread; in [multiagent](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration) sessions, child-thread transitions are also cross-posted to the primary stream. |
6161 | `session.thread_status_idle` | A session thread finished its turn and is awaiting input. Includes `stop_reason` (java, php: `stopReason`; csharp, go: `StopReason`). |
6262 | `session.thread_status_rescheduled` | A session thread hit a transient error and is retrying automatically. |
63 | `session.thread_status_terminated` | A session thread terminated and accepts no further input, for example because it was archived or hit an unrecoverable error. An advisor thread also terminates when its consultation ends. The server archives a workflow run's threads itself. |
63 | `session.thread_status_terminated` | A session thread terminated and accepts no further input, for example because it was archived or hit an unrecoverable error. An advisor thread also terminates when its consultation ends. The server archives a workflow run’s threads itself. |
6464 
65 In a session whose agent has [dynamic workflows](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#dynamic-workflows) turned on, these `workflow_run.*` events arrive on the session's stream:
65 In a session whose agent has [dynamic workflows](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#dynamic-workflows) turned on, these `workflow_run.*` events arrive on the session’s stream:
6666 
6767 | Type | Description |
6868 | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
69 | `workflow_run.created` | A workflow run was created. Includes `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`), the run's `name` (csharp, go: `Name`) and `description` (csharp, go: `Description`), and `phases` (csharp, go: `Phases`), the phases declared for the run. A status event follows, though after an interrupt it might not. |
69 | `workflow_run.created` | A workflow run was created. Includes `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`), the run’s `name` (csharp, go: `Name`) and `description` (csharp, go: `Description`), and `phases` (csharp, go: `Phases`), the phases declared for the run. A status event follows, though after an interrupt it might not. |
7070 | `workflow_run.status_running` | A workflow run is running. Sent when the run starts to execute, which can be a while after `workflow_run.created`, and again when it resumes after a pause at the budget. A resume after an interrupt might not send it. A run that is idle from the start might get `workflow_run.status_idle` first. Includes `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`). |
71 | `workflow_run.status_idle` | A workflow run went idle: it was paused, for example at the session's budget. A pause after an interrupt might not send it. Includes `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`). |
71 | `workflow_run.status_idle` | A workflow run went idle: it was paused, for example at the session’s budget. A pause after an interrupt might not send it. Includes `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`). |
7272 | `workflow_run.status_ended` | A workflow run ended. Includes `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) and `result` (csharp, go: `Result`), whose `type` (csharp, go: `Type`) says how the run ended. |
7373 | `workflow_run.error` | An error of a workflow run, or a start that the server refused. A run that ends in error gets it, with the same error, before its `workflow_run.status_ended`. Includes `error` (csharp, go: `Error`) and `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`), which is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) when no run was created. |
7474 | `workflow_run.phase_started` | A workflow run entered one of its phases. Includes `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) and `workflow_run_phase_id` (java: `workflowRunPhaseId`; php: `workflowRunPhaseID`; csharp, go: `WorkflowRunPhaseID`). |
from line 94
9494 </Tab>
9595 
9696 <Tab title="Event deltas">
97 Event deltas are stream-only preview events. They are emitted on stream connections (session-level or per-thread) that opt in with the `event_deltas` (curl: `event_deltas[]`; cli: `--event-delta`; java, php: `eventDeltas`; csharp, go: `EventDeltas`) parameter, and they are never persisted to the session's event history. See [Preview responses with event deltas](https://platform.claude.com/docs/en/managed-agents/event-deltas) for opting in, accumulating, and reconciling them.
97 Event deltas are stream-only preview events. They are emitted on stream connections (session-level or per-thread) that opt in with the `event_deltas` (curl: `event_deltas[]`; cli: `--event-delta`; java, php: `eventDeltas`; csharp, go: `EventDeltas`) parameter, and they are never persisted to the session’s event history. See [Preview responses with event deltas](https://platform.claude.com/docs/en/managed-agents/event-deltas) for opting in, accumulating, and reconciling them.
9898 
9999 | Type | Description |
100100 | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
101 | `event_start` | A previewed event has started generating. Carries the upcoming event's `type` (csharp, go: `Type`) and `id` (csharp, go: `ID`). Stream-only and never persisted. |
101 | `event_start` | A previewed event has started generating. Carries the upcoming event’s `type` (csharp, go: `Type`) and `id` (csharp, go: `ID`). Stream-only and never persisted. |
102102 | `event_delta` | Incremental content for a previewed event, identified by `event_id` (java: `eventId`; php: `eventID`; csharp, go: `EventID`). Stream-only and never persisted. |
103103 </Tab>
104104</Tabs>
from line 109
109109 
110110## Supported MCP server types
111111 
112Claude 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.
112Claude 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.
113113 
114114For more information on MCP and building MCP servers, see the [MCP documentation](https://modelcontextprotocol.io).
115115 
from line 130
130130 
131131**Allowed:**
132132 
133* "Claude Agent" (preferred for dropdown menus)
134* "Claude" (when within a menu already labeled "Agents")
135* "\{YourAgentName} Powered by Claude" (if you have an existing agent name)
133* “Claude Agent” (preferred for dropdown menus)
134* “Claude” (when within a menu already labeled “Agents”)
135* “\{YourAgentName} Powered by Claude” (if you have an existing agent name)
136136 
137137**Not permitted:**
138138 
139* "Claude Code" or "Claude Code Agent"
140* "Claude Cowork" or "Claude Cowork Agent"
139* “Claude Code” or “Claude Code Agent”
140* “Claude Cowork” or “Claude Cowork Agent”
141141* Claude Code-branded ASCII art or visual elements that mimic Claude Code
142142 
143143Your product should maintain its own branding and not appear to be Claude Code, Claude Cowork, or any other Anthropic product. For questions about branding compliance, contact the Anthropic [sales team](https://www.anthropic.com/contact-sales).

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

from line 19
1919When 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` (csharp, go: `Schedule`).
2020 
2121* 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-memory) 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 the SDK instead.
22* Deployments also require at least one initial event, a `user.message` or `user.define_outcome`, that starts each session's work. In a deployment file for `ant apply`, the text below the frontmatter becomes that `user.message`.
22* Deployments also require at least one initial event, a `user.message` or `user.define_outcome`, that starts each session’s work. In a deployment file for `ant apply`, the text below the frontmatter becomes that `user.message`.
2323* In the `schedule` (csharp, go: `Schedule`), you define a cron `expression` (csharp, go: `Expression`) and a `timezone` (csharp, go: `Timezone`). Maximum granularity supported is at the minute level.
2424 
2525<Note>
from line 73
7373 ```
7474 </File>
7575 
76 [`ant apply`](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/apply) prints the new deployment's ID and records it in `claude-lock.json`. To see the deployment object, run `ant beta:deployments retrieve`.
76 [`ant apply`](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/apply) prints the new deployment’s ID and records it in `claude-lock.json`. To see the deployment object, run `ant beta:deployments retrieve`.
7777 </CodeGroupItem>
7878 
7979 ```python Python
from line 260
260260 
261261Pass the optional `budget` (csharp, go: `Budget`) object when you create or update the deployment. It takes the same shape as a [session budget](https://platform.claude.com/docs/en/managed-agents/budgets). The deployment copies the cap onto each session it starts, so the budget bounds every run separately rather than acting as a cumulative ceiling across runs: a deployment with a `"2000"` cap can spend up to about $20 USD on every run.
262262 
263A session started by the deployment behaves exactly like any other budgeted session: it pauses with `budget_reached` when its own list cost [reaches the cap](https://platform.claude.com/docs/en/managed-agents/budgets#when-a-session-reaches-its-budget). Changing the deployment's budget applies to runs started afterward; a session already running keeps the cap it started with, which you can [change through the session itself](https://platform.claude.com/docs/en/managed-agents/session-operations#updating-the-session-budget). Unlike a session budget, a deployment's budget can be removed with `"budget": null` (python: `budget=None`; typescript: `budget: null`; ruby: `budget: nil`; go: `Budget: param.NullStruct[anthropic.BetaManagedAgentsBudgetLimitParam]()`; java: `.budget(Optional.empty())`; csharp: `Budget = null`; php: `requestOptions: ['extraBodyParams' => ['budget' => null]]`; cli: `--budget null`) and set again later.
263A session started by the deployment behaves exactly like any other budgeted session: it pauses with `budget_reached` when its own list cost [reaches the cap](https://platform.claude.com/docs/en/managed-agents/budgets#when-a-session-reaches-its-budget). Changing the deployment’s budget applies to runs started afterward; a session already running keeps the cap it started with, which you can [change through the session itself](https://platform.claude.com/docs/en/managed-agents/session-operations#updating-the-session-budget). Unlike a session budget, a deployment’s budget can be removed with `"budget": null` (python: `budget=None`; typescript: `budget: null`; ruby: `budget: nil`; go: `Budget: param.NullStruct[anthropic.BetaManagedAgentsBudgetLimitParam]()`; java: `.budget(Optional.empty())`; csharp: `Budget = null`; php: `requestOptions: ['extraBodyParams' => ['budget' => null]]`; cli: `--budget null`) and set again later.
264264 
265265The following example sets a budget on an existing deployment:
266266 
from line 395
395395 
396396Deployments can fail to trigger for a variety of reasons: for example, if the `environment` resource has been archived, or if session creation is rate-limited. Each attempt generates a **deployment run** record, allowing you to track successes and failures independent of the session lifecycle.
397397 
398Successful deployments generate active sessions, and a successful deployment run contains the associated `session_id` (java: `sessionId`; php: `sessionID`; csharp, go: `SessionID`). To follow a session's lifecycle, track the session events through the [event stream](https://platform.claude.com/docs/en/managed-agents/events-and-streaming) or [webhooks](https://platform.claude.com/docs/en/managed-agents/webhooks). Deployment lifecycle changes and the outcome of each scheduled run are also delivered as webhook events, listed in the **Deployment events** and **Deployment run events** tabs of [Supported event types](https://platform.claude.com/docs/en/managed-agents/webhooks#supported-event-types).
398Successful deployments generate active sessions, and a successful deployment run contains the associated `session_id` (java: `sessionId`; php: `sessionID`; csharp, go: `SessionID`). To follow a session’s lifecycle, track the session events through the [event stream](https://platform.claude.com/docs/en/managed-agents/events-and-streaming) or [webhooks](https://platform.claude.com/docs/en/managed-agents/webhooks). Deployment lifecycle changes and the outcome of each scheduled run are also delivered as webhook events, listed in the **Deployment events** and **Deployment run events** tabs of [Supported event types](https://platform.claude.com/docs/en/managed-agents/webhooks#supported-event-types).
399399 
400400List all deployment runs for a deployment as follows:
401401 
from line 735
735735 
736736Session creation rate-limit responses are recorded immediately as a `session_rate_limited_error` run without retry; the schedule attempts again at the next scheduled occurrence. Rate limits on underlying API calls within a session are handled by the session itself.
737737 
738If a deployment's agent has been archived, the deployment is automatically archived in the same operation. If the agent has been deleted, the next scheduled trigger detects the missing agent and automatically archives the deployment. In both cases no deployment run is recorded. If a subagent referenced by the agent has been archived, the next trigger records a failed run with `error.type: "agent_archived_error"` and the deployment is automatically paused so you can update the agent and resume. Other unrecoverable session-creation errors, such as an archived environment or vault, behave the same way: the trigger records a failed run and the deployment is automatically paused. The deployment's `paused_reason.error.type` mirrors the failed run's `error.type`.
738If a deployment’s agent has been archived, the deployment is automatically archived in the same operation. If the agent has been deleted, the next scheduled trigger detects the missing agent and automatically archives the deployment. In both cases no deployment run is recorded. If a subagent referenced by the agent has been archived, the next trigger records a failed run with `error.type: "agent_archived_error"` and the deployment is automatically paused so you can update the agent and resume. Other unrecoverable session-creation errors, such as an archived environment or vault, behave the same way: the trigger records a failed run and the deployment is automatically paused. The deployment’s `paused_reason.error.type` mirrors the failed run’s `error.type`.
739739 
740740## Trigger a manual run
741741 

managed-agents/secure-deployment Changed · +32 / -32 lines

from line 23
2323| [Give the agent the smallest tool set](https://platform.claude.com/docs/en/managed-agents/secure-deployment#give-the-agent-the-smallest-tool-set) | `default_config.enabled` on the agent toolset | `false`, then enable the tools the agent needs |
2424| [Keep untrusted input away from powerful tools](https://platform.claude.com/docs/en/managed-agents/secure-deployment#keep-untrusted-input-away-from-powerful-tools) | Which tools and credentials an agent holds when it reads untrusted input | No agent that reads untrusted input has a tool on `always_allow` that writes files, runs commands, or changes records |
2525| [Set limits and a way to stop](https://platform.claude.com/docs/en/managed-agents/secure-deployment#set-limits-and-a-way-to-stop) | `budget` on each session and deployment | A cap sized to what you expect a run to cost |
26| [Optionally have an offline reviewer read every transcript](https://platform.claude.com/docs/en/managed-agents/secure-deployment-monitoring#optionally-have-an-offline-reviewer-read-every-transcript) | An offline review job you run that reads each session's events | Optional. A review of each session that went idle or terminated, on a schedule |
26| [Optionally have an offline reviewer read every transcript](https://platform.claude.com/docs/en/managed-agents/secure-deployment-monitoring#optionally-have-an-offline-reviewer-read-every-transcript) | An offline review job you run that reads each session’s events | Optional. A review of each session that went idle or terminated, on a schedule |
2727| [Monitor sessions and review retention](https://platform.claude.com/docs/en/managed-agents/secure-deployment-monitoring#monitor-sessions-and-review-retention) | Webhooks and session deletion | An alert when a session goes idle, reaches its budget, or terminates, and a check of why it went idle. Store the events you want to keep in your own logs, and delete sessions you no longer need |
2828 
2929[Security risks and sandbox boundaries](https://platform.claude.com/docs/en/managed-agents/secure-deployment-risks) explains why these settings matter and what they do not protect against. To review and monitor sessions, see [Review and monitor agent sessions](https://platform.claude.com/docs/en/managed-agents/secure-deployment-monitoring).
from line 36
3636/claude-api managed-agents-secure
3737```
3838 
39The command changes nothing, and its report lists each setting to change with its recommended value and the questions only you can answer. Before you run it, update Claude Code and set up the `ant` CLI for the agent's workspace, as the [CLI quickstart](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/quickstart) shows.
39The command changes nothing, and its report lists each setting to change with its recommended value and the questions only you can answer. Before you run it, update Claude Code and set up the `ant` CLI for the agent’s workspace, as the [CLI quickstart](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/quickstart) shows.
4040 
4141## Choose where the agent runs
4242 
43Where the agent's tools run determines who secures the sandbox: Anthropic, with a cloud environment, or you, with a self-hosted sandbox. To choose between them and learn what reaches Anthropic with each, see [Choosing an agent environment](https://platform.claude.com/docs/en/managed-agents/choosing-an-environment).
43Where the agent’s tools run determines who secures the sandbox: Anthropic, with a cloud environment, or you, with a self-hosted sandbox. To choose between them and learn what reaches Anthropic with each, see [Choosing an agent environment](https://platform.claude.com/docs/en/managed-agents/choosing-an-environment).
4444 
4545If you use a [self-hosted sandbox](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes), keep these four points in mind:
4646 
4747* **Network:** [Limit the network](https://platform.claude.com/docs/en/managed-agents/secure-deployment#limit-the-network) applies to cloud environments. For a self-hosted sandbox, set the equivalent limits on its traffic in your own firewall. Your firewall does not limit the MCP servers an agent declares, so review them, and any that your application sets for a session.
48* **Web tools:** The web tools run on Anthropic's servers, so your firewall does not limit them. Limit them with their domain lists. See [Restrict web search and web fetch](https://platform.claude.com/docs/en/managed-agents/secure-deployment#restrict-web-search-and-web-fetch).
48* **Web tools:** The web tools run on Anthropic’s servers, so your firewall does not limit them. Limit them with their domain lists. See [Restrict web search and web fetch](https://platform.claude.com/docs/en/managed-agents/secure-deployment#restrict-web-search-and-web-fetch).
4949* **Credentials:** Environment variable credentials are not yet supported with self-hosted sandboxes.
5050* **Isolation and hardening:** You are responsible for both. See the [Security model](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-security).
5151 
from line 57
5757 
5858Files, memory stores, and GitHub repositories that you attach stay available to the agent regardless of `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`).
5959 
60The examples on this page use a support agent. It reads a customer's ticket, looks up the order, reads your help center, and drafts a reply. Your application runs the order lookup, which needs no host, so this environment allows one host, the help center, for `web_fetch`:
60The examples on this page use a support agent. It reads a customer’s ticket, looks up the order, reads your help center, and drafts a reply. Your application runs the order lookup, which needs no host, so this environment allows one host, the help center, for `web_fetch`:
6161 
6262<CodeGroup defaultLanguage="CLI">
6363 ```bash cURL
from line 203
203203| Setting | What it opens to code in the sandbox | Recommended |
204204| ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
205205| `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) | The hosts you list, for any request | Only the hosts the agent needs, including the host of each MCP server you operate or trust |
206| `allow_package_managers` (java, php: `allowPackageManagers`; csharp, go: `AllowPackageManagers`) | The [package manager hosts](https://platform.claude.com/docs/en/managed-agents/environments#package-manager-hosts). They include every repository and path on `github.com`, `gitlab.com`, and `bitbucket.org`, where anyone can publish content and where code in the sandbox can upload files | `false`, unless the environment's `packages` (csharp, go: `Packages`) setting lists packages, which requires `true`. If the agent installs packages while it runs, list only the registry hosts it needs in `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) instead |
207| `allow_mcp_servers` (java: `allowMcpServers`; php: `allowMCPServers`; csharp: `AllowMcpServers`; go: `AllowMCPServers`) | No host. Managed Agents connects to MCP servers from Anthropic's servers | `false`, with the host of each MCP server you operate or trust listed in `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) |
206| `allow_package_managers` (java, php: `allowPackageManagers`; csharp, go: `AllowPackageManagers`) | The [package manager hosts](https://platform.claude.com/docs/en/managed-agents/environments#package-manager-hosts). They include every repository and path on `github.com`, `gitlab.com`, and `bitbucket.org`, where anyone can publish content and where code in the sandbox can upload files | `false`, unless the environment’s `packages` (csharp, go: `Packages`) setting lists packages, which requires `true`. If the agent installs packages while it runs, list only the registry hosts it needs in `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) instead |
207| `allow_mcp_servers` (java: `allowMcpServers`; php: `allowMCPServers`; csharp: `AllowMcpServers`; go: `AllowMCPServers`) | No host. Managed Agents connects to MCP servers from Anthropic’s servers | `false`, with the host of each MCP server you operate or trust listed in `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) |
208208 
209209The `allow_package_managers` (java, php: `allowPackageManagers`; csharp, go: `AllowPackageManagers`) and `allow_mcp_servers` (java: `allowMcpServers`; php: `allowMCPServers`; csharp: `AllowMcpServers`; go: `AllowMCPServers`) settings add no hosts for web search and web fetch.
210210 
211Leave `allow_mcp_servers` (java: `allowMcpServers`; php: `allowMCPServers`; csharp: `AllowMcpServers`; go: `AllowMCPServers`) off, which is the default, and list the host of each MCP server you operate or trust in `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`). Each host you list is also open to code in the sandbox. With `allow_mcp_servers` (java: `allowMcpServers`; php: `allowMCPServers`; csharp: `AllowMcpServers`; go: `AllowMCPServers`) off, a check at session creation rejects the request if an MCP server's host is not listed. See [Provide authentication at session creation](https://platform.claude.com/docs/en/managed-agents/mcp-connector#provide-authentication-at-session-creation). The same check runs when a session update changes `mcp_servers` (java, php: `mcpServers`; csharp: `McpServers`; go: `MCPServers`).
211Leave `allow_mcp_servers` (java: `allowMcpServers`; php: `allowMCPServers`; csharp: `AllowMcpServers`; go: `AllowMCPServers`) off, which is the default, and list the host of each MCP server you operate or trust in `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`). Each host you list is also open to code in the sandbox. With `allow_mcp_servers` (java: `allowMcpServers`; php: `allowMCPServers`; csharp: `AllowMcpServers`; go: `AllowMCPServers`) off, a check at session creation rejects the request if an MCP server’s host is not listed. See [Provide authentication at session creation](https://platform.claude.com/docs/en/managed-agents/mcp-connector#provide-authentication-at-session-creation). The same check runs when a session update changes `mcp_servers` (java, php: `mcpServers`; csharp: `McpServers`; go: `MCPServers`).
212212 
213213<Warning>
214214 Network access is granted by host, not by operation. The sandbox can send any request to an allowed host, including uploads such as `git push` and package publishing. It can also use any credential the command supplies, even one that someone hid in text the agent reads.
from line 219
219219* List only hosts you operate or trust.
220220* Avoid `*.` wildcards and shared-hosting domains where anyone can publish content.
221221 
222If the agent keeps `bash`, set the `bash` tool's [permission policy](https://platform.claude.com/docs/en/managed-agents/permission-policies) as [Approve risky actions](https://platform.claude.com/docs/en/managed-agents/secure-deployment#approve-risky-actions) describes.
222If the agent keeps `bash`, set the `bash` tool’s [permission policy](https://platform.claude.com/docs/en/managed-agents/permission-policies) as [Approve risky actions](https://platform.claude.com/docs/en/managed-agents/secure-deployment#approve-risky-actions) describes.
223223 
224224<Note>
225225 After you tighten an environment, start new sessions and stop the ones that were already running. A session that is already running can keep the old limits until it ends. See [Set limits and a way to stop](https://platform.claude.com/docs/en/managed-agents/secure-deployment#set-limits-and-a-way-to-stop).
from line 229
229229 
230230## Keep credentials in vaults
231231 
232Store every secret in a vault. For each environment variable credential, set the injection location to request headers only and list only the hosts the secret is for. Code in the sandbox sees a placeholder instead of the secret. Managed Agents swaps in the real secret only in outgoing HTTPS requests to the hosts the credential allows. So the secret stays out of direct reach of the model, unless a service sends it back, such as an endpoint that echoes request headers. If the credential's `networking` (csharp, go: `Networking`) is `unrestricted`, Managed Agents swaps in the real secret in requests to any host the environment lets the sandbox reach. To use a vault, pass its ID in `vault_ids` (java: `vaultIds`; php: `vaultIDs`; csharp: `VaultIds`; go: `VaultIDs`) when you create the session or deployment.
232Store every secret in a vault. For each environment variable credential, set the injection location to request headers only and list only the hosts the secret is for. Code in the sandbox sees a placeholder instead of the secret. Managed Agents swaps in the real secret only in outgoing HTTPS requests to the hosts the credential allows. So the secret stays out of direct reach of the model, unless a service sends it back, such as an endpoint that echoes request headers. If the credential’s `networking` (csharp, go: `Networking`) is `unrestricted`, Managed Agents swaps in the real secret in requests to any host the environment lets the sandbox reach. To use a vault, pass its ID in `vault_ids` (java: `vaultIds`; php: `vaultIDs`; csharp: `VaultIds`; go: `VaultIDs`) when you create the session or deployment.
233233 
234234| Setting | Set it to | Why | What it does not do |
235235| -------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
236236| `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) | `{"header": true, "body": false}`, after you check that the service reads the key from a header | Request bodies are often built from content the agent reads, so a key in a body is more exposed. Name both fields: a create request that omits the object enables both locations, and an update changes only the fields you send | Code can still use the key on every host the credential allows. A service that expects the key in the body receives the placeholder and rejects the request |
237237| `networking` (csharp, go: `Networking`) on the credential | `limited`, with the exact hosts the key is for | Responses reach the sandbox unredacted, so avoid wildcards, shared-hosting domains, and hosts that echo request headers | It does not open the host. The environment must also allow it |
238| The key's permissions, at the service that issued the key | Only the permissions the agent needs | The agent can do anything the key allows | Not applicable |
239| A mounted repository's GitHub token | A [fine-grained token](https://platform.claude.com/docs/en/managed-agents/github#token-permissions) with the minimum permissions | Code in the sandbox can fetch from and push to the mounted repository with it for the whole session. Grant write access only if the agent must push | Not applicable |
238| The key’s permissions, at the service that issued the key | Only the permissions the agent needs | The agent can do anything the key allows | Not applicable |
239| A mounted repository’s GitHub token | A [fine-grained token](https://platform.claude.com/docs/en/managed-agents/github#token-permissions) with the minimum permissions | Code in the sandbox can fetch from and push to the mounted repository with it for the whole session. Grant write access only if the agent must push | Not applicable |
240240 
241241The support agent needs no vault credential, because your application holds the API key for your order API. If your agent does hold a vault credential, see [Add a credential](https://platform.claude.com/docs/en/managed-agents/vaults#add-a-credential) for the request in every language.
242242 
243Keep keys out of system prompts, agent definitions, and messages. Do not give the agent a Claude API key or Claude API access token. Even when one is in a vault, code in the sandbox can use it to call the Claude API directly. It can do anything that credential allows, such as starting or deleting sessions, or using web search and web fetch. The agent's tool settings, approvals, and budget do not apply to those calls. In a `limited` environment, code can make these calls only if `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) lets the sandbox reach `api.anthropic.com`.
243Keep keys out of system prompts, agent definitions, and messages. Do not give the agent a Claude API key or Claude API access token. Even when one is in a vault, code in the sandbox can use it to call the Claude API directly. It can do anything that credential allows, such as starting or deleting sessions, or using web search and web fetch. The agent’s tool settings, approvals, and budget do not apply to those calls. In a `limited` environment, code can make these calls only if `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) lets the sandbox reach `api.anthropic.com`.
244244 
245245Fetch third-party tokens yourself and store them in the vault. A token that code in the sandbox fetches with a stored secret comes back unredacted.
246246 
from line 250
250250 
251251## Restrict web search and web fetch
252252 
253Set `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) on `web_fetch` to the sites the agent needs. Any URL the agent fetches can carry data to the site it points to, so this list is a security control. On `web_search`, set `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) to the sites you want results from, so that results come only from sites you trust to be accurate. The list does not stop the search query from reaching the search provider. Search results include text from pages, so the list also limits which sites' text reaches the agent. Set `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) on both tools for every type of environment.
253Set `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) on `web_fetch` to the sites the agent needs. Any URL the agent fetches can carry data to the site it points to, so this list is a security control. On `web_search`, set `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) to the sites you want results from, so that results come only from sites you trust to be accurate. The list does not stop the search query from reaching the search provider. Search results include text from pages, so the list also limits which sites’ text reaches the agent. Set `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) on both tools for every type of environment.
254254 
255255A `blocked_domains` (java, php: `blockedDomains`; csharp, go: `BlockedDomains`) list blocks the hosts you list and their subdomains, and no other host. The same content can still reach the agent from web archives, caches, mirrors, or related domains you did not list. Do not rely on `blocked_domains` (java, php: `blockedDomains`; csharp, go: `BlockedDomains`) for security. Use `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) and name the hosts you trust.
256256 
257An administrator can turn off web search or web fetch, or restrict their domains, on the [**Capabilities**](https://platform.claude.com/settings/capabilities) page of the Claude Console. These settings also apply in a session. With a tool turned off, its calls return an error result to the agent, and the session continues. With domain restrictions set, a search result or a fetched URL must pass both the organization's restrictions and the tool's own domain lists. See [Restrict web search and web fetch domains](https://platform.claude.com/docs/en/managed-agents/tools-web-restrictions).
257An administrator can turn off web search or web fetch, or restrict their domains, on the [**Capabilities**](https://platform.claude.com/settings/capabilities) page of the Claude Console. These settings also apply in a session. With a tool turned off, its calls return an error result to the agent, and the session continues. With domain restrictions set, a search result or a fetched URL must pass both the organization’s restrictions and the tool’s own domain lists. See [Restrict web search and web fetch domains](https://platform.claude.com/docs/en/managed-agents/tools-web-restrictions).
258258 
259259In a `limited` environment, the `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) list from [Limit the network](https://platform.claude.com/docs/en/managed-agents/secure-deployment#limit-the-network) also limits the web tools. An `unrestricted` environment or a self-hosted sandbox does not limit the web tools.
260260 
from line 283
283283| The description of a `user.define_outcome` event | Yes |
284284| The address of a web search result | Yes |
285285| The text of a page that `web_fetch` returned earlier (not a PDF), where the full URL is shown | Yes |
286| The text of a custom tool's result, when Claude called the tool directly | Yes, unless the result is marked `is_error: true` |
286| The text of a custom tool’s result, when Claude called the tool directly | Yes, unless the result is marked `is_error: true` |
287287| The system prompt | No |
288| The agent's configuration, including `allowed_domains` entries | No |
289| Claude's own output | No |
288| The agent’s configuration, including `allowed_domains` entries | No |
289| Claude’s own output | No |
290290| Output of `bash` and the other sandbox tools | No |
291291| An MCP tool result | No |
292292| A file attached to a user message | No |
293293 
294In a multiagent session, `web_fetch` opens a URL from another agent only if it reached that agent through a source marked Yes. A custom tool's result from a direct call counts as a source marked Yes. This holds even if Claude wrote its text, for example when the tool repeats its input. A URL can count even when it is written without `https://`, such as `example.com/docs`. The `web_fetch` tool cannot always open a link that shows words instead of its URL, such as "Contact support." If the agent must fetch a URL that has not appeared in the session, send it in a user message.
294In a multiagent session, `web_fetch` opens a URL from another agent only if it reached that agent through a source marked Yes. A custom tool’s result from a direct call counts as a source marked Yes. This holds even if Claude wrote its text, for example when the tool repeats its input. A URL can count even when it is written without `https://`, such as `example.com/docs`. The `web_fetch` tool cannot always open a link that shows words instead of its URL, such as “Contact support.” If the agent must fetch a URL that has not appeared in the session, send it in a user message.
295295 
296296This rule reduces the chance that injected text builds a URL that carries private data. End-user text, search results, fetched pages, and custom tool results can still add URLs, so keep `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) set. The Messages API applies a similar rule with a different list of sources. See [URL validation](https://platform.claude.com/docs/en/agents-and-tools/tool-use/web-fetch-tool#url-validation).
297297 
from line 307
307307| `bash`, `write`, `edit` | `auto`. Use `always_ask` on a tool if you cannot undo its changes outside the sandbox. Use `always_ask` on `bash` if you relay end-user text | The agent toolset default is `always_allow`, which runs every call without approval |
308308| `web_fetch` | `auto` | A URL the agent fetches can carry data to the site it points to |
309309| `web_search` | `always_ask` if the agent handles data you would not want sent in a search query. Otherwise `always_allow` | `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) limits which sites results come from, not what the query contains |
310| MCP tools that only read data | `auto`, set for each tool in the toolset's `configs` (csharp, go: `Configs`) | The toolset default stays `always_ask`, so a tool the MCP server adds later still waits for approval |
310| MCP tools that only read data | `auto`, set for each tool in the toolset’s `configs` (csharp, go: `Configs`) | The toolset default stays `always_ask`, so a tool the MCP server adds later still waits for approval |
311311| MCP tools that change data | `always_ask` | This is the MCP toolset default. Keep it |
312312| Custom tools | Your code determines whether each call runs | Permission policies do not apply |
313313 
314314The toolset in [Give the agent the smallest tool set](https://platform.claude.com/docs/en/managed-agents/secure-deployment#give-the-agent-the-smallest-tool-set) applies these policies.
315315 
316The [`auto` policy](https://platform.claude.com/docs/en/managed-agents/permission-policies#let-the-server-evaluate-each-call-with-auto) lets the server run a call, deny it, or pause for approval. A person cannot approve every call in a long run, so the server checks each one instead. Pair `auto` with limited networking, a key with narrow permissions, a budget, and an alert on idle sessions. `auto` is not a human checkpoint, so if a person must review a tool's calls before they run, configure `always_ask` on that tool.
316The [`auto` policy](https://platform.claude.com/docs/en/managed-agents/permission-policies#let-the-server-evaluate-each-call-with-auto) lets the server run a call, deny it, or pause for approval. A person cannot approve every call in a long run, so the server checks each one instead. Pair `auto` with limited networking, a key with narrow permissions, a budget, and an alert on idle sessions. `auto` is not a human checkpoint, so if a person must review a tool’s calls before they run, configure `always_ask` on that tool.
317317 
318318`auto` treats text in `user.message` events and the description in a `user.define_outcome` event as your instruction, including end-user text you relay.
319319 
from line 330
330330| `bash` | Runs any command, including requests to allowed hosts |
331331| `write`, `edit` | Change files in the sandbox |
332332| `read`, `glob`, `grep` | Read files in the sandbox |
333| `web_fetch`, `web_search` | Return pages and search results from the web, through Anthropic's servers |
333| `web_fetch`, `web_search` | Return pages and search results from the web, through Anthropic’s servers |
334334 
335335The support agent needs three built-in tools: `read` and `write` for its draft, and `web_fetch` for the help center. It looks up orders through a [custom tool](https://platform.claude.com/docs/en/managed-agents/tools#custom-tools), `lookup_order`, that your application runs. Your application holds the API key for your order API, so the agent needs neither `bash` nor a credential.
336336 
337The following sample limits `web_fetch` to `help.example.com` with `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`). It sets `auto` on `write` and `web_fetch`, as [Approve risky actions](https://platform.claude.com/docs/en/managed-agents/secure-deployment#approve-risky-actions) recommends. If a customer's ticket leads the agent to use these tools, the agent can only change files in the sandbox or open help center pages. That is why neither tool needs `always_ask`. The sample also sets `always_ask` in `default_config` (java, php: `defaultConfig`; csharp, go: `DefaultConfig`), so a tool you enable later without its own policy uses `always_ask`:
337The following sample limits `web_fetch` to `help.example.com` with `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`). It sets `auto` on `write` and `web_fetch`, as [Approve risky actions](https://platform.claude.com/docs/en/managed-agents/secure-deployment#approve-risky-actions) recommends. If a customer’s ticket leads the agent to use these tools, the agent can only change files in the sandbox or open help center pages. That is why neither tool needs `always_ask`. The sample also sets `always_ask` in `default_config` (java, php: `defaultConfig`; csharp, go: `DefaultConfig`), so a tool you enable later without its own policy uses `always_ask`:
338338 
339339<CodeGroup defaultLanguage="CLI">
340340 ```bash cURL
from line 763
763763 
764764* A deployment pins an agent version, so point each deployment at the new one.
765765* An agent that lists this one in the [`predefined_agents` (java, php: `predefinedAgents`; csharp, go: `PredefinedAgents`) list of `subagents` (csharp, go: `Subagents`)](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#list-the-subagents) or of `workflows` (csharp, go: `Workflows`) keeps the version it pinned. Update that agent too.
766* To tighten a session that already exists, [update that session's tools](https://platform.claude.com/docs/en/managed-agents/session-operations#updating-the-agent-configuration). The session must be `idle`, and the update replaces the whole `tools` (csharp, go: `Tools`) array. In a multiagent session, new `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) and `blocked_domains` (java, php: `blockedDomains`; csharp, go: `BlockedDomains`) lists on the web tools of the agent the session runs also apply to every other agent. They apply from each agent's next turn. Those agents' enabled tools and permission policies do not change. To change those, update each agent, then start a new session.
766* To tighten a session that already exists, [update that session’s tools](https://platform.claude.com/docs/en/managed-agents/session-operations#updating-the-agent-configuration). The session must be `idle`, and the update replaces the whole `tools` (csharp, go: `Tools`) array. In a multiagent session, new `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) and `blocked_domains` (java, php: `blockedDomains`; csharp, go: `BlockedDomains`) lists on the web tools of the agent the session runs also apply to every other agent. They apply from each agent’s next turn. Those agents’ enabled tools and permission policies do not change. To change those, update each agent, then start a new session.
767767 
768768Limit MCP servers and custom tools to what the agent needs, too:
769769 
770770* **MCP servers:** An MCP toolset enables every tool the server exposes by default. Set `default_config.enabled` (java, php: `defaultConfig.enabled`; csharp, go: `DefaultConfig.Enabled`) to `false` and enable named tools, so tools a server adds later stay off. Remove servers the agent does not use. See [MCP connector](https://platform.claude.com/docs/en/managed-agents/mcp-connector#configure-which-mcp-tools-are-available).
771* **Custom tools:** Your application runs them, and permission policies do not apply. Validate each call's input in your application and limit what the tool can touch.
771* **Custom tools:** Your application runs them, and permission policies do not apply. Validate each call’s input in your application and limit what the tool can touch.
772772 
773773## Keep untrusted input away from powerful tools
774774 
from line 777
777777* **Untrusted input:** Webpages, search results, support tickets, emails, repository files, uploads, MCP server results, and end-user messages that you relay
778778* **Powerful tools:** `bash`, `write`, `edit`, `web_fetch`, `web_search`, MCP tools and custom tools that write or send data, and any tool that uses a credential
779779 
780Text in untrusted input can tell the agent to use a powerful tool it holds. The support agent reads tickets, so it reaches your order API only through the custom tool `lookup_order`. Your application checks that the order belongs to the ticket's sender.
780Text in untrusted input can tell the agent to use a powerful tool it holds. The support agent reads tickets, so it reaches your order API only through the custom tool `lookup_order`. Your application checks that the order belongs to the ticket’s sender.
781781 
782782| Input the agent reads | Power it also has | Do this |
783783| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
from line 784
784784| Tickets, emails, or uploads | `bash` with a credential | Replace `bash` with a custom tool that does one thing. If the agent must keep `bash`, approve each call with `always_ask` |
785785| Webpages or search results | Writing files or changing records | Turn off the web tools, or limit them to sites you operate or trust |
786786| MCP results or repository files | MCP tools that write | Keep the MCP toolset on `always_ask`, and enable only the tools the agent needs |
787| A mounted GitHub repository | Any tool | Mount only repositories you trust. An agent with `read` loads skills from the repository's `.claude/skills` directory as agent instructions, with no review step. See [Load skills from a GitHub repository](https://platform.claude.com/docs/en/managed-agents/skills#load-skills-from-a-github-repository) |
787| A mounted GitHub repository | Any tool | Mount only repositories you trust. An agent with `read` loads skills from the repository’s `.claude/skills` directory as agent instructions, with no review step. See [Load skills from a GitHub repository](https://platform.claude.com/docs/en/managed-agents/skills#load-skills-from-a-github-repository) |
788788| Any untrusted input | Writing to a [memory store](https://platform.claude.com/docs/en/managed-agents/memory#attach-a-memory-store-to-a-session) | Attach the store as `read_only` unless the agent must write. The default is `read_write`, and later sessions read saved text as trusted memory |
789789 
790In a cloud environment, reading a file with `read` can also load `CLAUDE.md` and `AGENTS.md` files as instructions. They load from the file's directory and its parent directories, up to the sandbox's working directory. Files they reference with `@` and a path, such as `@docs/setup.md`, also load, up to five references deep. A reference can point anywhere in the sandbox, for example `@/etc/hosts`. No setting turns this off except disabling `read`, so treat a repository, package, or archive that someone outside your team can write as untrusted input.
790In a cloud environment, reading a file with `read` can also load `CLAUDE.md` and `AGENTS.md` files as instructions. They load from the file’s directory and its parent directories, up to the sandbox’s working directory. Files they reference with `@` and a path, such as `@docs/setup.md`, also load, up to five references deep. A reference can point anywhere in the sandbox, for example `@/etc/hosts`. No setting turns this off except disabling `read`, so treat a repository, package, or archive that someone outside your team can write as untrusted input.
791791 
792792When an agent must read untrusted input and also act, this guide recommends one of three designs:
793793 
from line 803
803803| Fetcher | Webpages and search results | `web_fetch` and `web_search` only, each with `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) | Short results, in a format you ask for in its system prompt |
804804| Writer | The task from the lead | The tools that write files, run commands, or change records, on `auto` or `always_ask`. No web tools | Its result |
805805 
806The fetcher's results are built from untrusted pages, and the lead can pass their text on to the writer. Keep `auto` or `always_ask` on the writer's tools. The fetcher can still send some of what it reads to the sites on its `web_fetch` list, and to the search provider in its queries.
806The fetcher’s results are built from untrusted pages, and the lead can pass their text on to the writer. Keep `auto` or `always_ask` on the writer’s tools. The fetcher can still send some of what it reads to the sites on its `web_fetch` list, and to the search provider in its queries.
807807 
808808Agents in one multiagent session [share the sandbox](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#how-it-works), its files, and the vault credentials, so this split separates only their tools and conversations. For a stronger split, use two sessions with separate environments and vaults. Have your application pass only fixed fields, such as an order ID, between the two sessions.
809809 
from line 831
831831 
832832An interrupt does not undo what the agent already did or sent. Archiving an agent does not stop its running sessions.
833833 
834A budget's `max_list_cost.amount` (java, php: `maxListCost.amount`; csharp, go: `MaxListCost.Amount`) is a whole number of US cents written as a string, so `"125"` means $1.25 USD. See [Set a budget at session creation](https://platform.claude.com/docs/en/managed-agents/budgets#set-a-budget-at-session-creation).
834A budget’s `max_list_cost.amount` (java, php: `maxListCost.amount`; csharp, go: `MaxListCost.Amount`) is a whole number of US cents written as a string, so `"125"` means $1.25 USD. See [Set a budget at session creation](https://platform.claude.com/docs/en/managed-agents/budgets#set-a-budget-at-session-creation).
835835 
836You cannot add a budget to a session created without one. To change or remove a cap, see [Resume a session at its budget](https://platform.claude.com/docs/en/managed-agents/budgets#resume-a-session-at-its-budget). After you remove a session's cap, you cannot set a new one.
836You cannot add a budget to a session created without one. To change or remove a cap, see [Resume a session at its budget](https://platform.claude.com/docs/en/managed-agents/budgets#resume-a-session-at-its-budget). After you remove a session’s cap, you cannot set a new one.
837837 
838838A budget caps spending, but it does not limit what the agent does before the cap. To keep workloads with different trust levels apart, use separate [workspaces](https://platform.claude.com/docs/en/manage-claude/workspaces). Limit each workload to one workspace: where you can, a [Workload Identity Federation](https://platform.claude.com/docs/en/manage-claude/workload-identity-federation) rule enabled only in it, otherwise an API key scoped to it. Access to several workspaces lets the workload act in any of them.
839839 

managed-agents/secure-deployment-monitoring Changed · +6 / -6 lines

from line 10
1010 betaHeader: managed-agents-2026-04-01
1111---
1212 
13Optionally review each session's events with an offline job. Watch webhooks for sessions that need attention, and delete sessions you no longer need. To limit what an agent can do before it runs, see [Secure your Managed Agents deployment](https://platform.claude.com/docs/en/managed-agents/secure-deployment).
13Optionally review each session’s events with an offline job. Watch webhooks for sessions that need attention, and delete sessions you no longer need. To limit what an agent can do before it runs, see [Secure your Managed Agents deployment](https://platform.claude.com/docs/en/managed-agents/secure-deployment).
1414 
1515## Optionally have an offline reviewer read every transcript
1616 
17An offline reviewer is a job you run, separate from the sessions it reviews, that reads each session's events after they are written. Long sessions have too many events for a person to read, so the job has Claude read them. The review flags behavior beyond what the agent was granted. For a review prompt, setup steps, and working code, see the [security review recipe](https://platform.claude.com/cookbook/managed-agents-cma-agent-security-review) in the Claude Cookbook.
17An offline reviewer is a job you run, separate from the sessions it reviews, that reads each session’s events after they are written. Long sessions have too many events for a person to read, so the job has Claude read them. The review flags behavior beyond what the agent was granted. For a review prompt, setup steps, and working code, see the [security review recipe](https://platform.claude.com/cookbook/managed-agents-cma-agent-security-review) in the Claude Cookbook.
1818 
1919## Monitor sessions and review retention
2020 
from line 26
2626| Sessions that reach a budget or terminate | The `session.budget_reached` and `session.status_terminated` webhooks |
2727| Scheduled runs that fail to start a session | The `deployment_run.failed` and `deployment.paused` webhooks |
2828| MCP OAuth credentials that cannot refresh | The `vault_credential.refresh_failed` webhook |
29| Tool calls the server denied or paused | `evaluated_permission` on `agent.tool_use` and `agent.mcp_tool_use` events. In a multiagent session, also list each thread's events |
29| Tool calls the server denied or paused | `evaluated_permission` on `agent.tool_use` and `agent.mcp_tool_use` events. In a multiagent session, also list each thread’s events |
3030| What an agent did in a session | The Claude Console session viewer |
31| Behavior beyond what the agent was granted | An optional offline review job you run that reads each session's events. See [Optionally have an offline reviewer read every transcript](https://platform.claude.com/docs/en/managed-agents/secure-deployment-monitoring#optionally-have-an-offline-reviewer-read-every-transcript) |
31| Behavior beyond what the agent was granted | An optional offline review job you run that reads each session’s events. See [Optionally have an offline reviewer read every transcript](https://platform.claude.com/docs/en/managed-agents/secure-deployment-monitoring#optionally-have-an-offline-reviewer-read-every-transcript) |
3232 
33To see why a session went idle, list its events with `types` set to `session.status_idle`, `order` set to `desc`, and `limit` set to `1`. The event is named `session.status_idle`, and the webhook is named `session.status_idled`. If `stop_reason.type` is `requires_action`, the session is waiting on you, and `stop_reason.event_ids` lists the events it is waiting on. To answer them, see [Answer tool calls that pause the session](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#answer-tool-calls-that-pause-the-session). In a self-hosted sandbox, an `agent.tool_use` event can be waiting for your sandbox to return the tool's result. With workflow runs open, a tool call can wait for your answer while the session stays `running`. Answer each call when its event arrives. See [While a run is open](https://platform.claude.com/docs/en/managed-agents/workflow-runs#while-a-run-is-open).
33To see why a session went idle, list its events with `types` set to `session.status_idle`, `order` set to `desc`, and `limit` set to `1`. The event is named `session.status_idle`, and the webhook is named `session.status_idled`. If `stop_reason.type` is `requires_action`, the session is waiting on you, and `stop_reason.event_ids` lists the events it is waiting on. To answer them, see [Answer tool calls that pause the session](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#answer-tool-calls-that-pause-the-session). In a self-hosted sandbox, an `agent.tool_use` event can be waiting for your sandbox to return the tool’s result. With workflow runs open, a tool call can wait for your answer while the session stays `running`. Answer each call when its event arrives. See [While a run is open](https://platform.claude.com/docs/en/managed-agents/workflow-runs#while-a-run-is-open).
3434 
3535A webhook delivery can be missed, so also list your sessions on a schedule and check the idle ones.
3636 
from line 38
3838 
3939This list shows what Managed Agents keeps, and for how long:
4040 
41* **Session history:** Kept until you delete the session. Archiving a session keeps its history. To keep a session's events, copy them to your own logs with the events API before you delete it. A `running` session cannot be deleted. See [Deleting a session](https://platform.claude.com/docs/en/managed-agents/session-operations#deleting-a-session).
41* **Session history:** Kept until you delete the session. Archiving a session keeps its history. To keep a session’s events, copy them to your own logs with the events API before you delete it. A `running` session cannot be deleted. See [Deleting a session](https://platform.claude.com/docs/en/managed-agents/session-operations#deleting-a-session).
4242* **Sandbox state:** Kept for 30 days after the sandbox is created.
4343* **Files a session produces:** Deleted with the session. Download the files you want to keep first.
4444* **Files you uploaded, memory stores, and vaults:** Not deleted with the session. Delete them separately.

managed-agents/secure-deployment-risks Changed · +7 / -7 lines

from line 21
2121| What can go wrong | Example | Controls |
2222| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
2323| Untrusted input steers the agent | A ticket tells the agent to cancel every open order | [Smallest tool set](https://platform.claude.com/docs/en/managed-agents/secure-deployment#give-the-agent-the-smallest-tool-set), [untrusted input kept away from powerful tools](https://platform.claude.com/docs/en/managed-agents/secure-deployment#keep-untrusted-input-away-from-powerful-tools), [approvals for risky actions](https://platform.claude.com/docs/en/managed-agents/secure-deployment#approve-risky-actions) |
24| Code in the sandbox can use a credential | A script the agent was tricked into running sends the agent's key to an outside host, or uses it to read every customer's orders | [Credentials in vaults](https://platform.claude.com/docs/en/managed-agents/secure-deployment#keep-credentials-in-vaults), [limited networking](https://platform.claude.com/docs/en/managed-agents/secure-deployment#limit-the-network), [approvals for risky actions](https://platform.claude.com/docs/en/managed-agents/secure-deployment#approve-risky-actions) |
24| Code in the sandbox can use a credential | A script the agent was tricked into running sends the agent’s key to an outside host, or uses it to read every customer’s orders | [Credentials in vaults](https://platform.claude.com/docs/en/managed-agents/secure-deployment#keep-credentials-in-vaults), [limited networking](https://platform.claude.com/docs/en/managed-agents/secure-deployment#limit-the-network), [approvals for risky actions](https://platform.claude.com/docs/en/managed-agents/secure-deployment#approve-risky-actions) |
2525| An open network lets data out | A bash command posts a file to an outside host | [Limited networking](https://platform.claude.com/docs/en/managed-agents/secure-deployment#limit-the-network), the [`web_fetch` domain list](https://platform.claude.com/docs/en/managed-agents/secure-deployment#restrict-web-search-and-web-fetch) |
2626| Claude takes a step you did not expect | To get past an obstacle, it uses a tool or credential it can reach | The settings in [Secure your Managed Agents deployment](https://platform.claude.com/docs/en/managed-agents/secure-deployment). An [offline reviewer](https://platform.claude.com/docs/en/managed-agents/secure-deployment-monitoring#optionally-have-an-offline-reviewer-read-every-transcript) can flag the step afterward |
2727 
28These settings lower the risk but do not remove it, so do not put data in the sandbox that must never leave it. An agent can still put data it is allowed to read into its own reply or tool output. Limit a key's permissions at the service that issued it, because these settings do not limit them. The settings do not secure your custom tools, your MCP servers, or your self-hosted infrastructure.
28These settings lower the risk but do not remove it, so do not put data in the sandbox that must never leave it. An agent can still put data it is allowed to read into its own reply or tool output. Limit a key’s permissions at the service that issued it, because these settings do not limit them. The settings do not secure your custom tools, your MCP servers, or your self-hosted infrastructure.
2929 
3030## What the sandbox can and cannot do
3131 
from line 33
3333 
3434| Part | Where it runs | What limits it |
3535| ---------------------------- | -------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
36| Agent loop | Anthropic's servers | The tool set, permission policies, and budget that you set |
36| Agent loop | Anthropic’s servers | The tool set, permission policies, and budget that you set |
3737| `bash` and file tools | The sandbox. In a cloud environment, each session gets its own isolated Linux container | Environment networking, the tool set, and permission policies |
38| `web_search` and `web_fetch` | Anthropic's servers | The tool's own domain list, your organization's web search and web fetch settings in the Claude Console, and, in a `limited` cloud environment, the environment's allowed hosts. `web_fetch` also opens only URLs that have already appeared in the session |
39| Vault secret | Outside the sandbox. MCP credentials never enter it. For an environment variable credential, code sees a placeholder | For an MCP credential, the MCP server URL it is for. For an environment variable credential, the hosts the credential allows, its injection location, and the environment's allowed hosts |
40| Session history | Anthropic's servers, until you delete the session | The API keys for the workspace, the Developer and Admin roles in the Claude Console, and session deletion |
38| `web_search` and `web_fetch` | Anthropic’s servers | The tool’s own domain list, your organization’s web search and web fetch settings in the Claude Console, and, in a `limited` cloud environment, the environment’s allowed hosts. `web_fetch` also opens only URLs that have already appeared in the session |
39| Vault secret | Outside the sandbox. MCP credentials never enter it. For an environment variable credential, code sees a placeholder | For an MCP credential, the MCP server URL it is for. For an environment variable credential, the hosts the credential allows, its injection location, and the environment’s allowed hosts |
40| Session history | Anthropic’s servers, until you delete the session | The API keys for the workspace, the Developer and Admin roles in the Claude Console, and session deletion |
4141| Custom tools | Your application | Your code |
4242 
4343In a cloud environment, sessions do not share filesystem state. A memory store attached to more than one session is shared between them.
4444 
45These limits do not replace each other. For example, limiting the environment's hosts does not stop the agent from using a credential on a host you allowed.
45These limits do not replace each other. For example, limiting the environment’s hosts does not stop the agent from using a credential on a host you allowed.
4646 

managed-agents/self-hosted-sandboxes-custom-tools Changed · +18 / -18 lines

from line 22
2222 
2323<Steps>
2424 <Step title="Declare the tool on the agent">
25 Add a `custom` entry to the agent's `tools` whose `name` matches the tool your worker registers. See [Custom tools](https://platform.claude.com/docs/en/managed-agents/tools#custom-tools) for the full declaration shape.
25 Add a `custom` entry to the agent’s `tools` whose `name` matches the tool your worker registers. See [Custom tools](https://platform.claude.com/docs/en/managed-agents/tools#custom-tools) for the full declaration shape.
2626 
2727 ```json
2828 {
from line 41
4141 </Step>
4242 
4343 <Step title="Register the implementation with the worker">
44 Pass the tool through the worker's `tools` (go: `ToolsFunc`) factory (see [`EnvironmentWorker`](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-reference#environment-worker)), alongside the built-in toolset:
44 Pass the tool through the worker’s `tools` (go: `ToolsFunc`) factory (see [`EnvironmentWorker`](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-reference#environment-worker)), alongside the built-in toolset:
4545 
4646 <CodeGroup exclude="shell, csharp, java, php, ruby">
4747 ```python Python
from line 110
110110 ```
111111 
112112 <CodeGroupItem language="C#">
113 The C# SDK does not have `EnvironmentWorker`. To answer custom tool calls from your own code, send each result on the session's event stream, as in [Return a custom tool result](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#return-a-custom-tool-result).
113 The C# SDK does not have `EnvironmentWorker`. To answer custom tool calls from your own code, send each result on the session’s event stream, as in [Return a custom tool result](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#return-a-custom-tool-result).
114114 </CodeGroupItem>
115115 
116116 ```go Go
from line 175
175175 ```
176176 
177177 <CodeGroupItem language="Java">
178 The Java SDK does not have `EnvironmentWorker`. To answer custom tool calls from your own code, send each result on the session's event stream, as in [Return a custom tool result](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#return-a-custom-tool-result).
178 The Java SDK does not have `EnvironmentWorker`. To answer custom tool calls from your own code, send each result on the session’s event stream, as in [Return a custom tool result](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#return-a-custom-tool-result).
179179 </CodeGroupItem>
180180 
181181 <CodeGroupItem language="PHP">
182 The PHP SDK does not have `EnvironmentWorker`. To answer custom tool calls from your own code, send each result on the session's event stream, as in [Return a custom tool result](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#return-a-custom-tool-result).
182 The PHP SDK does not have `EnvironmentWorker`. To answer custom tool calls from your own code, send each result on the session’s event stream, as in [Return a custom tool result](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#return-a-custom-tool-result).
183183 </CodeGroupItem>
184184 
185185 <CodeGroupItem language="Ruby">
186 The Ruby SDK does not have `EnvironmentWorker`. To answer custom tool calls from your own code, send each result on the session's event stream, as in [Return a custom tool result](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#return-a-custom-tool-result).
186 The Ruby SDK does not have `EnvironmentWorker`. To answer custom tool calls from your own code, send each result on the session’s event stream, as in [Return a custom tool result](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#return-a-custom-tool-result).
187187 </CodeGroupItem>
188188 </CodeGroup>
189189 </Step>
from line 193
193193 
194194## Wrap an MCP server as custom tools
195195 
196The [MCP connector](https://platform.claude.com/docs/en/managed-agents/mcp-connector) connects to MCP servers from Anthropic's side. A server must therefore expose an HTTP endpoint that Anthropic can reach, directly or through an [MCP tunnel](https://platform.claude.com/docs/en/agents-and-tools/mcp-tunnels/overview).
196The [MCP connector](https://platform.claude.com/docs/en/managed-agents/mcp-connector) connects to MCP servers from Anthropic’s side. A server must therefore expose an HTTP endpoint that Anthropic can reach, directly or through an [MCP tunnel](https://platform.claude.com/docs/en/agents-and-tools/mcp-tunnels/overview).
197197 
198To use a server that only your network can reach, make the worker the MCP client instead and declare the server's tools as custom tools. The MCP server needs no inbound connectivity from outside your network. Anthropic receives the tool definitions you declare on the agent, each call's input, and the result your worker posts back.
198To use a server that only your network can reach, make the worker the MCP client instead and declare the server’s tools as custom tools. The MCP server needs no inbound connectivity from outside your network. Anthropic receives the tool definitions you declare on the agent, each call’s input, and the result your worker posts back.
199199 
200200At runtime the model calls a wrapped tool like any other custom tool:
201201 
2022021. The agent emits an `agent.custom_tool_use` event.
2032032. The worker, inside your sandbox, forwards the call over its open MCP session to the server on your network.
2043. The worker posts the server's response as the `user.custom_tool_result`.
2043. The worker posts the server’s response as the `user.custom_tool_result`.
205205 
206206### Install an MCP SDK
207207 
208The SDK's [Client-side MCP helpers](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector#client-side-mcp-helpers) convert the server's tools into the runnable tools the worker accepts. Install an MCP SDK alongside the Anthropic SDK: `pip install "anthropic[mcp]" "mcp>=1.24"` (typescript: `npm install @modelcontextprotocol/sdk`; go: `go get github.com/modelcontextprotocol/go-sdk`; csharp: `dotnet add package ModelContextProtocol`; java: `com.anthropic:anthropic-java-mcp`; php: `composer require mcp/sdk`; ruby: `bundle add mcp faraday event_stream_parser`).
208The SDK’s [Client-side MCP helpers](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector#client-side-mcp-helpers) convert the server’s tools into the runnable tools the worker accepts. Install an MCP SDK alongside the Anthropic SDK: `pip install "anthropic[mcp]" "mcp>=1.24"` (typescript: `npm install @modelcontextprotocol/sdk`; go: `go get github.com/modelcontextprotocol/go-sdk`; csharp: `dotnet add package ModelContextProtocol`; java: `com.anthropic:anthropic-java-mcp`; php: `composer require mcp/sdk`; ruby: `bundle add mcp faraday event_stream_parser`).
209209 
210210The examples connect without authentication. To send credentials, configure the `http_client` (typescript: `requestInit`; go: `HTTPClient`; csharp: `AdditionalHeaders`; java: `.customizeRequest()`; php, ruby: `headers`) you hand to the MCP transport.
211211 
from line 212
212212### Declare and serve the tools
213213 
214214<Steps>
215 <Step title="Declare the server's tools on the agent">
216 List the MCP server's tools and declare each one as a `custom` tool. The MCP `name`, `description`, and `inputSchema` map one to one onto the custom tool's fields. If the server paginates its tool list, declare every page; the worker must list the same pages.
215 <Step title="Declare the server’s tools on the agent">
216 List the MCP server’s tools and declare each one as a `custom` tool. The MCP `name`, `description`, and `inputSchema` map one to one onto the custom tool’s fields. If the server paginates its tool list, declare every page; the worker must list the same pages.
217217 
218218 <CodeGroup exclude="shell">
219219 ```python Python
from line 759
759759 
760760### Tools are declared, not discovered at runtime
761761 
762The worker lists the MCP server's tools once at startup and cannot add tools to a running session. When the server's tools change:
762The worker lists the MCP server’s tools once at startup and cannot add tools to a running session. When the server’s tools change:
763763 
7647641. Declare them again, on the agent or on an idle session through [Updating the agent configuration](https://platform.claude.com/docs/en/managed-agents/session-operations#updating-the-agent-configuration).
7657652. Restart the worker.
from line 766
766766 
767767### Declarations must fit the Managed Agents API
768768 
769The MCP helpers keep the server's names and descriptions, and most schemas pass through unchanged. Rename, trim, or inline where a declaration breaks one of these rules:
769The MCP helpers keep the server’s names and descriptions, and most schemas pass through unchanged. Rename, trim, or inline where a declaration breaks one of these rules:
770770 
771771| Field | Rule |
772772| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
from line 773
773773| `name` | Unique per agent. Letters, digits, underscores, and hyphens, 1–128 characters. Cannot match a built-in agent tool such as `bash` or `read`, or use the reserved `mcp__` prefix or `ant__` prefix. |
774774| `description` | Required and non-empty. |
775775| `input_schema` | Accepts the JSON Schema keywords MCP servers commonly emit, such as `additionalProperties` and `title`. Rejects reference keywords such as `$ref` anywhere, and top-level `oneOf`, `anyOf`, and `allOf`. Property names use letters, digits, underscores, dots, and hyphens, 1–64 characters. |
776| The agent's `tools` array | At most 256 entries. Each wrapped tool is one entry, and the built-in toolset is one more. |
776| The agent’s `tools` array | At most 256 entries. Each wrapped tool is one entry, and the built-in toolset is one more. |
777777 
778778Two cases need extra work:
779779 
780* **Two servers expose the same tool name:** Define the wrapper yourself under a prefixed name and have it call the server's original tool name.
780* **Two servers expose the same tool name:** Define the wrapper yourself under a prefixed name and have it call the server’s original tool name.
781781* **A generator such as Pydantic factors schemas into `$defs`:** Inline those schemas before you declare the tool.
782782 
783783### Tool failures surface as error tool results
from line 788
788788 
789789### Wrap only servers you operate or trust
790790 
791A wrapped tool's name, description, and results enter the model's context like any other tool's. They are untrusted input that can influence what the agent does with its other tools, including `bash` on the worker host. Declare only the tools you intend the agent to use.
791A wrapped tool’s name, description, and results enter the model’s context like any other tool’s. They are untrusted input that can influence what the agent does with its other tools, including `bash` on the worker host. Declare only the tools you intend the agent to use.
792792 
793793### Permission policies do not apply
794794 

managed-agents/self-hosted-sandboxes-memory Changed · +20 / -20 lines

from line 12
1212 
1313Sessions 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` (csharp, go: `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.
1414 
15The difference is who materializes the store. On a self-hosted environment your worker, rather than Anthropic's infrastructure, downloads each store into the sandbox and syncs the agent's changes back.
15The difference is who materializes the store. On a self-hosted environment your worker, rather than Anthropic’s infrastructure, downloads each store into the sandbox and syncs the agent’s changes back.
1616 
1717## Requirements
1818 
from line 19
1919* **A worker that mounts memory stores:** Use `ant` CLI 1.33.0 or later, or `EnvironmentWorker` from the Python, TypeScript, or Go SDK.
2020* **A POSIX filesystem:** 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. macOS volumes are case-insensitive by default, so such paths collide there.
2121* **A writable `/mnt/memory` directory:** See [Prepare the host](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-memory#prepare-the-host). On macOS, see [Prepare a macOS host](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-memory#prepare-a-macos-host).
22* **The work item's secret:** If your own code launches the worker, [forward the work item's secret](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-workers#forward-the-work-items-secret) to it.
22* **The work item’s secret:** If your own code launches the worker, [forward the work item’s secret](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-workers#forward-the-work-items-secret) to it.
2323 
2424<Note>
2525 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).
2626 
27 On [Claude Models on Google Cloud (Anthropic managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/anthropic-managed), memory stores aren't supported for sessions on self-hosted environments.
27 On [Claude Models on Google Cloud (Anthropic managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/anthropic-managed), memory stores aren’t supported for sessions on self-hosted environments.
2828</Note>
2929 
3030## Prepare the host
from line 37
3737sudo mkdir -p /mnt/memory && sudo chown "$USER" /mnt/memory
3838```
3939 
40Do not create the per-store directories yourself. The worker creates each store's `mount_path` (java, php: `mountPath`; csharp, go: `MountPath`) directory (for example, `/mnt/memory/user-preferences`) when a session starts and removes it when the session ends. If something already exists at that path, the worker refuses to start the session's work.
40Do not create the per-store directories yourself. The worker creates each store’s `mount_path` (java, php: `mountPath`; csharp, go: `MountPath`) directory (for example, `/mnt/memory/user-preferences`) when a session starts and removes it when the session ends. If something already exists at that path, the worker refuses to start the session’s work.
4141 
42In the [sandbox-per-session pattern](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-workers#run-one-sandbox-per-session), the sandbox image needs a writable `/mnt/memory`. You don't need to bind-mount the memory directories to the host, because the worker uploads their contents to the store before the sandbox exits.
42In the [sandbox-per-session pattern](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-workers#run-one-sandbox-per-session), the sandbox image needs a writable `/mnt/memory`. You don’t need to bind-mount the memory directories to the host, because the worker uploads their contents to the store before the sandbox exits.
4343 
4444### Prepare a macOS host
4545 
46On macOS, the root volume is read-only, so `mkdir` can't create `/mnt`. Instead, create `/System/Volumes/Data/mnt/memory` on the data volume, which is writable. Then add a line to `/etc/synthetic.conf`, so that macOS creates `/mnt` as a symbolic link to `/System/Volumes/Data/mnt`. These steps need administrator rights.
46On macOS, the root volume is read-only, so `mkdir` can’t create `/mnt`. Instead, create `/System/Volumes/Data/mnt/memory` on the data volume, which is writable. Then add a line to `/etc/synthetic.conf`, so that macOS creates `/mnt` as a symbolic link to `/System/Volumes/Data/mnt`. These steps need administrator rights.
4747 
48Without this setup, the worker can't create a store's directory, so it fails the work item. The session then stays idle with no error event. See [Memory stores fail to mount](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-operations#memory-stores-fail-to-mount).
48Without this setup, the worker can’t create a store’s directory, so it fails the work item. The session then stays idle with no error event. See [Memory stores fail to mount](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-operations#memory-stores-fail-to-mount).
4949 
5050<Steps>
5151 <Step title="Create the directory on the data volume">
52 Create the `memory` directory and make the worker's user its owner. `$USER` is your own username. If the worker runs as another user, replace `"$USER"` with that user's name.
52 Create the `memory` directory and make the worker’s user its owner. `$USER` is your own username. If the worker runs as another user, replace `"$USER"` with that user’s name.
5353 
5454 ```bash
5555 sudo mkdir -p /System/Volumes/Data/mnt/memory && sudo chown "$USER" /System/Volumes/Data/mnt/memory
from line 63
6363 
6464 * If a line reads `mnt^ISystem/Volumes/Data/mnt$`, this step is already done. Go to the next step.
6565 * If another line starts with `mnt`, stop. Something else on this Mac already defines `/mnt`.
66 * If the last line doesn't end with `$`, run `echo | sudo tee -a /etc/synthetic.conf` to end it.
67 * If it prints nothing or reports `No such file or directory`, continue. The `printf` command creates the file if it's missing.
66 * If the last line doesn’t end with `$`, run `echo | sudo tee -a /etc/synthetic.conf` to end it.
67 * If it prints nothing or reports `No such file or directory`, continue. The `printf` command creates the file if it’s missing.
6868 
6969 Then add the line, unless one of the first two cases applies. Run this command only once, because each run appends another line.
7070 
from line 90
9090 ls -ld /mnt /mnt/memory
9191 ```
9292 
93 The first line ends with `/mnt -> System/Volumes/Data/mnt`. The second line shows the worker's user as the owner of `/mnt/memory`. You can now start the worker.
93 The first line ends with `/mnt -> System/Volumes/Data/mnt`. The second line shows the worker’s user as the owner of `/mnt/memory`. You can now start the worker.
9494 </Step>
9595</Steps>
9696 
from line 104
104104 
105105When the worker claims a work item whose session has memory stores attached, it:
106106 
1071. **Downloads each store to its `mount_path` (java, php: `mountPath`; csharp, go: `MountPath`).** This is the same directory under `/mnt/memory/` that cloud sessions use, and the session's system prompt describes it to the agent. For example, a store named "User Preferences" lands at `/mnt/memory/user-preferences/`.
1071. **Downloads each store to its `mount_path` (java, php: `mountPath`; csharp, go: `MountPath`).** This is the same directory under `/mnt/memory/` that cloud sessions use, and the session’s system prompt describes it to the agent. For example, a store named “User Preferences” lands at `/mnt/memory/user-preferences/`.
1081082. **Opens those directories to the file tools.** The agent works on memories with the same file tools it uses in the working directory.
1091093. **Reconciles 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.
1101104. **Runs a final sync when the session ends.** It flushes any uploads still pending for up to 30 seconds, then removes the directories it created.
111111 
112The 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 Claude Console work as they do for cloud sessions. 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.
112The 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 Claude Console work as they do for cloud sessions. 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.
113113 
114Because each worker syncs on an interval, a change written in one session becomes visible to another running session only after both have synced. That is typically well under a minute at the default interval. Sessions on cloud sandboxes see each other's changes almost immediately.
114Because each worker syncs on an interval, a change written in one session becomes visible to another running session only after both have synced. That is typically well under a minute at the default interval. Sessions on cloud sandboxes see each other’s changes almost immediately.
115115 
116116Each 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.
117117 
from line 208
208208 
209209Changes made through `bash`, or through a custom tool or MCP server you serve from the sandbox, are not blocked locally. They are never synced to the store, and the next remote change to that memory overwrites them. If the local copy itself must stay unchanged during the session:
210210 
211* Disable the `bash` tool for that agent, and give it no custom tool that writes to the sandbox's filesystem.
211* Disable the `bash` tool for that agent, and give it no custom tool that writes to the sandbox’s filesystem.
212212* Do not mount the store path read-only. The worker itself must create the directory and write the downloaded memories into it.
213213 
214Conflicts resolve in favor of the store. Suppose the agent changes a memory file that also changed in the store since the session last synced it. At the next sync, the worker keeps the store's version, 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.
214Conflicts resolve in favor of the store. Suppose the agent changes a memory file that also changed in the store since the session last synced it. At the next sync, the worker keeps the store’s version, 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.
215215 
216216## Troubleshooting
217217 
218See [Memory stores fail to mount](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-operations#memory-stores-fail-to-mount) for the worker's log messages and their fixes.
218See [Memory stores fail to mount](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-operations#memory-stores-fail-to-mount) for the worker’s log messages and their fixes.
219219 

managed-agents/self-hosted-sandboxes-operations Changed · +16 / -16 lines

### The worker doesn’t connect ### The worker doesn't connect

from line 10
1010 betaHeader: managed-agents-2026-04-01
1111---
1212 
13The monitoring calls on this page run from your monitoring or operations tooling, authenticated with your Claude API key. The worker helpers handle the claim and keep-alive loop, so you don't call those endpoints directly.
13The monitoring calls on this page run from your monitoring or operations tooling, authenticated with your Claude API key. The worker helpers handle the claim and keep-alive loop, so you don’t call those endpoints directly.
1414 
1515<Warning>
1616 These endpoints accept either your organization API key or the environment key. Call them from outside the worker host with your organization API key. Setting `ANTHROPIC_API_KEY` on the worker host exposes an organization-scoped credential to agent tool calls.
from line 154
154154 
155155Use `POST /v1/environments/{environment_id}/work/{work_id}/stop` (python, typescript, ruby: `client.beta.environments.work.stop()`; go, csharp: `client.Beta.Environments.Work.Stop()`; java: `client.beta().environments().work().stop()`; php: `$client->beta->environments->work->stop()`; cli: `ant beta:environments:work stop`) to ask the worker handling a specific session to shut it down.
156156 
157By default the work item moves to `stopping`. The worker detects this on its next lease heartbeat, cancels the session's in-flight tool call, and confirms the shutdown. The work item then becomes `stopped`.
157By default the work item moves to `stopping`. The worker detects this on its next lease heartbeat, cancels the session’s in-flight tool call, and confirms the shutdown. The work item then becomes `stopped`.
158158 
159Pass `force: true` (python: `force=True`; cli: `--force`) to mark the work item `stopped` immediately instead of waiting for the worker's confirmation.
159Pass `force: true` (python: `force=True`; cli: `--force`) to mark the work item `stopped` immediately instead of waiting for the worker’s confirmation.
160160 
161Because these calls run from your operations tooling rather than the worker host, `ANTHROPIC_WORK_ID` isn't set automatically. Set it to the target work item's ID before running the following examples. To find a work item's ID, list the environment's work items through the [Environments Work endpoints](https://platform.claude.com/docs/en/api/beta/environments/work).
161Because these calls run from your operations tooling rather than the worker host, `ANTHROPIC_WORK_ID` isn’t set automatically. Set it to the target work item’s ID before running the following examples. To find a work item’s ID, list the environment’s work items through the [Environments Work endpoints](https://platform.claude.com/docs/en/api/beta/environments/work).
162162 
163163<CodeGroup>
164164 ```bash cURL
from line 309
309309 | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
310310 | `ant` CLI | Nothing. The CLI handles both signals itself: it cancels any in-flight tool call, posts its error result, and releases the work item. |
311311 | SDK worker that is its own process | `EnvironmentWorker` installs no signal handlers. Cancel the worker from a signal handler, as the standalone worker examples do. |
312 | SDK worker inside a webhook server | Cancel the worker from the server's own shutdown hook, as the webhook examples do. The worker must not take over the server's signals. |
312 | SDK worker inside a webhook server | Cancel the worker from the server’s own shutdown hook, as the webhook examples do. The worker must not take over the server’s signals. |
313313 
3142. **Stop the worker with SIGTERM, and allow at least 30 seconds before any hard kill.** The final upload can take that long. Docker sends SIGKILL 10 seconds after the stop signal by default. Raise that limit with `--stop-timeout` on `docker run`, or with your orchestrator's termination grace period.
3142. **Stop the worker with SIGTERM, and allow at least 30 seconds before any hard kill.** The final upload can take that long. Docker sends SIGKILL 10 seconds after the stop signal by default. Raise that limit with `--stop-timeout` on `docker run`, or with your orchestrator’s termination grace period.
315315 
316316If a worker is killed before its teardown runs, any memory edits that had not synced are lost. On a long-lived host, also remove the leftover store directory under `/mnt/memory/` before the next session that attaches that store. A sandbox that serves one session and is then discarded needs no cleanup.
317317 
318318## Troubleshooting
319319 
320### The worker doesn't connect
320### The worker doesn’t connect
321321 
322If `workers_polling` (java, php: `workersPolling`; csharp, go: `WorkersPolling`) stays at 0, the worker isn't reaching the queue. Confirm that `ANTHROPIC_ENVIRONMENT_KEY` and `ANTHROPIC_ENVIRONMENT_ID` are set on the worker host.
322If `workers_polling` (java, php: `workersPolling`; csharp, go: `WorkersPolling`) stays at 0, the worker isn’t reaching the queue. Confirm that `ANTHROPIC_ENVIRONMENT_KEY` and `ANTHROPIC_ENVIRONMENT_ID` are set on the worker host.
323323 
324324### A session stays queued
325325 
from line 333
333333 
334334| Symptom | Cause | Fix |
335335| --------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
336| 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` (csharp, go: `Secret`) did not reach the worker. Either your code did not forward it, or memory stores on self-hosted sandboxes are not enabled for your organization. | [Forward the work item's secret](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-workers#forward-the-work-items-secret). If the worker polls and runs sessions in one process and still logs this, contact support. |
336| 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` (csharp, go: `Secret`) did not reach the worker. Either your code did not forward it, or memory stores on self-hosted sandboxes are not enabled for your organization. | [Forward the work item’s secret](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-workers#forward-the-work-items-secret). If the worker polls and runs sessions in one process and still logs this, contact support. |
337337| 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. |
338338| 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-memory#prepare-the-host). On macOS, follow [Prepare a macOS host](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-memory#prepare-a-macos-host) instead. |
339| 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#interrupt-the-agent) event. The session's work is queued again, and the next worker that claims it retries the mount. |
339| 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#interrupt-the-agent) event. The session’s work is queued again, and the next worker that claims it retries the mount. |
340340 
341341### A custom tool call never returns
342342 
from line 348
348348 
349349| SDK | Backstop | Fires after |
350350| ---------- | -------------------------------------------------------------- | ----------------- |
351| Python | The worker's own tool call limit | About 2.5 minutes |
352| TypeScript | The MCP SDK's default request timeout | About a minute |
351| Python | The worker’s own tool call limit | About 2.5 minutes |
352| TypeScript | The MCP SDK’s default request timeout | About a minute |
353353| Go | The worker cancels a tool call that outlives its default limit | 120 seconds |
354354 

managed-agents/self-hosted-sandboxes-reference Changed · +17 / -17 lines

from line 16
1616 
1717| Command | Description |
1818| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
19| `ant beta:worker poll` | Claims work items from the environment's queue and runs each session in process. With `--on-work`, calls your script for each work item instead. |
19| `ant beta:worker poll` | Claims work items from the environment’s queue and runs each session in process. With `--on-work`, calls your script for each work item instead. |
2020| `ant beta:worker run` | Handles one claimed session and exits. Use it as the entrypoint of a per-session sandbox. |
2121 
2222| Flag | Description |
from line 36
3636| `ANTHROPIC_ENVIRONMENT_KEY` | Authenticates the worker to its queue. | You, on the worker host. The poller passes it to the `--on-work` script. |
3737| `ANTHROPIC_SESSION_ID` | The session that a claimed work item represents. | The poller, for the `--on-work` script. |
3838| `ANTHROPIC_WORK_ID` | The claimed work item. | The poller, for the `--on-work` script. |
39| `ANTHROPIC_WORK_SECRET` | The work item's per-session secret. | You. The poller does not set it. See [Forward the work item's secret](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-workers#forward-the-work-items-secret). |
39| `ANTHROPIC_WORK_SECRET` | The work item’s per-session secret. | You. The poller does not set it. See [Forward the work item’s secret](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-workers#forward-the-work-items-secret). |
4040| `ANTHROPIC_BASE_URL` | Overrides the default API endpoint. Optional. | You, on the worker host. |
4141| `ANTHROPIC_WEBHOOK_SIGNING_KEY` | Verifies incoming webhook payloads. | You, on a webhook handler host. |
4242 
from line 44
4444 
4545| Worker | Requirement |
4646| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
47| All workers | A Linux or macOS host with `/bin/bash` at that exact path. The worker's bash tool invokes it directly, without consulting `PATH`. On macOS, that is the system Bash 3.2. |
47| All workers | A Linux or macOS host with `/bin/bash` at that exact path. The worker’s bash tool invokes it directly, without consulting `PATH`. On macOS, that is the system Bash 3.2. |
4848| TypeScript SDK | `unzip` and `tar` on the `PATH`, and Node.js 22 or later. |
4949| Python and Go SDKs | No additional binaries. These SDKs use their standard libraries for archive extraction. |
5050 
5151[Memory stores](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-memory#requirements) add their own requirements.
5252 
53On macOS, the root volume is read-only, so `mkdir` can't create `/workspace`. Set the worker's working directory to one that you can write to, such as a `workspace` directory in your home directory. To use memory stores on macOS, first [prepare the macOS host](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-memory#prepare-a-macos-host).
53On macOS, the root volume is read-only, so `mkdir` can’t create `/workspace`. Set the worker’s working directory to one that you can write to, such as a `workspace` directory in your home directory. To use memory stores on macOS, first [prepare the macOS host](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-memory#prepare-a-macos-host).
5454 
5555## Sandbox filesystem
5656 
5757| Path | Contents |
5858| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
59| `/workspace` | The system default working directory for tool execution and skill download. If you use a different working directory, update your agent's system prompt so Claude can locate the skill files. |
60| `<workdir>/skills/<name>/` | The agent's downloaded skills. |
61| `/mnt/memory/<store>/` | One directory per attached memory store, at the store's `mount_path` (java, php: `mountPath`; csharp, go: `MountPath`) (for example, `/mnt/memory/user-preferences/`). The worker creates these directories when it claims the session and removes them when the session ends. |
59| `/workspace` | The system default working directory for tool execution and skill download. If you use a different working directory, update your agent’s system prompt so Claude can locate the skill files. |
60| `<workdir>/skills/<name>/` | The agent’s downloaded skills. |
61| `/mnt/memory/<store>/` | One directory per attached memory store, at the store’s `mount_path` (java, php: `mountPath`; csharp, go: `MountPath`) (for example, `/mnt/memory/user-preferences/`). The worker creates these directories when it claims the session and removes them when the session ends. |
6262 
63On self-hosted environments the session's system prompt omits the `/mnt/session/outputs` instruction used on Anthropic-managed sandboxes. Final deliverables land wherever the agent writes them in your sandbox filesystem, typically under the working directory.
63On self-hosted environments the session’s system prompt omits the `/mnt/session/outputs` instruction used on Anthropic-managed sandboxes. Final deliverables land wherever the agent writes them in your sandbox filesystem, typically under the working directory.
6464 
6565Skills can include executables that the agent may run directly. The CLI and SDK workers preserve the executable permissions recorded in the skill bundle when they extract it. If you implement skills download manually, you are responsible for setting executable permissions.
6666 
from line 72
7272| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
7373| [`EnvironmentWorker`](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-reference#environment-worker) | Handles polling, setup, and execution end to end. | Most cases. |
7474| [`work.poller()` (go: `environments.NewWorkPoller()`)](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-reference#work-poller) | Polls the work queue and gives you each claimed session. | You determine what happens for each session, for example launching a sandbox rather than running tools in-process. |
75| [`client.beta.sessions.events.tool_runner()` (typescript: `client.beta.sessions.events.toolRunner()`; go: `client.Beta.Sessions.Events.NewToolRunner()`)](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-reference#session-tool-runner) | Runs tool calls for a single session, given the session ID and a tool list. | You've already claimed the work and only need the execution layer. |
75| [`client.beta.sessions.events.tool_runner()` (typescript: `client.beta.sessions.events.toolRunner()`; go: `client.Beta.Sessions.Events.NewToolRunner()`)](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-reference#session-tool-runner) | Runs tool calls for a single session, given the session ID and a tool list. | You’ve already claimed the work and only need the execution layer. |
7676 
7777### EnvironmentWorker
7878 
from line 83
8383 
8484| Option | Description |
8585| -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
86| `tools` (go: `ToolsFunc`) | A factory that receives the session's `AgentToolContext` and returns the tool list. Defaults to the standard agent toolset. |
86| `tools` (go: `ToolsFunc`) | A factory that receives the session’s `AgentToolContext` and returns the tool list. Defaults to the standard agent toolset. |
8787| `memory_sync_interval` (typescript: `memorySyncIntervalMs`; go: `MemorySyncInterval`) | How often attached memory stores reconcile with the server while the session runs. See [Sync interval](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-memory#sync-interval). |
8888| `memory_sync_deletions` (typescript: `memorySyncDeletions`; go: `MemorySyncDeletions`) | Whether files the agent deletes locally are also deleted from the store. See [Deletions](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-memory#deletions). |
8989 
from line 104
104104 ```
105105 
106106 <CodeGroupItem language="C#">
107 The C# SDK does not have `EnvironmentWorker`. To answer custom tool calls from your own code, send each result on the session's event stream, as in [Return a custom tool result](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#return-a-custom-tool-result).
107 The C# SDK does not have `EnvironmentWorker`. To answer custom tool calls from your own code, send each result on the session’s event stream, as in [Return a custom tool result](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#return-a-custom-tool-result).
108108 </CodeGroupItem>
109109 
110110 ```go Go
from line 118
118118 ```
119119 
120120 <CodeGroupItem language="Java">
121 The Java SDK does not have `EnvironmentWorker`. To answer custom tool calls from your own code, send each result on the session's event stream, as in [Return a custom tool result](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#return-a-custom-tool-result).
121 The Java SDK does not have `EnvironmentWorker`. To answer custom tool calls from your own code, send each result on the session’s event stream, as in [Return a custom tool result](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#return-a-custom-tool-result).
122122 </CodeGroupItem>
123123 
124124 <CodeGroupItem language="PHP">
125 The PHP SDK does not have `EnvironmentWorker`. To answer custom tool calls from your own code, send each result on the session's event stream, as in [Return a custom tool result](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#return-a-custom-tool-result).
125 The PHP SDK does not have `EnvironmentWorker`. To answer custom tool calls from your own code, send each result on the session’s event stream, as in [Return a custom tool result](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#return-a-custom-tool-result).
126126 </CodeGroupItem>
127127 
128128 <CodeGroupItem language="Ruby">
129 The Ruby SDK does not have `EnvironmentWorker`. To answer custom tool calls from your own code, send each result on the session's event stream, as in [Return a custom tool result](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#return-a-custom-tool-result).
129 The Ruby SDK does not have `EnvironmentWorker`. To answer custom tool calls from your own code, send each result on the session’s event stream, as in [Return a custom tool result](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#return-a-custom-tool-result).
130130 </CodeGroupItem>
131131</CodeGroup>
132132 
from line 198
198198 
199199### AgentToolContext and the agent toolset
200200 
201`AgentToolContext` is the execution context for tool calls. It defines the working directory and path policy, and can download the session's skills.
201`AgentToolContext` is the execution context for tool calls. It defines the working directory and path policy, and can download the session’s skills.
202202 
203203| Option | Description |
204204| -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
from line 205
205205| `allowed_roots` (typescript: `allowedRoots`; go: `AllowedRoots`) | Directories, in addition to the working directory, that the file tools (`read`, `write`, `edit`, `glob`, `grep`) can reach. |
206206| `read_only_roots` (typescript: `readOnlyRoots`; go: `ReadOnlyRoots`) | Directories under which `write` and `edit` refuse paths. |
207207 
208`EnvironmentWorker` adds the session's memory store directories to `allowed_roots` (typescript: `allowedRoots`; go: `AllowedRoots`) itself, and the directories of stores attached with `access: "read_only"` to `read_only_roots` (typescript: `readOnlyRoots`; go: `ReadOnlyRoots`).
208`EnvironmentWorker` adds the session’s memory store directories to `allowed_roots` (typescript: `allowedRoots`; go: `AllowedRoots`) itself, and the directories of stores attached with `access: "read_only"` to `read_only_roots` (typescript: `readOnlyRoots`; go: `ReadOnlyRoots`).
209209 
210210The confinement is a guardrail for the file tools only, not a sandbox. It does not constrain `bash`.
211211 

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

from line 15
1515## What you own
1616 
1717* **Sandbox image quality and runtime hardening.** Anthropic does not inspect or verify your sandbox image. Follow best practices such as dropping unnecessary Linux capabilities, running as a non-root user, and using a read-only root filesystem.
18* **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.
19* **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.
20* **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.
21* **Per-session credentials.** Each work item your worker claims can carry a per-session `secret` (csharp, go: `Secret`), which the 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` (csharp, go: `Secret`): the memory store endpoints reject the environment key (see [Forward the work item's secret](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-workers#forward-the-work-items-secret)). Pass the `secret` (csharp, go: `Secret`) only into the sandbox that serves that session, keep it out of images and shared volumes, and never log it.
18* **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.
19* **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.
20* **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.
21* **Per-session credentials.** Each work item your worker claims can carry a per-session `secret` (csharp, go: `Secret`), which the 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` (csharp, go: `Secret`): the memory store endpoints reject the environment key (see [Forward the work item’s secret](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-workers#forward-the-work-items-secret)). Pass the `secret` (csharp, go: `Secret`) only into the sandbox that serves that session, keep it out of images and shared volumes, and never log it.
2222* **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.
2323* **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.
24* **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. Cleanup of leftover copies, the permissions on that path, and isolation between sessions that share a filesystem are your responsibility.
25* **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` (csharp, go: `Secret`). Other processes in the sandbox can still change the local copy: commands the agent runs through the `bash` tool, and [custom tools](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-custom-tools) or MCP servers you serve from the sandbox, which run with the worker's permissions. 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 and give it no custom tool that writes to the sandbox's filesystem.
24* **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. Cleanup of leftover copies, the permissions on that path, and isolation between sessions that share a filesystem are your responsibility.
25* **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` (csharp, go: `Secret`). Other processes in the sandbox can still change the local copy: commands the agent runs through the `bash` tool, and [custom tools](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-custom-tools) or MCP servers you serve from the sandbox, which run with the worker’s permissions. 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 and give it no custom tool that writes to the sandbox’s filesystem.
2626 
2727## What Anthropic cannot do for you
2828 
29* **Know that your key leaked.** Anthropic can detect anomalous usage patterns, but cannot know your key was compromised. If you suspect `ANTHROPIC_ENVIRONMENT_KEY` leaked, revoke it and generate a replacement immediately. Revocation is validated on every request, so it takes effect on the worker's next call.
29* **Know that your key leaked.** Anthropic can detect anomalous usage patterns, but cannot know your key was compromised. If you suspect `ANTHROPIC_ENVIRONMENT_KEY` leaked, revoke it and generate a replacement immediately. Revocation is validated on every request, so it takes effect on the worker’s next call.
3030* **Verify your worker build.** Anthropic does not inspect your sandbox image or runtime. A supply-chain compromise in your image is not detectable from the control plane.
31* **Isolate tools inside your sandbox.** Anthropic's security boundary stops at the sandbox. How you isolate individual tool executions from each other inside that boundary is entirely your responsibility.
32* **Enforce data retention in your environment.** Once session content reaches your worker, it is outside Anthropic's data lifecycle controls.
31* **Isolate tools inside your sandbox.** Anthropic’s security boundary stops at the sandbox. How you isolate individual tool executions from each other inside that boundary is entirely your responsibility.
32* **Enforce data retention in your environment.** Once session content reaches your worker, it is outside Anthropic’s data lifecycle controls.
3333 

managed-agents/self-hosted-sandboxes-workers Changed · +9 / -9 lines

### Forward the work item’s secret ### Forward the work item's secret

from line 421
421421 </CodeGroupItem>
422422 </CodeGroup>
423423 
424 Because the handler claims work itself, it must [forward the work item's secret](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-workers#forward-the-work-items-secret), as the `work_secret` (typescript: `workSecret`; go: `WorkSecret`) argument does here.
424 Because the handler claims work itself, it must [forward the work item’s secret](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-workers#forward-the-work-items-secret), as the `work_secret` (typescript: `workSecret`; go: `WorkSecret`) argument does here.
425425 </Step>
426426</Steps>
427427 
from line 437
437437 
438438 ```dockerfile
439439 FROM your-base-image
440 ARG ANT_VERSION=2.3.0
440 ARG ANT_VERSION=2.4.0
441441 ARG TARGETARCH
442442 RUN ARCH=$([ "$TARGETARCH" = "arm64" ] && echo arm64 || echo amd64) && \
443443 curl -fsSL "https://github.com/anthropics/anthropic-cli/releases/download/v${ANT_VERSION}/ant_${ANT_VERSION}_linux_${ARCH}.tar.gz" \
from line 468
468468 
469469 The poller sets the `ANTHROPIC_*` variables that the script forwards, except the secret. See [Environment variables](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-reference#environment-variables).
470470 
471 `/host/outputs` is a host directory you choose. Mounting it at `/workspace` lets you retrieve the session's deliverables after the sandbox exits. The mount also picks up the downloaded `skills/` tree and any intermediate files.
471 `/host/outputs` is a host directory you choose. Mounting it at `/workspace` lets you retrieve the session’s deliverables after the sandbox exits. The mount also picks up the downloaded `skills/` tree and any intermediate files.
472472 </Step>
473473 
474474 <Step title="Start the poller">
from line 478
478478 </Step>
479479</Steps>
480480 
481### Forward the work item's secret
481### Forward the work item’s secret
482482 
483483Each claimed work item can carry a per-session `secret` (csharp, go: `Secret`), which Anthropic issues. The worker that runs the session needs it to mount [memory stores](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-memory).
484484 
from line 486
486486 
487487| You claim work with | The secret arrives as | Pass it to the worker as |
488488| -------------------------------------------------------------- | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
489| `ant beta:worker poll --on-work` | The `secret` field of the work item JSON on your script's standard input | `ANTHROPIC_WORK_SECRET` in the sandbox's environment |
490| The SDK's `work.poller()` (go: `environments.NewWorkPoller()`) | The `secret` (go: `Secret`) field of each claimed work item | `ANTHROPIC_WORK_SECRET` in the sandbox's environment, or the `work_secret` (typescript: `workSecret`; go: `WorkSecret`) argument to `handle_item()` (typescript: `handleItem()`; go: `HandleItem()`) |
489| `ant beta:worker poll --on-work` | The `secret` field of the work item JSON on your script’s standard input | `ANTHROPIC_WORK_SECRET` in the sandbox’s environment |
490| The SDK’s `work.poller()` (go: `environments.NewWorkPoller()`) | The `secret` (go: `Secret`) field of each claimed work item | `ANTHROPIC_WORK_SECRET` in the sandbox’s environment, or the `work_secret` (typescript: `workSecret`; go: `WorkSecret`) argument to `handle_item()` (typescript: `handleItem()`; go: `HandleItem()`) |
491491 
492492Pass the secret only into the sandbox that serves that session, and never log it. See [Security model](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-security) for how it relates to the environment key.
493493 
from line 797
797797 
798798## Stage files for a session
799799 
800Anthropic doesn't mount files or GitHub repositories into self-hosted sandboxes. To make session-specific files available:
800Anthropic doesn’t mount files or GitHub repositories into self-hosted sandboxes. To make session-specific files available:
801801 
8021. Pass file references, such as an S3 path or commit SHA, in the session's `metadata` field.
8021. Pass file references, such as an S3 path or commit SHA, in the session’s `metadata` field.
8038032. In your spawn script or `--on-work` handler, retrieve the session (`GET /v1/sessions/{session_id}`) and read `metadata`. The claimed work item carries the session ID but not the metadata.
8048043. Stage the files into the working directory before any tool runs.
805805 

managed-agents/session-observability Changed · +16 / -16 lines

from line 10
1010 betaHeader: managed-agents-2026-04-01
1111---
1212 
13Use the session viewer in the Claude Console to inspect what an agent did in a session, without writing any code. Use the session's `usage` (csharp, go: `Usage`) totals to see what that work consumed. To see a session's turns, model requests, and tool uses in your observability platform, set up [OpenTelemetry tracing](https://platform.claude.com/docs/en/manage-claude/opentelemetry).
13Use the session viewer in the Claude Console to inspect what an agent did in a session, without writing any code. Use the session’s `usage` (csharp, go: `Usage`) totals to see what that work consumed. To see a session’s turns, model requests, and tool uses in your observability platform, set up [OpenTelemetry tracing](https://platform.claude.com/docs/en/manage-claude/opentelemetry).
1414 
1515## Inspect a session in the Console
1616 
from line 18
1818 
1919The session viewer shows:
2020 
21* **Timeline minimap:** A zoomable overview of the session's activity over time, with one lane for each 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.
21* **Timeline minimap:** A zoomable overview of the session’s activity over time, with one lane for each 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.
2222* **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.
2323* **Inspector:** A resizable side panel with details about the session, in five tabs.
2424 
2525| Inspector tab | What it shows |
2626| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
27| **Session** | 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. |
27| **Session** | 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. |
2828| **Events** | 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/event-deltas). |
29| **Tools** | 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. |
30| **Resources** | 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. Also lists 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. |
29| **Tools** | 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. |
30| **Resources** | 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. Also lists 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. |
3131| **Threads** | 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. |
3232 
3333Append `?event={event_id}` to a session URL to open the session at a specific event.
from line 36
3636 
3737## Track usage
3838 
39The session object includes a `usage` field with the session's cumulative usage: token counts, server tool use, active time, and the tracked list cost. Fetch the session after it goes idle to read the latest totals.
39The session object includes a `usage` field with the session’s cumulative usage: token counts, server tool use, active time, and the tracked list cost. Fetch the session after it goes idle to read the latest totals.
4040 
4141```json
4242{
from line 69
6969| `output_tokens` | Total output tokens across all model calls in the session. |
7070| `cache_read_input_tokens` | Tokens read from the prompt cache. |
7171| `cache_creation` | Cache-creation tokens, broken down by cache lifetime (`ephemeral_5m_input_tokens` and `ephemeral_1h_input_tokens`). |
72| `list_cost` | The session's cumulative consumption priced at public list rates, as a whole number of cents in a string, with a currency code. |
73| `active_seconds` | The cumulative time during which the session had at least one thread running. Overlapping activity from concurrent threads is counted once. The session's runtime cost is priced on this duration. |
74| `server_tool_use` | Counts of server-executed tool requests, for pricing. Web search requests are priced into list cost per request. Web fetch requests carry no per-request charge and aren't metered, so `web_fetch_requests` reads `0`. |
72| `list_cost` | The session’s cumulative consumption priced at public list rates, as a whole number of cents in a string, with a currency code. |
73| `active_seconds` | The cumulative time during which the session had at least one thread running. Overlapping activity from concurrent threads is counted once. The session’s runtime cost is priced on this duration. |
74| `server_tool_use` | Counts of server-executed tool requests, for pricing. Web search requests are priced into list cost per request. Web fetch requests carry no per-request charge and aren’t metered, so `web_fetch_requests` reads `0`. |
7575 
7676Cache entries use a 5-minute TTL by default, so back-to-back turns within that window benefit from cache reads, which reduce per-token cost.
7777 
78The session's `stats` object has its own `active_seconds`, which sums each thread's own active time instead of counting overlapping activity once.
78The session’s `stats` object has its own `active_seconds`, which sums each thread’s own active time instead of counting overlapping activity once.
7979 
8080### Per-thread usage
8181 
82Each [session thread](https://platform.claude.com/docs/en/managed-agents/session-threads)'s own `usage` (csharp, go: `Usage`) carries `list_cost` (java, php: `listCost`; csharp, go: `ListCost`) and `active_seconds` (java, php: `activeSeconds`; csharp, go: `ActiveSeconds`) too. Per-thread figures are rounded independently and exclude the session's running-time cost, so they don't sum exactly to the session's `list_cost` (java, php: `listCost`; csharp, go: `ListCost`). The session figure is the authoritative one.
82Each [session thread](https://platform.claude.com/docs/en/managed-agents/session-threads)’s own `usage` (csharp, go: `Usage`) carries `list_cost` (java, php: `listCost`; csharp, go: `ListCost`) and `active_seconds` (java, php: `activeSeconds`; csharp, go: `ActiveSeconds`) too. Per-thread figures are rounded independently and exclude the session’s running-time cost, so they don’t sum exactly to the session’s `list_cost` (java, php: `listCost`; csharp, go: `ListCost`). The session figure is the authoritative one.
8383 
8484### Read usage from the stream
8585 
86You don't have to poll the session to observe these totals. The `session.usage` event carries the same cumulative snapshot on the session stream and in the event history. The snapshot holds the `usage` (csharp, go: `Usage`) object, plus the session's `budget` (csharp, go: `Budget`) if the session has one.
86You don’t have to poll the session to observe these totals. The `session.usage` event carries the same cumulative snapshot on the session stream and in the event history. The snapshot holds the `usage` (csharp, go: `Usage`) object, plus the session’s `budget` (csharp, go: `Budget`) if the session has one.
8787 
8888The event is emitted on idle transitions rather than on a timer:
8989 
from line 92
9292 
9393### Enforce a spend limit
9494 
95To enforce a spend limit, set a session budget rather than polling usage and stopping the session yourself. The platform prices the session's consumption continuously, and pauses each thread before its next model request once the list cost reaches the cap. See [When a session reaches its budget](https://platform.claude.com/docs/en/managed-agents/budgets#when-a-session-reaches-its-budget) for what that looks like on the stream.
95To enforce a spend limit, set a session budget rather than polling usage and stopping the session yourself. The platform prices the session’s consumption continuously, and pauses each thread before its next model request once the list cost reaches the cap. See [When a session reaches its budget](https://platform.claude.com/docs/en/managed-agents/budgets#when-a-session-reaches-its-budget) for what that looks like on the stream.
9696 
9797## Debugging tips
9898 
9999* **Check session events:** The session reports errors through [`session.error`](https://platform.claude.com/docs/en/managed-agents/reference#event-types) events.
100* **Review tool results:** Tool failures often explain unexpected agent behavior. The Inspector's **Tools** tab shows each tool's failures.
100* **Review tool results:** Tool failures often explain unexpected agent behavior. The Inspector’s **Tools** tab shows each tool’s failures.
101101* **Use system prompts:** Add logging instructions to the system prompt so the agent summarizes what it did and what it found.
102* **Troubleshoot previews:** If a stream that opts in to event deltas doesn't behave as you expect, see [Troubleshoot previews](https://platform.claude.com/docs/en/managed-agents/event-deltas#troubleshoot-previews).
102* **Troubleshoot previews:** If a stream that opts in to event deltas doesn’t behave as you expect, see [Troubleshoot previews](https://platform.claude.com/docs/en/managed-agents/event-deltas#troubleshoot-previews).
103103 
104104## Next steps
105105 
from line 109
109109 </Card>
110110 
111111 <Card title="Session budgets" icon="coins" href="https://platform.claude.com/docs/en/managed-agents/budgets">
112 Cap a session's spend with a hard dollar budget enforced at public list rates.
112 Cap a session’s spend with a hard dollar budget enforced at public list rates.
113113 </Card>
114114</CardGroup>
115115 

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

from line 18
1818 
1919| Status | Description |
2020| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
21| `idle` | Agent is waiting for input, including user messages or tool confirmations. Sessions created without `initial_events` (java, php: `initialEvents`; csharp, go: `InitialEvents`) start in `idle`. A session can be `idle` while a [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs#while-a-run-is-open) is still open, so `idle` alone doesn't mean that the work is done. See [Know when the work is done](https://platform.claude.com/docs/en/managed-agents/workflow-runs#know-when-the-work-is-done). |
21| `idle` | Agent is waiting for input, including user messages or tool confirmations. Sessions created without `initial_events` (java, php: `initialEvents`; csharp, go: `InitialEvents`) start in `idle`. A session can be `idle` while a [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs#while-a-run-is-open) is still open, so `idle` alone doesn’t mean that the work is done. See [Know when the work is done](https://platform.claude.com/docs/en/managed-agents/workflow-runs#know-when-the-work-is-done). |
2222| `running` | Agent is actively executing. |
2323| `rescheduling` | Transient error occurred, retrying automatically. |
2424| `terminated` | Session has ended, either because of an unrecoverable error or because it was archived. A session that completes its work goes `idle`, not `terminated`. |
from line 25
2525 
2626## Updating the agent configuration
2727 
28You can update a session's `agent.tools` (csharp, go: `Agent.Tools`) and `agent.mcp_servers` (java, php: `agent.mcpServers`; csharp: `Agent.McpServers`; go: `Agent.MCPServers`), including permission policies and per-tool web settings such as [domain filters](https://platform.claude.com/docs/en/managed-agents/tools-web-restrictions#change-the-lists-mid-session), mid-session without creating a new agent version. Updates are session-local and do not apply to the underlying agent. Updated `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) and `blocked_domains` (java, php: `blockedDomains`; csharp, go: `BlockedDomains`) apply to the rest of the session.
28You can update a session’s `agent.tools` (csharp, go: `Agent.Tools`) and `agent.mcp_servers` (java, php: `agent.mcpServers`; csharp: `Agent.McpServers`; go: `Agent.MCPServers`), including permission policies and per-tool web settings such as [domain filters](https://platform.claude.com/docs/en/managed-agents/tools-web-restrictions#change-the-lists-mid-session), mid-session without creating a new agent version. Updates are session-local and do not apply to the underlying agent. Updated `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) and `blocked_domains` (java, php: `blockedDomains`; csharp, go: `BlockedDomains`) apply to the rest of the session.
2929 
30Only the agent's `tools` (csharp, go: `Tools`) and `mcp_servers` (java, php: `mcpServers`; csharp: `McpServers`; go: `MCPServers`) can change after a session is created. To run a session with `model` (csharp, go: `Model`), `system` (csharp, go: `System`; ruby: `system_`), or `skills` (csharp, go: `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` (csharp, go: `Model`) override when you create it. The agent's configured `system` (csharp, go: `System`; ruby: `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#send-system-messages).
30Only the agent’s `tools` (csharp, go: `Tools`) and `mcp_servers` (java, php: `mcpServers`; csharp: `McpServers`; go: `MCPServers`) can change after a session is created. To run a session with `model` (csharp, go: `Model`), `system` (csharp, go: `System`; ruby: `system_`), or `skills` (csharp, go: `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` (csharp, go: `Model`) override when you create it. The agent’s configured `system` (csharp, go: `System`; ruby: `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#send-system-messages).
3131 
3232The semantics of a `tools` (csharp, go: `Tools`) or `mcp_servers` (java, php: `mcpServers`; csharp: `McpServers`; go: `MCPServers`) update are full replacement: the provided array is the new value. To preserve existing entries, `GET` the session, modify the array, and `POST` it back.
3333 
34The session must be `idle` to update the agent. To update the agent while the session is running, send a [`user.interrupt` event](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#interrupt-the-agent) by itself and wait for the session to become `idle`. If a [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs#while-a-run-is-open) is open, whether it's running or paused, the update returns a 400 error, even when the session is `idle`. An interrupt doesn't end a run, so the update still fails after you interrupt the session. Send a `user.message` that [asks the agent to stop its runs](https://platform.claude.com/docs/en/managed-agents/workflow-runs#interrupt-a-session-with-runs-open), or wait until every run has ended.
34The session must be `idle` to update the agent. To update the agent while the session is running, send a [`user.interrupt` event](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#interrupt-the-agent) by itself and wait for the session to become `idle`. If a [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs#while-a-run-is-open) is open, whether it’s running or paused, the update returns a 400 error, even when the session is `idle`. An interrupt doesn’t end a run, so the update still fails after you interrupt the session. Send a `user.message` that [asks the agent to stop its runs](https://platform.claude.com/docs/en/managed-agents/workflow-runs#interrupt-a-session-with-runs-open), or wait until every run has ended.
3535 
3636<CodeGroup>
3737 ```bash cURL
from line 196
196196 
197197## Updating the session budget
198198 
199A session [created with a budget](https://platform.claude.com/docs/en/managed-agents/sessions#set-a-session-budget) accepts two kinds of budget update: replacing the cap with a new `max_list_cost` (java, php: `maxListCost`; csharp, go: `MaxListCost`), and removing it by passing `"budget": null` (python: `budget=None`; typescript: `budget: null`; ruby: `budget: nil`; go: `Budget: param.NullStruct[anthropic.BetaManagedAgentsBudgetLimitParam]()`; java: `.budget(Optional.empty())`; csharp: `Budget = null`; php: `requestOptions: ['extraBodyParams' => ['budget' => null]]`; cli: `--budget null`). Both automatically resume work that paused when the session reached its cap. A replacement cap can be higher or lower than the current one, but it must be strictly greater than the session's consumed list cost. Removal is one-way: a non-null `budget` (csharp, go: `Budget`) is accepted only on a session that currently has one. You therefore can't re-add a removed budget or add one to a session created without it. See [Session budgets](https://platform.claude.com/docs/en/managed-agents/budgets#resume-a-session-at-its-budget) for request examples, the error behaviors, and what counts toward list cost.
199A session [created with a budget](https://platform.claude.com/docs/en/managed-agents/sessions#set-a-session-budget) accepts two kinds of budget update: replacing the cap with a new `max_list_cost` (java, php: `maxListCost`; csharp, go: `MaxListCost`), and removing it by passing `"budget": null` (python: `budget=None`; typescript: `budget: null`; ruby: `budget: nil`; go: `Budget: param.NullStruct[anthropic.BetaManagedAgentsBudgetLimitParam]()`; java: `.budget(Optional.empty())`; csharp: `Budget = null`; php: `requestOptions: ['extraBodyParams' => ['budget' => null]]`; cli: `--budget null`). Both automatically resume work that paused when the session reached its cap. A replacement cap can be higher or lower than the current one, but it must be strictly greater than the session’s consumed list cost. Removal is one-way: a non-null `budget` (csharp, go: `Budget`) is accepted only on a session that currently has one. You therefore can’t re-add a removed budget or add one to a session created without it. See [Session budgets](https://platform.claude.com/docs/en/managed-agents/budgets#resume-a-session-at-its-budget) for request examples, the error behaviors, and what counts toward list cost.
200200 
201201## Retrieving a session
202202 
from line 255
255255 
256256Results from `GET /v1/sessions` are paginated. Use the `limit` query parameter to control the page size. Each response includes a `next_page` cursor; pass it as the `page` parameter on the next request to fetch the following page. `next_page` is `null` when there are no more results.
257257 
258To go back a page, pass `prev_page` as the `page` parameter. `prev_page` is `null` when you're on the first page.
258To go back a page, pass `prev_page` as the `page` parameter. `prev_page` is `null` when you’re on the first page.
259259 
260A `page` cursor is opaque and encodes the `order` of the request that produced it. The `order` query parameter sets the sort direction of the results, `asc` or `desc` by creation time; the default is `desc` (newest first). Reusing a cursor with a different `order` returns a 400 error, as does changing a `created_at` filter so that it excludes the cursor's position. Other query parameters, including the remaining filters and `limit`, can change between paginated requests. For the pagination fields shared across list endpoints, see [Pagination](https://platform.claude.com/docs/en/api/overview#pagination).
260A `page` cursor is opaque and encodes the `order` of the request that produced it. The `order` query parameter sets the sort direction of the results, `asc` or `desc` by creation time; the default is `desc` (newest first). Reusing a cursor with a different `order` returns a 400 error, as does changing a `created_at` filter so that it excludes the cursor’s position. Other query parameters, including the remaining filters and `limit`, can change between paginated requests. For the pagination fields shared across list endpoints, see [Pagination](https://platform.claude.com/docs/en/api/overview#pagination).
261261 
262262<CodeGroup>
263263 ```bash cURL
from line 490
490490 
491491## Archiving a session
492492 
493Archive a session to prevent new events from being sent while preserving its history. A `running` session cannot be archived; to archive one, send a [`user.interrupt` event](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#interrupt-the-agent) by itself and wait for the session to become `idle`. If a [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs#while-a-run-is-open) is open, archiving might return a 400 error, even when the session is `idle`, or it might succeed and end the run. Before you archive, send a `user.message` that [asks the agent to stop its runs](https://platform.claude.com/docs/en/managed-agents/workflow-runs#interrupt-a-session-with-runs-open), or wait until each run has ended. Then archive the session once it's `idle`.
493Archive a session to prevent new events from being sent while preserving its history. A `running` session cannot be archived; to archive one, send a [`user.interrupt` event](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#interrupt-the-agent) by itself and wait for the session to become `idle`. If a [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs#while-a-run-is-open) is open, archiving might return a 400 error, even when the session is `idle`, or it might succeed and end the run. Before you archive, send a `user.message` that [asks the agent to stop its runs](https://platform.claude.com/docs/en/managed-agents/workflow-runs#interrupt-a-session-with-runs-open), or wait until each run has ended. Then archive the session once it’s `idle`.
494494 
495495<CodeGroup>
496496 ```bash cURL
from line 538
538538 
539539## Deleting a session
540540 
541Deleting a session is permanent. It deletes the session's record, events, and associated sandbox. A `running` session cannot be deleted; to delete one, send a [`user.interrupt` event](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#interrupt-the-agent) by itself and wait for the session to become `idle`. If a [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs#while-a-run-is-open) is open, deleting might return a 400 error, even when the session is `idle`, or it might succeed. After a delete that succeeds, no `workflow_run` event reports the end of the session's runs. Before you delete, send a `user.message` that [asks the agent to stop its runs](https://platform.claude.com/docs/en/managed-agents/workflow-runs#interrupt-a-session-with-runs-open), or wait until each run has ended. Then delete the session once it's `idle`.
541Deleting a session is permanent. It deletes the session’s record, events, and associated sandbox. A `running` session cannot be deleted; to delete one, send a [`user.interrupt` event](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#interrupt-the-agent) by itself and wait for the session to become `idle`. If a [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs#while-a-run-is-open) is open, deleting might return a 400 error, even when the session is `idle`, or it might succeed. After a delete that succeeds, no `workflow_run` event reports the end of the session’s runs. Before you delete, send a `user.message` that [asks the agent to stop its runs](https://platform.claude.com/docs/en/managed-agents/workflow-runs#interrupt-a-session-with-runs-open), or wait until each run has ended. Then delete the session once it’s `idle`.
542542 
543Memory stores, vaults, skills, environments, and agents are independent resources and are not affected by session deletion. Files you uploaded through the Files API are also unaffected, but files the session itself produced are scoped to it and are permanently deleted along with its filesystem. Download anything you need to keep before deleting the session. An output file written at the end of the last turn can take a few seconds after the session goes idle to appear in the [session's file list](https://platform.claude.com/docs/en/managed-agents/files#listing-and-downloading-session-files), so check that the files you expect are listed first.
543Memory stores, vaults, skills, environments, and agents are independent resources and are not affected by session deletion. Files you uploaded through the Files API are also unaffected, but files the session itself produced are scoped to it and are permanently deleted along with its filesystem. Download anything you need to keep before deleting the session. An output file written at the end of the last turn can take a few seconds after the session goes idle to appear in the [session’s file list](https://platform.claude.com/docs/en/managed-agents/files#listing-and-downloading-session-files), so check that the files you expect are listed first.
544544 
545545<CodeGroup>
546546 ```bash cURL

managed-agents/session-threads Changed · +33 / -33 lines

from line 14
1414 
1515## Primary thread and session threads
1616 
17The **session-level event stream** (`/v1/sessions/{session_id}/events/stream`) is considered the **primary thread**, containing a condensed view of all activity across all threads. You don't see the full activity from [subagents](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#delegate-to-subagents), but you do see the start and end of their work, and blocking events such as tool permission requests.
17The **session-level event stream** (`/v1/sessions/{session_id}/events/stream`) is considered the **primary thread**, containing a condensed view of all activity across all threads. You don’t see the full activity from [subagents](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#delegate-to-subagents), but you do see the start and end of their work, and blocking events such as tool permission requests.
1818 
19**Session threads** are where you examine a specific agent's activity.
19**Session threads** are where you examine a specific agent’s activity.
2020 
21The session `status` (csharp, go: `Status`) is an aggregation of all agent activity; if at least one thread is `running`, then the overall session status is `running` as well. A [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs) that's running can keep the session `running` too, even while none of its threads is working. When no thread is working and a thread waits on your client, the session is `idle`; see [Know when the work is done](https://platform.claude.com/docs/en/managed-agents/workflow-runs#know-when-the-work-is-done).
21The session `status` (csharp, go: `Status`) is an aggregation of all agent activity; if at least one thread is `running`, then the overall session status is `running` as well. A [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs) that’s running can keep the session `running` too, even while none of its threads is working. When no thread is working and a thread waits on your client, the session is `idle`; see [Know when the work is done](https://platform.claude.com/docs/en/managed-agents/workflow-runs#know-when-the-work-is-done).
2222 
23A [session budget](https://platform.claude.com/docs/en/managed-agents/budgets) is a single shared cap across all of a session's threads. As the cap is reached, threads pause independently, and each thread's cost is priced at the thread's own served model.
23A [session budget](https://platform.claude.com/docs/en/managed-agents/budgets) is a single shared cap across all of a session’s threads. As the cap is reached, threads pause independently, and each thread’s cost is priced at the thread’s own served model.
2424 
2525<Note>
26 A session can have at most 25 child threads at a time. Idle threads count until you archive them, and the primary thread doesn't count. The primary thread's agent can call multiple copies of a single subagent, creating multiple threads associated with one `agent`. [Advisor](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#give-the-session-an-advisor) consultation threads are exempt from this limit. So are a [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs)'s threads.
26 A session can have at most 25 child threads at a time. Idle threads count until you archive them, and the primary thread doesn’t count. The primary thread’s agent can call multiple copies of a single subagent, creating multiple threads associated with one `agent`. [Advisor](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#give-the-session-an-advisor) consultation threads are exempt from this limit. So are a [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs)’s threads.
2727</Note>
2828 
2929## List threads
from line 102
102102 ```
103103</CodeGroup>
104104 
105The full list includes the primary thread. `parent_thread_id` (java: `parentThreadId`; php: `parentThreadID`; csharp, go: `ParentThreadID`) is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) for the primary thread. Every other thread is a child thread. `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) except on [a run's threads](https://platform.claude.com/docs/en/managed-agents/workflow-runs#a-runs-threads).
105The full list includes the primary thread. `parent_thread_id` (java: `parentThreadId`; php: `parentThreadID`; csharp, go: `ParentThreadID`) is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) for the primary thread. Every other thread is a child thread. `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) except on [a run’s threads](https://platform.claude.com/docs/en/managed-agents/workflow-runs#a-runs-threads).
106106 
107107To list only threads that have certain statuses, add `statuses[]` to the request, and repeat it to give more than one status, as in `?statuses[]=running&statuses[]=idle`. Leave it out to return threads of every status.
108108 
109109## Interrupt a session thread
110110 
111Send `user.interrupt` with `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`) to stop a specific thread. Omitting `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`) interrupts every non-archived thread in the session, including the primary. In a session with dynamic workflows, an interrupt ends no run, and one that names a run's thread stops nothing. An interrupt closes other child threads' pending tool calls, but don't rely on it to close a run thread's. See [Interrupt a session with runs open](https://platform.claude.com/docs/en/managed-agents/workflow-runs#interrupt-a-session-with-runs-open).
111Send `user.interrupt` with `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`) to stop a specific thread. Omitting `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`) interrupts every non-archived thread in the session, including the primary. In a session with dynamic workflows, an interrupt ends no run, and one that names a run’s thread stops nothing. An interrupt closes other child threads’ pending tool calls, but don’t rely on it to close a run thread’s. See [Interrupt a session with runs open](https://platform.claude.com/docs/en/managed-agents/workflow-runs#interrupt-a-session-with-runs-open).
112112 
113113<CodeGroup>
114114 ```bash cURL
from line 189
189189 ```
190190</CodeGroup>
191191 
192Against a subagent's thread blocked on `requires_action`, the interrupt closes each pending tool call with an error tool result ("Tool execution was interrupted before completion. Please retry.") and re-emits `session.thread_status_idle` with `stop_reason: end_turn` directly; the model is not sampled. Against a child thread that's idle with `end_turn` or `budget_reached`, the interrupt is a no-op. An interrupt that names a terminated thread returns a 400 error. An interrupted child doesn't send the primary thread's agent the report it sends when a turn ends. While that agent waits on the child, it doesn't start another turn until something else reaches it, such as a `user.message` or another thread's report.
192Against a subagent’s thread blocked on `requires_action`, the interrupt closes each pending tool call with an error tool result (“Tool execution was interrupted before completion. Please retry.”) and re-emits `session.thread_status_idle` with `stop_reason: end_turn` directly; the model is not sampled. Against a child thread that’s idle with `end_turn` or `budget_reached`, the interrupt is a no-op. An interrupt that names a terminated thread returns a 400 error. An interrupted child doesn’t send the primary thread’s agent the report it sends when a turn ends. While that agent waits on the child, it doesn’t start another turn until something else reaches it, such as a `user.message` or another thread’s report.
193193 
194194## Archive a session thread
195195 
196Optionally archive a session thread when it has completed its work. Archiving a thread frees its place under the 25-child-thread limit. The server archives a [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs)'s threads itself. You don't need to archive them, and you can't while the run is open.
196Optionally archive a session thread when it has completed its work. Archiving a thread frees its place under the 25-child-thread limit. The server archives a [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs)’s threads itself. You don’t need to archive them, and you can’t while the run is open.
197197 
198198<CodeGroup>
199199 ```bash cURL
from line 374
374374 
375375## Primary thread events
376376 
377These events surface multiagent activity on the primary thread at `/v1/sessions/{session_id}/events/stream`. Message-direction events are named relative to the thread whose stream they appear on: `agent.thread_message_received` means a message arrived on this thread from another thread, and `agent.thread_message_sent` means this thread sent one. The task that the primary thread's agent delegates, for example, arrives on the child's own stream as an `agent.thread_message_received` event.
377These events surface multiagent activity on the primary thread at `/v1/sessions/{session_id}/events/stream`. Message-direction events are named relative to the thread whose stream they appear on: `agent.thread_message_received` means a message arrived on this thread from another thread, and `agent.thread_message_sent` means this thread sent one. The task that the primary thread’s agent delegates, for example, arrives on the child’s own stream as an `agent.thread_message_received` event.
378378 
379379| Type | Description |
380380| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
from line 382
382382| `session.thread_status_running` | A thread started activity. |
383383| `session.thread_status_idle` | The agent associated with the thread is awaiting input. Includes a `stop_reason` (java, php: `stopReason`; csharp, go: `StopReason`) indicating why the agent stopped. |
384384| `session.thread_status_terminated` | A thread terminated and accepts no further input, for example because it was archived or encountered an unrecoverable error. An advisor thread also terminates when its consultation ends. |
385| `agent.thread_message_received` | On the primary thread, a subagent sent the primary thread's agent a report or question. Includes `from_session_thread_id` (java: `fromSessionThreadId`; php: `fromSessionThreadID`; csharp, go: `FromSessionThreadID`), `from_agent_name` (java, php: `fromAgentName`; csharp, go: `FromAgentName`), and `content` (csharp, go: `Content`). |
386| `agent.thread_message_sent` | On the primary thread, the primary thread's agent sent a subagent a task or follow-up message. Includes `to_session_thread_id` (java: `toSessionThreadId`; php: `toSessionThreadID`; csharp, go: `ToSessionThreadID`), `to_agent_name` (java, php: `toAgentName`; csharp, go: `ToAgentName`), and `content` (csharp, go: `Content`). |
385| `agent.thread_message_received` | On the primary thread, a subagent sent the primary thread’s agent a report or question. Includes `from_session_thread_id` (java: `fromSessionThreadId`; php: `fromSessionThreadID`; csharp, go: `FromSessionThreadID`), `from_agent_name` (java, php: `fromAgentName`; csharp, go: `FromAgentName`), and `content` (csharp, go: `Content`). |
386| `agent.thread_message_sent` | On the primary thread, the primary thread’s agent sent a subagent a task or follow-up message. Includes `to_session_thread_id` (java: `toSessionThreadId`; php: `toSessionThreadID`; csharp, go: `ToSessionThreadID`), `to_agent_name` (java, php: `toAgentName`; csharp, go: `ToAgentName`), and `content` (csharp, go: `Content`). |
387387 
388388Advisor consultations emit these same thread events under the reserved name `anthropic.advisor` (as `agent_name` (java, php: `agentName`; csharp, go: `AgentName`) on the thread lifecycle events and `from_agent_name` (java, php: `fromAgentName`; csharp, go: `FromAgentName`) on the advice delivery); see [Give the session an advisor](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#give-the-session-an-advisor) for the sequence.
389389 
390A [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs)'s threads show on the primary stream as follows:
390A [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs)’s threads show on the primary stream as follows:
391391 
392* **Lifecycle events:** Each run thread sends `session.thread_created`, with the run's `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`), and its `session.thread_status_running`, `session.thread_status_idle`, and `session.thread_status_terminated` events.
393* **Message events:** A run thread's prompt, an `agent.thread_message_received` event, stays on its own stream.
392* **Lifecycle events:** Each run thread sends `session.thread_created`, with the run’s `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`), and its `session.thread_status_running`, `session.thread_status_idle`, and `session.thread_status_terminated` events.
393* **Message events:** A run thread’s prompt, an `agent.thread_message_received` event, stays on its own stream.
394394* **Run events:** `workflow_run.*` events also arrive on this stream; see [Run events](https://platform.claude.com/docs/en/managed-agents/workflow-runs#run-events).
395* **Tool calls that wait on you:** A run thread's tool calls that need your client are cross-posted to this stream, as for any child thread. See [Tool permissions and custom tools](https://platform.claude.com/docs/en/managed-agents/session-threads#tool-permissions-and-custom-tools).
395* **Tool calls that wait on you:** A run thread’s tool calls that need your client are cross-posted to this stream, as for any child thread. See [Tool permissions and custom tools](https://platform.claude.com/docs/en/managed-agents/session-threads#tool-permissions-and-custom-tools).
396396 
397397## Session thread events
398398 
399Critical events are proxied to the primary thread. However, you might still want to investigate a specific agent's reasoning and tool calls. To do so, stream or list the events from the associated session thread.
399Critical events are proxied to the primary thread. However, you might still want to investigate a specific agent’s reasoning and tool calls. To do so, stream or list the events from the associated session thread.
400400 
401Each session thread has its own event stream at `/v1/sessions/{session_id}/threads/{thread_id}/stream`, and it accepts the same `event_deltas[]` parameter as the session-level stream, so you can preview a subagent's text as the model generates it. A connection previews only the thread it's reading: a child thread's previews never appear on the session-level stream, so to watch a subagent live, open its own thread stream. See [Preview session thread events](https://platform.claude.com/docs/en/managed-agents/event-deltas#preview-session-thread-events) for opting in, accumulating, and reconciling previews.
401Each session thread has its own event stream at `/v1/sessions/{session_id}/threads/{thread_id}/stream`, and it accepts the same `event_deltas[]` parameter as the session-level stream, so you can preview a subagent’s text as the model generates it. A connection previews only the thread it’s reading: a child thread’s previews never appear on the session-level stream, so to watch a subagent live, open its own thread stream. See [Preview session thread events](https://platform.claude.com/docs/en/managed-agents/event-deltas#preview-session-thread-events) for opting in, accumulating, and reconciling previews.
402402 
403In a workflow run, the server runs a workflow: a program that the primary thread's agent writes. On each of the run's threads, the first `agent.thread_message_received` is the prompt that the workflow wrote. Its `from_session_thread_id` (java: `fromSessionThreadId`; php: `fromSessionThreadID`; csharp, go: `FromSessionThreadID`) is the primary thread's ID, and the API doesn't set its `from_agent_name` (java, php: `fromAgentName`; csharp, go: `FromAgentName`). The API doesn't guarantee the prompt's text, so don't parse it. The thread's `session.thread_status_terminated` event, on the primary thread's stream, tells you the thread is done. No event records the result it returned to the workflow.
403In a workflow run, the server runs a workflow: a program that the primary thread’s agent writes. On each of the run’s threads, the first `agent.thread_message_received` is the prompt that the workflow wrote. Its `from_session_thread_id` (java: `fromSessionThreadId`; php: `fromSessionThreadID`; csharp, go: `FromSessionThreadID`) is the primary thread’s ID, and the API doesn’t set its `from_agent_name` (java, php: `fromAgentName`; csharp, go: `FromAgentName`). The API doesn’t guarantee the prompt’s text, so don’t parse it. The thread’s `session.thread_status_terminated` event, on the primary thread’s stream, tells you the thread is done. No event records the result it returned to the workflow.
404404 
405A thread's stream doesn't replay earlier events. Right after `session.thread_created`, the event list of a run's thread can be empty, because the server writes the thread's first event after it. So open the thread's stream first, then list the thread's events, and skip each streamed event whose `id` (csharp, go: `ID`) the list returned.
405A thread’s stream doesn’t replay earlier events. Right after `session.thread_created`, the event list of a run’s thread can be empty, because the server writes the thread’s first event after it. So open the thread’s stream first, then list the thread’s events, and skip each streamed event whose `id` (csharp, go: `ID`) the list returned.
406406 
407407<Tabs>
408408 <Tab title="Stream session thread events">
from line 668
668668}
669669```
670670 
671Post `user.tool_confirmation` (with `tool_use_id` (java: `toolUseId`; php: `toolUseID`; csharp, go: `ToolUseID`)) or `user.custom_tool_result` (with `custom_tool_use_id` (java: `customToolUseId`; php: `customToolUseID`; csharp, go: `CustomToolUseID`)); the server routes the response to the correct thread automatically. The response can appear on the primary thread and on the subagent's thread with different `id` (csharp, go: `ID`) values. To match the two copies, compare `type` (csharp, go: `Type`) and `tool_use_id` (java: `toolUseId`; php: `toolUseID`; csharp, go: `ToolUseID`) (or `custom_tool_use_id` (java: `customToolUseId`; php: `customToolUseID`; csharp, go: `CustomToolUseID`)), not `id` (csharp, go: `ID`).
671Post `user.tool_confirmation` (with `tool_use_id` (java: `toolUseId`; php: `toolUseID`; csharp, go: `ToolUseID`)) or `user.custom_tool_result` (with `custom_tool_use_id` (java: `customToolUseId`; php: `customToolUseID`; csharp, go: `CustomToolUseID`)); the server routes the response to the correct thread automatically. The response can appear on the primary thread and on the subagent’s thread with different `id` (csharp, go: `ID`) values. To match the two copies, compare `type` (csharp, go: `Type`) and `tool_use_id` (java: `toolUseId`; php: `toolUseID`; csharp, go: `ToolUseID`) (or `custom_tool_use_id` (java: `customToolUseId`; php: `customToolUseID`; csharp, go: `CustomToolUseID`)), not `id` (csharp, go: `ID`).
672672 
673The session goes `idle` only when no thread is `running`, so `session.status_idle` can arrive long after a subagent's call. You don't have to wait for it: send the `user.custom_tool_result` as soon as the cross-posted `agent.custom_tool_use` event arrives.
673The session goes `idle` only when no thread is `running`, so `session.status_idle` can arrive long after a subagent’s call. You don’t have to wait for it: send the `user.custom_tool_result` as soon as the cross-posted `agent.custom_tool_use` event arrives.
674674 
675Under `auto`, your `user.message` events can lead the server to allow a call it would otherwise deny. Nothing in a subagent's thread counts as your intent. Your client posts no messages there, and the messages that the primary thread's agent sends the subagent don't count. When the server denies a call under `auto`, nothing is cross-posted: the event and the error tool result appear only on the subagent's own [thread stream](https://platform.claude.com/docs/en/managed-agents/session-threads#session-thread-events), and the subagent keeps running.
675Under `auto`, your `user.message` events can lead the server to allow a call it would otherwise deny. Nothing in a subagent’s thread counts as your intent. Your client posts no messages there, and the messages that the primary thread’s agent sends the subagent don’t count. When the server denies a call under `auto`, nothing is cross-posted: the event and the error tool result appear only on the subagent’s own [thread stream](https://platform.claude.com/docs/en/managed-agents/session-threads#session-thread-events), and the subagent keeps running.
676676 
677677The following example goes inside the event loop of the [tool confirmation handler](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#tool-confirmation). For each ID in `stop_reason.event_ids`, it sends a `user.tool_confirmation` that allows the call. The same pattern applies to `user.custom_tool_result`, which you can also send as soon as its `agent.custom_tool_use` event arrives.
678678 
from line 779
779779 ```
780780</CodeGroup>
781781 
782The previous pattern answers the calls that an idle event lists. On the primary stream, a subagent's `session.thread_status_idle` event can arrive before the `agent.tool_use` or `agent.mcp_tool_use` events that its `stop_reason.event_ids` lists. A `user.tool_confirmation` for a call whose event hasn't arrived yet can return 400. To avoid that, answer each call whose [`evaluated_permission` (java, php: `evaluatedPermission`; csharp, go: `EvaluatedPermission`)](https://platform.claude.com/docs/en/managed-agents/permission-policies#see-how-each-call-was-evaluated) is `ask` when its own event arrives on the primary stream.
782The previous pattern answers the calls that an idle event lists. On the primary stream, a subagent’s `session.thread_status_idle` event can arrive before the `agent.tool_use` or `agent.mcp_tool_use` events that its `stop_reason.event_ids` lists. A `user.tool_confirmation` for a call whose event hasn’t arrived yet can return 400. To avoid that, answer each call whose [`evaluated_permission` (java, php: `evaluatedPermission`; csharp, go: `EvaluatedPermission`)](https://platform.claude.com/docs/en/managed-agents/permission-policies#see-how-each-call-was-evaluated) is `ask` when its own event arrives on the primary stream.
783783 

managed-agents/sessions Changed · +14 / -14 lines

from line 404
404404 ```
405405</CodeGroup>
406406 
407`initial_events` (java, php: `initialEvents`; csharp, go: `InitialEvents`) are not echoed on the create response. To see the seeded message, list the session's events.
407`initial_events` (java, php: `initialEvents`; csharp, go: `InitialEvents`) are not echoed on the create response. To see the seeded message, list the session’s events.
408408 
409No other event type is accepted. Events that respond to an agent turn (`user.tool_confirmation`, `user.tool_result`, and `user.custom_tool_result`) aren't accepted because no agent turn exists yet, and `user.interrupt` isn't accepted because there is no turn to stop. Unlike `initial_events` (java, php: `initialEvents`; csharp, go: `InitialEvents`) on a scheduled deployment, a session's `initial_events` (java, php: `initialEvents`; csharp, go: `InitialEvents`) don't accept `system.message`.
409No other event type is accepted. Events that respond to an agent turn (`user.tool_confirmation`, `user.tool_result`, and `user.custom_tool_result`) aren’t accepted because no agent turn exists yet, and `user.interrupt` isn’t accepted because there is no turn to stop. Unlike `initial_events` (java, php: `initialEvents`; csharp, go: `InitialEvents`) on a scheduled deployment, a session’s `initial_events` (java, php: `initialEvents`; csharp, go: `InitialEvents`) don’t accept `system.message`.
410410 
411411Each event in `initial_events` (java, php: `initialEvents`; csharp, go: `InitialEvents`) is validated and persisted before the create response returns, in list order, with a server-assigned ID, exactly as if you had posted it to the [send events](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#send-events) endpoint immediately after creation. Per-event content rules are also the same as on that endpoint. An empty list is equivalent to omitting the field. Validation is all-or-nothing: if any event fails validation, the whole request is rejected and no session is created.
412412 
from line 423
423423 
424424### Override agent configuration for a session
425425 
426You can pass `agent` (csharp, go: `Agent`) in three forms: an agent ID string, a pinned-version object (`type: "agent"`), or an overrides object (`type: "agent_with_overrides"`). The overrides form changes parts of the agent's configuration for a single session. Use it to try a different model or grant an extra tool in one session without versioning the agent. For the overrides form, pass the agent's `id` (csharp, go: `ID`) and optionally a `version` (csharp, go: `Version`) (omit `version` (csharp, go: `Version`) to use the agent's latest version). Then include any of `model` (csharp, go: `Model`), `system` (csharp, go: `System`; ruby: `system_`), `tools` (csharp, go: `Tools`), `mcp_servers` (java, php: `mcpServers`; csharp: `McpServers`; go: `MCPServers`), or `skills` (csharp, go: `Skills`) with the values the session should use.
426You can pass `agent` (csharp, go: `Agent`) in three forms: an agent ID string, a pinned-version object (`type: "agent"`), or an overrides object (`type: "agent_with_overrides"`). The overrides form changes parts of the agent’s configuration for a single session. Use it to try a different model or grant an extra tool in one session without versioning the agent. For the overrides form, pass the agent’s `id` (csharp, go: `ID`) and optionally a `version` (csharp, go: `Version`) (omit `version` (csharp, go: `Version`) to use the agent’s latest version). Then include any of `model` (csharp, go: `Model`), `system` (csharp, go: `System`; ruby: `system_`), `tools` (csharp, go: `Tools`), `mcp_servers` (java, php: `mcpServers`; csharp: `McpServers`; go: `MCPServers`), or `skills` (csharp, go: `Skills`) with the values the session should use.
427427 
428428Each overridable field follows the same three rules:
429429 
from line 432
432432* **Set the field to `null`, or to an empty array for list fields:** The session runs with that field cleared. This rule applies in full to `system` (csharp, go: `System`; ruby: `system_`) and `skills` (csharp, go: `Skills`). There are three exceptions:
433433 
434434 * `model` (csharp, go: `Model`) is never clearable. A session always needs a model, so setting `model` (csharp, go: `Model`) to `null` returns a 400 `agent_model_required` error.
435 * Clearing `tools` (csharp, go: `Tools`) returns a 400 error when the session's effective `skills` (csharp, go: `Skills`) is non-empty, because skills require the `read` tool. Otherwise, setting `tools` (csharp, go: `Tools`) to `null` or to an empty array clears the field.
436 * Clearing `mcp_servers` (java, php: `mcpServers`; csharp: `McpServers`; go: `MCPServers`) returns a 400 error when the session's effective `tools` (csharp, go: `Tools`) still contains an `mcp_toolset` that references one of the agent's servers. Override `tools` (csharp, go: `Tools`) in the same request to remove those `mcp_toolset` entries, then clear `mcp_servers` (java, php: `mcpServers`; csharp: `McpServers`; go: `MCPServers`).
435 * Clearing `tools` (csharp, go: `Tools`) returns a 400 error when the session’s effective `skills` (csharp, go: `Skills`) is non-empty, because skills require the `read` tool. Otherwise, setting `tools` (csharp, go: `Tools`) to `null` or to an empty array clears the field.
436 * Clearing `mcp_servers` (java, php: `mcpServers`; csharp: `McpServers`; go: `MCPServers`) returns a 400 error when the session’s effective `tools` (csharp, go: `Tools`) still contains an `mcp_toolset` that references one of the agent’s servers. Override `tools` (csharp, go: `Tools`) in the same request to remove those `mcp_toolset` entries, then clear `mcp_servers` (java, php: `mcpServers`; csharp: `McpServers`; go: `MCPServers`).
437437 
438* **Set the field to a value:** The value replaces the agent's value in full. Overrides never merge with the agent's configuration, so a `tools` (csharp, go: `Tools`) override must list every tool the session should have. Likewise, a `model` (csharp, go: `Model`) override replaces the agent's `model` (csharp, go: `Model`) object in full, so the agent's own `effort` (csharp, go: `Effort`) isn't carried over. To run the session at a specific effort level, set `effort` (csharp, go: `Effort`) inside the override's `model` (csharp, go: `Model`) object. A level the model doesn't support returns a 400 error, and a `model` (csharp, go: `Model`) override without `effort` (csharp, go: `Effort`) runs at that model's default effort level.
438* **Set the field to a value:** The value replaces the agent’s value in full. Overrides never merge with the agent’s configuration, so a `tools` (csharp, go: `Tools`) override must list every tool the session should have. Likewise, a `model` (csharp, go: `Model`) override replaces the agent’s `model` (csharp, go: `Model`) object in full, so the agent’s own `effort` (csharp, go: `Effort`) isn’t carried over. To run the session at a specific effort level, set `effort` (csharp, go: `Effort`) inside the override’s `model` (csharp, go: `Model`) object. A level the model doesn’t support returns a 400 error, and a `model` (csharp, go: `Model`) override without `effort` (csharp, go: `Effort`) runs at that model’s default effort level.
439439 
440440Overrides apply only to the session you create. They do not modify the agent resource or create a new agent version, so other sessions that reference the same agent are unaffected.
441441 
from line 600
600600 
601601#### Pin the inference geo for a session
602602 
603Because a `model` (csharp, go: `Model`) override replaces the agent's `model` (csharp, go: `Model`) object in full, it also sets or clears the model's [inference geo](https://platform.claude.com/docs/en/manage-claude/data-residency) pin for the session. An override that includes `inference_geo` (java, php: `inferenceGeo`; csharp, go: `InferenceGeo`) pins the geography that serves the session's model requests. An override that omits it clears the agent's pin, so the session follows the workspace's `default_inference_geo`. The overridden value is validated against the workspace's `allowed_inference_geos` when the session is created.
603Because a `model` (csharp, go: `Model`) override replaces the agent’s `model` (csharp, go: `Model`) object in full, it also sets or clears the model’s [inference geo](https://platform.claude.com/docs/en/manage-claude/data-residency) pin for the session. An override that includes `inference_geo` (java, php: `inferenceGeo`; csharp, go: `InferenceGeo`) pins the geography that serves the session’s model requests. An override that omits it clears the agent’s pin, so the session follows the workspace’s `default_inference_geo`. The overridden value is validated against the workspace’s `allowed_inference_geos` when the session is created.
604604 
605The following example starts a session from an agent whose model has no geo pin, and pins the session's model requests to US inference by including `inference_geo` (java, php: `inferenceGeo`; csharp, go: `InferenceGeo`) in the `model` (csharp, go: `Model`) override. The response echoes the value in `agent.model` (csharp, go: `Agent.Model`):
605The following example starts a session from an agent whose model has no geo pin, and pins the session’s model requests to US inference by including `inference_geo` (java, php: `inferenceGeo`; csharp, go: `InferenceGeo`) in the `model` (csharp, go: `Model`) override. The response echoes the value in `agent.model` (csharp, go: `Agent.Model`):
606606 
607607<CodeGroup>
608608 ```bash cURL
from line 749
749749 
750750### Set a session budget
751751 
752To cap what a session can spend, pass the optional `budget` (csharp, go: `Budget`) object when you create it. A budget is a hard ceiling on the session's list cost: the platform prices everything the session consumes at public list rates, and the session stops issuing new model requests once that running total reaches `max_list_cost` (java, php: `maxListCost`; csharp, go: `MaxListCost`). The budget's `type` (csharp, go: `Type`) is always `limit`. Give `max_list_cost` (java, php: `maxListCost`; csharp, go: `MaxListCost`) an `amount` (csharp, go: `Amount`) and a `currency` (csharp, go: `Currency`). `amount` (csharp, go: `Amount`) is a whole number of US cents written as a string, such as `"125"` for $1.25 USD. The API takes a string rather than a number so no floating-point rounding is ever applied. `USD` is the only currency currently supported. When the session reaches the cap, it pauses and goes idle with the stop reason `budget_reached`. The cap is enforced between model requests, so the request that crosses it completes first and the session's final list cost can land [a fraction past the cap](https://platform.claude.com/docs/en/managed-agents/budgets#when-a-session-reaches-its-budget). A budget can only be attached at creation: you can [change or remove the budget](https://platform.claude.com/docs/en/managed-agents/session-operations#updating-the-session-budget) later, but you can't add one to a session created without it.
752To cap what a session can spend, pass the optional `budget` (csharp, go: `Budget`) object when you create it. A budget is a hard ceiling on the session’s list cost: the platform prices everything the session consumes at public list rates, and the session stops issuing new model requests once that running total reaches `max_list_cost` (java, php: `maxListCost`; csharp, go: `MaxListCost`). The budget’s `type` (csharp, go: `Type`) is always `limit`. Give `max_list_cost` (java, php: `maxListCost`; csharp, go: `MaxListCost`) an `amount` (csharp, go: `Amount`) and a `currency` (csharp, go: `Currency`). `amount` (csharp, go: `Amount`) is a whole number of US cents written as a string, such as `"125"` for $1.25 USD. The API takes a string rather than a number so no floating-point rounding is ever applied. `USD` is the only currency currently supported. When the session reaches the cap, it pauses and goes idle with the stop reason `budget_reached`. The cap is enforced between model requests, so the request that crosses it completes first and the session’s final list cost can land [a fraction past the cap](https://platform.claude.com/docs/en/managed-agents/budgets#when-a-session-reaches-its-budget). A budget can only be attached at creation: you can [change or remove the budget](https://platform.claude.com/docs/en/managed-agents/session-operations#updating-the-session-budget) later, but you can’t add one to a session created without it.
753753 
754754The following example creates a session with a $1.25 USD budget:
755755 
from line 967
967967 
968968## Starting the session
969969 
970Creating a session without `initial_events` (java, php: `initialEvents`; csharp, go: `InitialEvents`) registers the session but does not start any work; the environment's sandbox starts provisioning as soon as the session is created, so the first tool call does not wait on it. To delegate a task, send events to the session using a [user event](https://platform.claude.com/docs/en/managed-agents/reference#event-types). To supply the first event in the create request instead, see [Seed the session with initial events](https://platform.claude.com/docs/en/managed-agents/sessions#seed-the-session-with-initial-events). The session acts as a state machine that tracks progress, and events drive the actual execution.
970Creating a session without `initial_events` (java, php: `initialEvents`; csharp, go: `InitialEvents`) registers the session but does not start any work; the environment’s sandbox starts provisioning as soon as the session is created, so the first tool call does not wait on it. To delegate a task, send events to the session using a [user event](https://platform.claude.com/docs/en/managed-agents/reference#event-types). To supply the first event in the create request instead, see [Seed the session with initial events](https://platform.claude.com/docs/en/managed-agents/sessions#seed-the-session-with-initial-events). The session acts as a state machine that tracks progress, and events drive the actual execution.
971971 
972972<CodeGroup>
973973 ```bash cURL
from line 1091
10911091 ```
10921092</CodeGroup>
10931093 
1094See [Session event stream](https://platform.claude.com/docs/en/managed-agents/events-and-streaming) for how to stream the agent's responses and handle tool confirmations.
1094See [Session event stream](https://platform.claude.com/docs/en/managed-agents/events-and-streaming) for how to stream the agent’s responses and handle tool confirmations.
10951095 
10961096See [Session statuses](https://platform.claude.com/docs/en/managed-agents/session-operations#session-statuses) for the statuses a session moves through.
10971097 

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

from line 10
1010 betaHeader: managed-agents-2026-04-01
1111---
1212 
13Skills are reusable, filesystem-based resources that give your agent domain-specific expertise: workflows, context, and best practices that turn a general-purpose agent into a specialist. Each skill you add incurs a modest cost on the session's context window, adding instructions and metadata that help the model use the skill. Learn more in the [Agent Skills](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview) overview.
13Skills are reusable, filesystem-based resources that give your agent domain-specific expertise: workflows, context, and best practices that turn a general-purpose agent into a specialist. Each skill you add incurs a modest cost on the session’s context window, adding instructions and metadata that help the model use the skill. Learn more in the [Agent Skills](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview) overview.
1414 
15Skills reach your agent in two ways: attach them through the agent's `skills` (csharp, go: `Skills`) array, or [load them from a GitHub repository](https://platform.claude.com/docs/en/managed-agents/skills#load-skills-from-a-github-repository) mounted on the session. Attached skills come in two types. All skills work the same way: your agent uses them automatically when they are relevant to the task.
15Skills reach your agent in two ways: attach them through the agent’s `skills` (csharp, go: `Skills`) array, or [load them from a GitHub repository](https://platform.claude.com/docs/en/managed-agents/skills#load-skills-from-a-github-repository) mounted on the session. Attached skills come in two types. All skills work the same way: your agent uses them automatically when they are relevant to the task.
1616 
1717* **Pre-built Anthropic skills:** Common document tasks such as PowerPoint, Excel, Word, and PDF handling (`pptx`, `xlsx`, `docx`, `pdf`).
1818* **Custom skills:** Skills you author and upload to your workspace.
from line 21
2121 
2222## Create a custom skill
2323 
24A 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).
24A 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).
2525 
26These examples omit the optional `display_name` (java, php: `displayName`; csharp, go: `DisplayName`) field, so the skill's display name is derived from the `name` field in `SKILL.md`. An explicit `display_name` (java, php: `displayName`; csharp, go: `DisplayName`) can be up to 255 characters and doesn't need to be unique within your workspace.
26These examples omit the optional `display_name` (java, php: `displayName`; csharp, go: `DisplayName`) field, so the skill’s display name is derived from the `name` field in `SKILL.md`. An explicit `display_name` (java, php: `displayName`; csharp, go: `DisplayName`) can be up to 255 characters and doesn’t need to be unique within your workspace.
2727 
2828<CodeGroup defaultLanguage="CLI">
2929 ```bash cURL
from line 51
5151 ```
5252 </File>
5353 
54 [`ant apply`](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/apply) uploads the `skills/pr-summary` directory, prints the new skill's ID, and records it in `claude-lock.json`. Commit `claude-lock.json` so the next `ant apply` uploads your edits as a new version instead of creating a second skill.
54 [`ant apply`](https://platform.claude.com/docs/en/cli-sdks-libraries/cli/apply) uploads the `skills/pr-summary` directory, prints the new skill’s ID, and records it in `claude-lock.json`. Commit `claude-lock.json` so the next `ant apply` uploads your edits as a new version instead of creating a second skill.
5555 </CodeGroupItem>
5656 
5757 ```python Python
from line 205
205205Attach skills when creating an agent. Each [session](https://platform.claude.com/docs/en/managed-agents/sessions) supports up to 500 skills, counted as the deduplicated set across every agent in the session (see [Multiagent orchestration](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration)).
206206 
207207<Note>
208 Mounting more skills increases the time it takes for the session's sandbox to start. Attach only the skills each agent needs for its task.
208 Mounting more skills increases the time it takes for the session’s sandbox to start. Attach only the skills each agent needs for its task.
209209</Note>
210210 
211211Each entry in the `skills` (csharp, go: `Skills`) array uses the following fields:
from line 382
382382 
383383## Load skills from a GitHub repository
384384 
385Skills can also live in your code base. When a session mounts a repository through the [`github_repository` resource](https://platform.claude.com/docs/en/managed-agents/github), the repository's root `.claude/skills` directory is scanned at session start, and each skill found there becomes available to the agent. No upload and no entry in the agent's `skills` (csharp, go: `Skills`) array are required. The agent receives each discovered skill's name, description, and path in the sandbox, and reads the skill's `SKILL.md` when a task matches, including any scripts and resources the skill ships. Discovery relies on the agent's `read` tool from the [agent toolset](https://platform.claude.com/docs/en/managed-agents/tools), which is enabled by default; an agent with `read` disabled doesn't load repository skills.
385Skills can also live in your code base. When a session mounts a repository through the [`github_repository` resource](https://platform.claude.com/docs/en/managed-agents/github), the repository’s root `.claude/skills` directory is scanned at session start, and each skill found there becomes available to the agent. No upload and no entry in the agent’s `skills` (csharp, go: `Skills`) array are required. The agent receives each discovered skill’s name, description, and path in the sandbox, and reads the skill’s `SKILL.md` when a task matches, including any scripts and resources the skill ships. Discovery relies on the agent’s `read` tool from the [agent toolset](https://platform.claude.com/docs/en/managed-agents/tools), which is enabled by default; an agent with `read` disabled doesn’t load repository skills.
386386 
387387<Warning>
388 Repository skills are agent instructions, so a mounted repository is part of your agent's trust boundary. Anyone who can commit to the repository (a merged external pull request, a compromised dependency, a contributor) can add or change a skill. The platform loads that skill at session start without a review step, and session tools such as `bash` and `web_fetch` give its instructions real reach. Mount only repositories you trust, and review `.claude/skills` before mounting a repository that accepts outside contributions.
388 Repository skills are agent instructions, so a mounted repository is part of your agent’s trust boundary. Anyone who can commit to the repository (a merged external pull request, a compromised dependency, a contributor) can add or change a skill. The platform loads that skill at session start without a review step, and session tools such as `bash` and `web_fetch` give its instructions real reach. Mount only repositories you trust, and review `.claude/skills` before mounting a repository that accepts outside contributions.
389389</Warning>
390390 
391391<Note>
392 Repository skill discovery runs in cloud sandboxes. [Self-hosted sandboxes](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes) don't support GitHub repository resources.
392 Repository skill discovery runs in cloud sandboxes. [Self-hosted sandboxes](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes) don’t support GitHub repository resources.
393393</Note>
394394 
395395Discovery finds skills at exactly `.claude/skills/<skill-name>/SKILL.md`, one directory level deep at the repository root:
from line 411
411411 
412412 * `src/`
413413 
414Locations that don't match this layout aren't discovered at session start:
414Locations that don’t match this layout aren’t discovered at session start:
415415 
416416* `.claude/skills/SKILL.md`: a `SKILL.md` with no skill directory around it
417417* `.claude/skills/tools/code-review/SKILL.md`: nested more than one directory level deep
418418* `skills/code-review/SKILL.md`: a `skills` directory outside `.claude`
419419 
420A `.claude/skills` directory elsewhere in the repository, such as inside a package subdirectory, isn't announced at session start; those skills can still surface when the agent reads files under that subtree.
420A `.claude/skills` directory elsewhere in the repository, such as inside a package subdirectory, isn’t announced at session start; those skills can still surface when the agent reads files under that subtree.
421421 
422422Repository skills use the same `SKILL.md` format as the custom skills you upload. For the format and authoring guidance, see [Agent Skills](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview) and [Skill authoring best practices](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/best-practices).
423423 
from line 567
567567 ```
568568</CodeGroup>
569569 
570For private repositories, the resource's `authorization_token` (java, php: `authorizationToken`; csharp, go: `AuthorizationToken`) must have access to the repository. This is the same personal access token flow used for any repository mount; see [Accessing GitHub](https://platform.claude.com/docs/en/managed-agents/github#token-permissions).
570For private repositories, the resource’s `authorization_token` (java, php: `authorizationToken`; csharp, go: `AuthorizationToken`) must have access to the repository. This is the same personal access token flow used for any repository mount; see [Accessing GitHub](https://platform.claude.com/docs/en/managed-agents/github#token-permissions).
571571 
572Discovered skills follow the checked-out state of the repository: the `checkout` (csharp, go: `Checkout`) branch or commit when the resource sets one, otherwise the repository's default branch. The scan runs once, when the session starts. Commits pushed mid-session are not picked up; to load updated skills, start a new session.
572Discovered skills follow the checked-out state of the repository: the `checkout` (csharp, go: `Checkout`) branch or commit when the resource sets one, otherwise the repository’s default branch. The scan runs once, when the session starts. Commits pushed mid-session are not picked up; to load updated skills, start a new session.
573573 
574Repository skills work alongside skills attached through the agent's `skills` (csharp, go: `Skills`) array. If a repository skill shares a name with an attached skill, or with a skill from another mounted repository, both are available; each is announced with its own path.
574Repository skills work alongside skills attached through the agent’s `skills` (csharp, go: `Skills`) array. If a repository skill shares a name with an attached skill, or with a skill from another mounted repository, both are available; each is announced with its own path.
575575 
576576## Next steps
577577 
from line 581
581581 </Card>
582582 
583583 <Card title="Using Agent Skills with the API" icon="code" href="https://platform.claude.com/docs/en/build-with-claude/skills-guide">
584 Learn how to use Agent Skills to extend Claude's capabilities through the API.
584 Learn how to use Agent Skills to extend Claude’s capabilities through the API.
585585 </Card>
586586 
587587 <Card title="Files API" icon="file" href="https://platform.claude.com/docs/en/build-with-claude/files">

managed-agents/tools Changed · +3 / -3 lines

from line 35
3535 
3636Enable the full toolset with `agent_toolset_20260401` when creating an agent. Use the `configs` (csharp, go: `Configs`) array to disable specific tools or override their settings. Each entry is identified by its `name` (csharp, go: `Name`), which takes a value from the Name column in [Available tools](https://platform.claude.com/docs/en/managed-agents/tools#available-tools). An entry also accepts an optional `type` (csharp, go: `Type`) field with the same value.
3737 
38Each config entry can also set a `permission_policy` (java, php: `permissionPolicy`; csharp, go: `PermissionPolicy`). The policy controls whether the tool's calls run without confirmation, require confirmation, or are evaluated individually by the server. See [Permission policies](https://platform.claude.com/docs/en/managed-agents/permission-policies) for the available policy types.
38Each config entry can also set a `permission_policy` (java, php: `permissionPolicy`; csharp, go: `PermissionPolicy`). The policy controls whether the tool’s calls run without confirmation, require confirmation, or are evaluated individually by the server. See [Permission policies](https://platform.claude.com/docs/en/managed-agents/permission-policies) for the available policy types.
3939 
4040The following example enables the toolset and disables `web_fetch`:
4141 
from line 473
473473 ```
474474</CodeGroup>
475475 
476A custom tool's name can't start with `mcp__` or `ant__`, or match the name of a built-in agent tool. A request that breaks this rule returns a 400 error. An agent that already has a custom tool whose name starts with `ant__` accepts an update only if the update sends `tools` (csharp, go: `Tools`) without that name, so rename or remove the tool in your next update. A new session is refused with a 400 error if such a tool is on its agent (after any [overrides](https://platform.claude.com/docs/en/managed-agents/sessions#override-agent-configuration-for-a-session)), on an agent in the `predefined_agents` (java, php: `predefinedAgents`; csharp, go: `PredefinedAgents`) list of `subagents` (csharp, go: `Subagents`), or on an agent in the `predefined_agents` (java, php: `predefinedAgents`; csharp, go: `PredefinedAgents`) list of `workflows` (csharp, go: `Workflows`). Sessions that already exist aren't affected.
476A custom tool’s name can’t start with `mcp__` or `ant__`, or match the name of a built-in agent tool. A request that breaks this rule returns a 400 error. An agent that already has a custom tool whose name starts with `ant__` accepts an update only if the update sends `tools` (csharp, go: `Tools`) without that name, so rename or remove the tool in your next update. A new session is refused with a 400 error if such a tool is on its agent (after any [overrides](https://platform.claude.com/docs/en/managed-agents/sessions#override-agent-configuration-for-a-session)), on an agent in the `predefined_agents` (java, php: `predefinedAgents`; csharp, go: `PredefinedAgents`) list of `subagents` (csharp, go: `Subagents`), or on an agent in the `predefined_agents` (java, php: `predefinedAgents`; csharp, go: `PredefinedAgents`) list of `workflows` (csharp, go: `Workflows`). Sessions that already exist aren’t affected.
477477 
478478The agent calls its custom tools during a session. To receive the calls and return results, see [Answer tool calls that pause the session](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#handling-custom-tool-calls).
479479 
from line 485
485485 
486486 * What the tool does
487487 * When to use it, and when not to
488 * What each parameter means and how it affects the tool's behavior
488 * What each parameter means and how it affects the tool’s behavior
489489 * Any important caveats or limitations
490490 
491491* **Consolidate related operations into fewer tools.** Group actions such as `create_pr`, `review_pr`, and `merge_pr` into a single tool with an `action` parameter. Fewer, more capable tools reduce selection ambiguity and make your tool surface easier for Claude to navigate.

managed-agents/tools-web-restrictions Changed · +22 / -22 lines

from line 10
1010 betaHeader: managed-agents-2026-04-01
1111---
1212 
13To control which sites the agent's web tools can reach, set a domain list on the `web_search` and `web_fetch` entries of the [agent toolset](https://platform.claude.com/docs/en/managed-agents/tools#configuring-the-toolset). Each of these `configs` (csharp, go: `Configs`) entries takes one of two lists:
13To control which sites the agent’s web tools can reach, set a domain list on the `web_search` and `web_fetch` entries of the [agent toolset](https://platform.claude.com/docs/en/managed-agents/tools#configuring-the-toolset). Each of these `configs` (csharp, go: `Configs`) entries takes one of two lists:
1414 
1515* **`allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`):** The tool can reach only these hosts.
1616* **`blocked_domains` (java, php: `blockedDomains`; csharp, go: `BlockedDomains`):** The tool can never reach these hosts.
from line 18
1818Each tool carries its own list, so `web_search` and `web_fetch` can have different restrictions.
1919 
2020<Note>
21 `web_search` and `web_fetch` run on Anthropic's servers, not in the sandbox. A cloud environment with `limited` [networking](https://platform.claude.com/docs/en/managed-agents/environments#networking) also applies its `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) to them; see [Set domain lists on an agent](https://platform.claude.com/docs/en/managed-agents/tools-web-restrictions#set-domain-lists-on-an-agent). `unrestricted` networking and self-hosted environments do not limit them. The per-tool lists restrict these tools further.
21 `web_search` and `web_fetch` run on Anthropic’s servers, not in the sandbox. A cloud environment with `limited` [networking](https://platform.claude.com/docs/en/managed-agents/environments#networking) also applies its `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) to them; see [Set domain lists on an agent](https://platform.claude.com/docs/en/managed-agents/tools-web-restrictions#set-domain-lists-on-an-agent). `unrestricted` networking and self-hosted environments do not limit them. The per-tool lists restrict these tools further.
2222</Note>
2323 
24Your organization's web search settings on the [**Capabilities**](https://platform.claude.com/settings/capabilities) page of the Claude Console also apply to `web_search` in a session. If an administrator disables web search, `web_search` calls return an error result to the agent, and the session continues. If the organization restricts web search domains, the agent receives only the search results that both the organization's domain restrictions and the agent's per-tool lists allow.
24Your organization’s web search settings on the [**Capabilities**](https://platform.claude.com/settings/capabilities) page of the Claude Console also apply to `web_search` in a session. If an administrator disables web search, `web_search` calls return an error result to the agent, and the session continues. If the organization restricts web search domains, the agent receives only the search results that both the organization’s domain restrictions and the agent’s per-tool lists allow.
2525 
26Your organization's web fetch settings on the same page also apply to `web_fetch` in a session. If an administrator turns off web fetch, `web_fetch` calls return an error result to the agent, and the session continues. If the organization sets allowed or blocked domains for web fetch, a URL must pass the organization's list and the agent's per-tool lists, and so must any URL a redirect leads to. A `web_fetch` call for a URL that any of them excludes also returns an error result to the agent.
26Your organization’s web fetch settings on the same page also apply to `web_fetch` in a session. If an administrator turns off web fetch, `web_fetch` calls return an error result to the agent, and the session continues. If the organization sets allowed or blocked domains for web fetch, a URL must pass the organization’s list and the agent’s per-tool lists, and so must any URL a redirect leads to. A `web_fetch` call for a URL that any of them excludes also returns an error result to the agent.
2727 
2828## Set domain lists on an agent
2929 
from line 366
366366 ```
367367</CodeGroup>
368368 
369In a cloud environment with `limited` [networking](https://platform.claude.com/docs/en/managed-agents/environments#networking), the environment's `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) also applies to `web_search` and `web_fetch`. Creating a session fails with a 400 error when an enabled web tool's `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) has an entry that is not within `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`). So does a session update that adds such an entry. To fix it, add the host to `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) or remove the entry from `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`). At runtime, a `web_fetch` call for a URL on a host that `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) does not match returns a `url_not_allowed` error result. `web_search` omits results from such hosts. The two lists match differently: a tool's entry covers its subdomains, but an `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) entry matches one exact host unless it starts with `*.`. For example, the tool entry `docs.example.com` is not within an `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) of `["example.com"]`, but it is within `["docs.example.com"]` or `["*.example.com"]`.
369In a cloud environment with `limited` [networking](https://platform.claude.com/docs/en/managed-agents/environments#networking), the environment’s `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) also applies to `web_search` and `web_fetch`. Creating a session fails with a 400 error when an enabled web tool’s `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) has an entry that is not within `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`). So does a session update that adds such an entry. To fix it, add the host to `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) or remove the entry from `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`). At runtime, a `web_fetch` call for a URL on a host that `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) does not match returns a `url_not_allowed` error result. `web_search` omits results from such hosts. The two lists match differently: a tool’s entry covers its subdomains, but an `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) entry matches one exact host unless it starts with `*.`. For example, the tool entry `docs.example.com` is not within an `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) of `["example.com"]`, but it is within `["docs.example.com"]` or `["*.example.com"]`.
370370 
371In 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.
371In 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.
372372 
373373## Settings
374374 
from line 414
414414| A port | `example.com:443` | `example.com` |
415415| A wildcard | `*.example.com` | `example.com` |
416416| A path on a `web_fetch` domain | `example.com/*` | `example.com` |
417| An IP address in any form, whether IPv4, IPv6, bracketed, or numeric shorthand | `127.1` | The site's domain name |
417| An IP address in any form, whether IPv4, IPv6, bracketed, or numeric shorthand | `127.1` | The site’s domain name |
418418| A bare top-level domain or registry suffix | `com`, `co.uk`, `gov.uk` | A full domain such as `example.co.uk` |
419419| A single-label name | `intranet` | A full domain such as `example.co.uk` |
420420| Non-ASCII characters, as in an internationalized domain name | | The `xn--` (Punycode) form |
from line 437
437437| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
438438| An entry sets both lists. | Includes `Only one of allowed_domains or blocked_domains may be set.` |
439439| A list is empty. | Includes `allowed_domains: Empty list of domains is ambiguous. Provide at least one domain or null.` |
440| A domain breaks a format rule. | Names the domain's list and zero-based position. For example, `allowed_domains.0: IP addresses are not supported; provide a plain hostname like "example.com"` |
440| A domain breaks a format rule. | Names the domain’s list and zero-based position. For example, `allowed_domains.0: IP addresses are not supported; provide a plain hostname like "example.com"` |
441441 
442442On the same requests, the API also rejects three settings that depend on the search and fetch providers:
443443 
444* A domain in `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) that Anthropic's crawler is not allowed to access.
444* A domain in `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) that Anthropic’s crawler is not allowed to access.
445445* 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`.
446446* A `user_location.timezone` that is not a valid IANA name.
447447 
448In a cloud environment with `limited` [networking](https://platform.claude.com/docs/en/managed-agents/environments#networking), session create and update also check `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) against the environment's `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`). See the rule in [Set domain lists on an agent](https://platform.claude.com/docs/en/managed-agents/tools-web-restrictions#set-domain-lists-on-an-agent).
448In a cloud environment with `limited` [networking](https://platform.claude.com/docs/en/managed-agents/environments#networking), session create and update also check `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) against the environment’s `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`). See the rule in [Set domain lists on an agent](https://platform.claude.com/docs/en/managed-agents/tools-web-restrictions#set-domain-lists-on-an-agent).
449449 
450450### When an accepted setting is no longer valid
451451 
from line 453
453453 
454454To continue the session:
455455 
4561. Fix the setting by [updating the session's tools](https://platform.claude.com/docs/en/managed-agents/session-operations#updating-the-agent-configuration).
4561. Fix the setting by [updating the session’s tools](https://platform.claude.com/docs/en/managed-agents/session-operations#updating-the-agent-configuration).
4574572. Update the agent as well, so that new sessions start with the corrected configuration.
4584583. Send a new `user.message`.
459459 
from line 471
471471| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
472472| `allowed_domains` | The tool can reach a host only if every list covers it. |
473473| `blocked_domains` | The lists add together. |
474| `max_content_tokens`, `user_location` | Not combined. A thread uses the value from its own tool configuration if set. Otherwise it uses the value from the agent that called it, and otherwise the current configuration of the session's agent. |
474| `max_content_tokens`, `user_location` | Not combined. A thread uses the value from its own tool configuration if set. Otherwise it uses the value from the agent that called it, and otherwise the current configuration of the session’s agent. |
475475 
476476A listed agent can therefore narrow what a tool reaches but never widen it:
477477 
478* A listed agent that sets `blocked_domains` (java, php: `blockedDomains`; csharp, go: `BlockedDomains`) keeps the `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) of the session's agent and blocks those hosts within it.
479* A listed agent that sets its own `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) can reach only the hosts that both its list and the list of the session's agent cover.
478* A listed agent that sets `blocked_domains` (java, php: `blockedDomains`; csharp, go: `BlockedDomains`) keeps the `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) of the session’s agent and blocks those hosts within it.
479* A listed agent that sets its own `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) can reach only the hosts that both its list and the list of the session’s agent cover.
480480 
481A `{"type": "self"}` entry in the `predefined_agents` (java, php: `predefinedAgents`; csharp, go: `PredefinedAgents`) list of `subagents` (csharp, go: `Subagents`) has no web settings of its own and follows the current settings of the session's agent.
481A `{"type": "self"}` entry in the `predefined_agents` (java, php: `predefinedAgents`; csharp, go: `PredefinedAgents`) list of `subagents` (csharp, go: `Subagents`) has no web settings of its own and follows the current settings of the session’s agent.
482482 
483If the combined `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) lists have no domain in common, the tool stays available to that agent, but every call fails. Each call returns a `url_not_allowed` error whose text includes `no domain is permitted`. The tool description tells the model the same. To avoid this, keep each listed agent's `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) inside the `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) of the session's agent.
483If the combined `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) lists have no domain in common, the tool stays available to that agent, but every call fails. Each call returns a `url_not_allowed` error whose text includes `no domain is permitted`. The tool description tells the model the same. To avoid this, keep each listed agent’s `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) inside the `allowed_domains` (java, php: `allowedDomains`; csharp, go: `AllowedDomains`) of the session’s agent.
484484 
485485The 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.
486486 
from line 488
488488 
489489You 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.
490490 
491In a multiagent session, every thread applies the new lists from its next turn. For an agent listed in the `predefined_agents` (java, php: `predefinedAgents`; csharp, go: `PredefinedAgents`) list of `subagents` (csharp, go: `Subagents`), the update does not change the agent's own lists. Those stay as the agent's definition set them when the session was created.
491In a multiagent session, every thread applies the new lists from its next turn. For an agent listed in the `predefined_agents` (java, php: `predefinedAgents`; csharp, go: `PredefinedAgents`) list of `subagents` (csharp, go: `Subagents`), the update does not change the agent’s own lists. Those stay as the agent’s definition set them when the session was created.
492492 
493493## Differences from the Messages API tools
494494 
from line 511
511511 </Card>
512512 
513513 <Card title="Cloud environment setup" icon="settings" href="https://platform.claude.com/docs/en/managed-agents/environments">
514 Control the sandbox's own outbound network access.
514 Control the sandbox’s own outbound network access.
515515 </Card>
516516 
517517 <Card title="Multiagent orchestration" icon="sitemap" href="https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration">

managed-agents/vaults Changed · +9 / -9 lines

from line 10
1010 betaHeader: managed-agents-2026-04-01
1111---
1212 
13Vaults and credentials are authentication primitives that let you register credentials for third-party services once and reference them by ID at session creation. This means you don't need to run your own secret store, transmit tokens on every call, or lose track of which end user an agent acted on behalf of.
13Vaults and credentials are authentication primitives that let you register credentials for third-party services once and reference them by ID at session creation. This means you don’t need to run your own secret store, transmit tokens on every call, or lose track of which end user an agent acted on behalf of.
1414 
1515The vault reference is a per-session parameter, so you can manage your product at the `agent` resource granularity and your users at the `session` resource granularity.
1616 
from line 359
359359 ```
360360 </CodeGroup>
361361 
362 Set `refresh.token_endpoint` (java, php: `refresh.tokenEndpoint`; csharp, go: `Refresh.TokenEndpoint`) to the token endpoint of the OAuth flow that issued the refresh token, because Anthropic sends every refresh request to that URL and the field can't be changed after the credential is created.
362 Set `refresh.token_endpoint` (java, php: `refresh.tokenEndpoint`; csharp, go: `Refresh.TokenEndpoint`) to the token endpoint of the OAuth flow that issued the refresh token, because Anthropic sends every refresh request to that URL and the field can’t be changed after the credential is created.
363363 </Tab>
364364 
365365 <Tab title="MCP static bearer">
from line 483
483483 <Tab title="Environment variable">
484484 Use `environment_variable` to authenticate to external services through an environment variable, such as CLIs, SDKs, or direct API calls. Environment variable credentials work for clients that send the secret value verbatim in an outbound request, so check the client eligibility criteria in this tab before configuring one.
485485 
486 The `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) array in `networking` (csharp, go: `Networking`) controls which outbound hosts the secret can be substituted for. Use `"type": "limited"` with a specific list, or `"type": "unrestricted"` if the caller reaches domains you can't enumerate in advance.
486 The `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) array in `networking` (csharp, go: `Networking`) controls which outbound hosts the secret can be substituted for. Use `"type": "limited"` with a specific list, or `"type": "unrestricted"` if the caller reaches domains you can’t enumerate in advance.
487487 
488488 Limiting domains is strongly recommended for security purposes, and prevents your key from ever being shared with unauthorized hosts.
489489 
from line 685
685685 
686686 Request payloads are often assembled from content the agent is working with, so the request body is the broader exposure surface. Most services read an API key from a request header, so enabling only `header` (csharp, go: `Header`) is the narrower configuration. It scopes substitution to request header values for that credential.
687687 
688 The credential's `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) controls which parts of an outbound request the secret is substituted into. It is an optional object, a sibling of `networking` (csharp, go: `Networking`), with two Boolean fields: `header` (csharp, go: `Header`) (request headers) and `body` (csharp, go: `Body`) (request body). `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) is independent of `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) in `networking` (csharp, go: `Networking`): `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) scopes which hosts the secret is substituted for, and `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) scopes which parts of the request it is substituted into.
688 The credential’s `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) controls which parts of an outbound request the secret is substituted into. It is an optional object, a sibling of `networking` (csharp, go: `Networking`), with two Boolean fields: `header` (csharp, go: `Header`) (request headers) and `body` (csharp, go: `Body`) (request body). `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) is independent of `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) in `networking` (csharp, go: `Networking`): `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) scopes which hosts the secret is substituted for, and `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) scopes which parts of the request it is substituted into.
689689 
690690 `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) behaves differently on create and on update:
691691 
from line 694
694694 | Create credential | If you provide the object, any field you omit inside it defaults to `false`: `{"header": true}` creates a header-only credential. Omit the object entirely and both locations are enabled. |
695695 | Update credential | Fields merge individually: `{"body": false}` disables body substitution and leaves `header` unchanged. |
696696 
697 A credential must have at least one location enabled, so a create or update that would disable both locations returns a 400 error. Passing an explicit `null` for the `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) object or for either field also returns a 400 error ("omit the field instead"). The response always returns both fields with their resolved values.
697 A credential must have at least one location enabled, so a create or update that would disable both locations returns a 400 error. Passing an explicit `null` for the `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) object or for either field also returns a 400 error (“omit the field instead”). The response always returns both fields with their resolved values.
698698 
699 A placeholder in a disabled location is neither substituted nor stripped. The request is sent to the third party with the literal opaque placeholder string in that location. If a request arrives at the third party containing the literal placeholder string, either that location is disabled for the credential or the destination host is not covered by the `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) in the credential's `networking` (csharp, go: `Networking`).
699 A placeholder in a disabled location is neither substituted nor stripped. The request is sent to the third party with the literal opaque placeholder string in that location. If a request arrives at the third party containing the literal placeholder string, either that location is disabled for the credential or the destination host is not covered by the `allowed_hosts` (java, php: `allowedHosts`; csharp, go: `AllowedHosts`) in the credential’s `networking` (csharp, go: `Networking`).
700700 
701701 <Note>
702702 Credentials created in the Claude Console enable header injection only. If your client sends the secret in the request body, such as a form-encoded token request, the placeholder passes through literally and the service rejects it with its own authentication error. Enable body injection in the Console form when you create the credential, or update the credential with `{"injection_location": {"body": true}}`.
703703 </Note>
704704 
705 The substitution occurs at egress, not inside the sandbox. Anything that processes the credential locally sees the opaque placeholder, not the real value: clients that validate the credential format at startup might reject it, and clients that compute a request signature from the secret (for example, AWS SigV4) produce an invalid signature. Environment variable credentials work for clients that send the secret value verbatim in an outbound request, in a location the credential's `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) enables.
705 The substitution occurs at egress, not inside the sandbox. Anything that processes the credential locally sees the opaque placeholder, not the real value: clients that validate the credential format at startup might reject it, and clients that compute a request signature from the secret (for example, AWS SigV4) produce an invalid signature. Environment variable credentials work for clients that send the secret value verbatim in an outbound request, in a location the credential’s `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) enables.
706706 
707707 Substitution is outbound only. If a client uses the stored secret to fetch a session token (for example, an OAuth client-credentials grant), the returned token arrives in the sandbox unredacted. For exchange-based flows, perform the exchange yourself and store the resulting token in the vault instead.
708708 
from line 825
825825 
826826## Rotate a credential
827827 
828Secret values, `display_name` (java, php: `displayName`; csharp, go: `DisplayName`), and (on environment variable credentials) `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) can be updated. `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) updates merge field by field, as described in the **Environment variable** tab of [Add a credential](https://platform.claude.com/docs/en/managed-agents/vaults#add-a-credential). For a running session, an `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) update takes effect the same way as a secret rotation: the session's credentials are re-resolved without a restart, as described in [Credential lifecycle](https://platform.claude.com/docs/en/managed-agents/vaults#credential-lifecycle), and the updated locations apply to the session's subsequent outbound requests. Structural fields (`mcp_server_url` (java: `mcpServerUrl`; php: `mcpServerURL`; csharp: `McpServerUrl`; go: `MCPServerURL`), `secret_name` (java, php: `secretName`; csharp, go: `SecretName`), `token_endpoint` (java, php: `tokenEndpoint`; csharp, go: `TokenEndpoint`), `client_id` (java: `clientId`; php: `clientID`; csharp, go: `ClientID`)) are locked after creation. To change them, archive the credential and create a new one.
828Secret values, `display_name` (java, php: `displayName`; csharp, go: `DisplayName`), and (on environment variable credentials) `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) can be updated. `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) updates merge field by field, as described in the **Environment variable** tab of [Add a credential](https://platform.claude.com/docs/en/managed-agents/vaults#add-a-credential). For a running session, an `injection_location` (java, php: `injectionLocation`; csharp, go: `InjectionLocation`) update takes effect the same way as a secret rotation: the session’s credentials are re-resolved without a restart, as described in [Credential lifecycle](https://platform.claude.com/docs/en/managed-agents/vaults#credential-lifecycle), and the updated locations apply to the session’s subsequent outbound requests. Structural fields (`mcp_server_url` (java: `mcpServerUrl`; php: `mcpServerURL`; csharp: `McpServerUrl`; go: `MCPServerURL`), `secret_name` (java, php: `secretName`; csharp, go: `SecretName`), `token_endpoint` (java, php: `tokenEndpoint`; csharp, go: `TokenEndpoint`), `client_id` (java: `clientId`; php: `clientID`; csharp, go: `ClientID`)) are locked after creation. To change them, archive the credential and create a new one.
829829 
830830<CodeGroup>
831831 ```bash cURL

managed-agents/webhooks Changed · +23 / -23 lines

from line 18
1818 
1919<Tabs>
2020 <Tab title="Session events">
21 Some of these events are named differently from the matching events on the session's [event stream](https://platform.claude.com/docs/en/managed-agents/events-and-streaming). For example, the stream's `session.status_idle` and `session.status_running` correspond to the `session.status_idled` and `session.status_run_started` webhook events.
21 Some of these events are named differently from the matching events on the session’s [event stream](https://platform.claude.com/docs/en/managed-agents/events-and-streaming). For example, the stream’s `session.status_idle` and `session.status_running` correspond to the `session.status_idled` and `session.status_run_started` webhook events.
2222 
2323 | Event | Trigger |
2424 | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
from line 27
2727 | `session.budget_reached` | The session reached its [budget](https://platform.claude.com/docs/en/managed-agents/budgets) and paused. Fires at most once for each budget value you set; changing the budget arms it again. |
2828 | `session.status_rescheduled` | A transient error occurred and the session is retrying automatically. |
2929 | `session.status_terminated` | The session terminated, either because of an unrecoverable error or because it was archived. |
30 | `session.thread_created` | New [multiagent thread](https://platform.claude.com/docs/en/managed-agents/session-threads) opened: an additional agent called by the agent that the session runs is starting work, or the session's [advisor](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#give-the-session-an-advisor) is being consulted. It also fires for each thread of a [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs#a-runs-threads), and so do the other two thread events in this table. |
30 | `session.thread_created` | New [multiagent thread](https://platform.claude.com/docs/en/managed-agents/session-threads) opened: an additional agent called by the agent that the session runs is starting work, or the session’s [advisor](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#give-the-session-an-advisor) is being consulted. It also fires for each thread of a [workflow run](https://platform.claude.com/docs/en/managed-agents/workflow-runs#a-runs-threads), and so do the other two thread events in this table. |
3131 | `session.thread_idled` | An agent in a [multiagent interaction](https://platform.claude.com/docs/en/managed-agents/session-threads) is waiting for input. |
32 | `session.thread_terminated` | A [multiagent thread](https://platform.claude.com/docs/en/managed-agents/session-threads) terminated, either because the thread was archived or because it exhausted its retries. A subagent that finishes its work goes `idle`, not `terminated` (an advisor thread terminates once its consultation completes, and a workflow run's threads terminate when the server archives them, by the end of the run). Fires for child threads only; the primary thread's end, including archiving the whole session, surfaces only as `session.status_terminated`. |
32 | `session.thread_terminated` | A [multiagent thread](https://platform.claude.com/docs/en/managed-agents/session-threads) terminated, either because the thread was archived or because it exhausted its retries. A subagent that finishes its work goes `idle`, not `terminated` (an advisor thread terminates once its consultation completes, and a workflow run’s threads terminate when the server archives them, by the end of the run). Fires for child threads only; the primary thread’s end, including archiving the whole session, surfaces only as `session.status_terminated`. |
3333 | `session.outcome_evaluation_ended` | [Outcome evaluation](https://platform.claude.com/docs/en/managed-agents/define-outcomes) for a single iteration completed. |
3434 | `session.updated` | Session properties changed (for example, its name or configuration was updated). |
3535 | `session.deleted` | Session permanently deleted. There is no object left to fetch, so treat the event itself as final. |
from line 48
4848 </Tab>
4949 
5050 <Tab title="Agent events">
51 These events track the lifecycle of the agent resources in your workspace, and are distinct from the agent events delivered on a session's event stream.
51 These events track the lifecycle of the agent resources in your workspace, and are distinct from the agent events delivered on a session’s event stream.
5252 
5353 | Event | Trigger |
5454 | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
from line 63
6363 | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
6464 | `deployment.created` | [Scheduled deployment](https://platform.claude.com/docs/en/managed-agents/scheduled-deployments) created. |
6565 | `deployment.updated` | Deployment properties changed (for example, its schedule was updated). |
66 | `deployment.paused` | Deployment paused, either by request or automatically when a scheduled run fails with an unrecoverable error, such as an archived subagent or an archived environment. Recoverable failures, including rate limits, don't pause the deployment. See [Failure behavior](https://platform.claude.com/docs/en/managed-agents/scheduled-deployments#failure-behavior). |
66 | `deployment.paused` | Deployment paused, either by request or automatically when a scheduled run fails with an unrecoverable error, such as an archived subagent or an archived environment. Recoverable failures, including rate limits, don’t pause the deployment. See [Failure behavior](https://platform.claude.com/docs/en/managed-agents/scheduled-deployments#failure-behavior). |
6767 | `deployment.unpaused` | Deployment unpaused, resuming its schedule. |
6868 | `deployment.archived` | Deployment archived, either directly or because its agent was archived. If the agent is deleted instead, a scheduled deployment is archived at its next scheduled run; a deployment without a schedule is not archived automatically. |
6969 | `deployment.deleted` | Deployment permanently deleted. There is no object left to fetch, so treat the event itself as final. |
from line 73
7373 | Event | Trigger |
7474 | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
7575 | `deployment_run.started` | A scheduled run started. Only scheduled runs emit `deployment_run` events; [manual runs](https://platform.claude.com/docs/en/managed-agents/scheduled-deployments#trigger-a-manual-run) do not. |
76 | `deployment_run.succeeded` | A scheduled run created its session. The event carries the same `data.id` (the run ID) as the run's `deployment_run.started` event. To follow the session's work, subscribe to its session events (the **Session events** tab), or fetch the [deployment run](https://platform.claude.com/docs/en/managed-agents/scheduled-deployments#deployment-runs) for its `session_id` (java: `sessionId`; php: `sessionID`; csharp, go: `SessionID`). |
77 | `deployment_run.failed` | A scheduled run did not create a session. The event carries the same `data.id` as the run's `deployment_run.started` event. Fetch the [deployment run](https://platform.claude.com/docs/en/managed-agents/scheduled-deployments#deployment-runs) for the error details. |
76 | `deployment_run.succeeded` | A scheduled run created its session. The event carries the same `data.id` (the run ID) as the run’s `deployment_run.started` event. To follow the session’s work, subscribe to its session events (the **Session events** tab), or fetch the [deployment run](https://platform.claude.com/docs/en/managed-agents/scheduled-deployments#deployment-runs) for its `session_id` (java: `sessionId`; php: `sessionID`; csharp, go: `SessionID`). |
77 | `deployment_run.failed` | A scheduled run did not create a session. The event carries the same `data.id` as the run’s `deployment_run.started` event. Fetch the [deployment run](https://platform.claude.com/docs/en/managed-agents/scheduled-deployments#deployment-runs) for the error details. |
7878 </Tab>
7979 
8080 <Tab title="Environment events">
from line 85
8585 | `environment.archived` | Environment archived. Re-archiving an already-archived environment emits nothing. |
8686 | `environment.deleted` | Environment deleted, including delete of an already-archived environment. There is no object left to fetch, so treat the event itself as final. |
8787 
88 An environment's [work items](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes) emit no webhook events.
88 An environment’s [work items](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes) emit no webhook events.
8989 </Tab>
9090 
9191 <Tab title="Memory store events">
from line 106
106106A webhook endpoint consists of:
107107 
108108* **URL:** Must be HTTPS on port 443 with a publicly resolvable hostname.
109* **Event types:** The list of `data.type` values this endpoint receives. An endpoint only receives events it's subscribed to.
110* **Signing secret:** A 32-byte `whsec_`-prefixed secret generated at creation. It's shown only once, so store it securely to verify webhook deliveries.
109* **Event types:** The list of `data.type` values this endpoint receives. An endpoint only receives events it’s subscribed to.
110* **Signing secret:** A 32-byte `whsec_`-prefixed secret generated at creation. It’s shown only once, so store it securely to verify webhook deliveries.
111111 
112112## Verify the signature
113113 
114Every delivery carries the `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers. Use the SDK's `unwrap()` (csharp, go: `Unwrap()`) helper to verify the signature and parse the event in one step. It throws if the signature is invalid or the payload is more than 5 minutes old.
114Every delivery carries the `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers. Use the SDK’s `unwrap()` (csharp, go: `Unwrap()`) helper to verify the signature and parse the event in one step. It throws if the signature is invalid or the payload is more than 5 minutes old.
115115 
116116Set `ANTHROPIC_WEBHOOK_SIGNING_KEY` to the `whsec_`-prefixed secret shown at endpoint creation.
117117 
from line 419
419419 ```
420420</CodeGroup>
421421 
422The top-level `event.id` is unique for each event, not for each delivery. If you receive the same `event.id` twice, it's a retry and you can discard it.
422The top-level `event.id` is unique for each event, not for each delivery. If you receive the same `event.id` twice, it’s a retry and you can discard it.
423423 
424424## Delivery behavior
425425 
426426* **Duplicates:** An endpoint can receive the same event more than once, and every attempt delivers the same top-level `event.id` (the same value as the `webhook-id` header). Deduplicate on it.
427427 
428* **Subscription scope:** An event is delivered only to endpoints subscribed to its type at the moment it's emitted. An event emitted while no endpoint is subscribed to its type is never delivered, and subscribing later doesn't backfill it, so subscribe to an event type before you need it.
428* **Subscription scope:** An event is delivered only to endpoints subscribed to its type at the moment it’s emitted. An event emitted while no endpoint is subscribed to its type is never delivered, and subscribing later doesn’t backfill it, so subscribe to an event type before you need it.
429429 
430* **Ordering:** Events aren't guaranteed to be delivered in the order they occurred: `session.status_idled` might arrive before `session.outcome_evaluation_ended` even if the outcome was produced first, and a `.deleted` event can arrive before the `.archived` event for the same resource. Drive your state from the resource you fetch, not from the order events arrive in.
430* **Ordering:** Events aren’t guaranteed to be delivered in the order they occurred: `session.status_idled` might arrive before `session.outcome_evaluation_ended` even if the outcome was produced first, and a `.deleted` event can arrive before the `.archived` event for the same resource. Drive your state from the resource you fetch, not from the order events arrive in.
431431 
432* **Retries:** For each endpoint and event, Anthropic makes up to three delivery attempts (a response that triggers auto-disable, described later in this section, is never retried) with jittered exponential backoff between 5 and 120 seconds. Every attempt delivers the same `event.id`. After the last attempt fails, the event is dropped: it isn't queued for later delivery and there's no signal that it was lost. Webhooks aren't a durable log, so if you need to observe every transition, reconcile by listing or fetching the resource through the API.
432* **Retries:** For each endpoint and event, Anthropic makes up to three delivery attempts (a response that triggers auto-disable, described later in this section, is never retried) with jittered exponential backoff between 5 and 120 seconds. Every attempt delivers the same `event.id`. After the last attempt fails, the event is dropped: it isn’t queued for later delivery and there’s no signal that it was lost. Webhooks aren’t a durable log, so if you need to observe every transition, reconcile by listing or fetching the resource through the API.
433433 
434* **Timestamps:** The `webhook-timestamp` header is stamped when a delivery attempt is signed and is regenerated on every retry, so retries aren't rejected by the SDK's freshness check. It's the clock for the delivery attempt, not for the event: use the event payload's `created_at` (java, php: `createdAt`; csharp, go: `CreatedAt`) for when the event occurred.
434* **Timestamps:** The `webhook-timestamp` header is stamped when a delivery attempt is signed and is regenerated on every retry, so retries aren’t rejected by the SDK’s freshness check. It’s the clock for the delivery attempt, not for the event: use the event payload’s `created_at` (java, php: `createdAt`; csharp, go: `CreatedAt`) for when the event occurred.
435435 
436436* **Auto-disable:** An endpoint is automatically set to `disabled` with a machine-readable `disabled_reason` in three cases:
437437 
438438 * The endpoint returns a `3xx` response. Redirects are never followed; this disables the endpoint immediately, on the first attempt, with the reason `auto-disabled: endpoint URL returned a redirect (3xx)`. If your endpoint moves, update the URL in Console and re-enable the endpoint.
439 * The endpoint's URL resolves to a non-public IP address when Anthropic connects. This disables the endpoint immediately, with the reason `auto-disabled: endpoint URL resolved to an invalid address`.
440 * Deliveries to the endpoint fail continuously for a sustained period, with the reason `auto-disabled after sustained delivery failures`. The trigger is how long the endpoint has been failing without interruption, not a delivery count. A single `2xx` resets the window, so one event that fails intermittently can't disable the endpoint.
439 * The endpoint’s URL resolves to a non-public IP address when Anthropic connects. This disables the endpoint immediately, with the reason `auto-disabled: endpoint URL resolved to an invalid address`.
440 * Deliveries to the endpoint fail continuously for a sustained period, with the reason `auto-disabled after sustained delivery failures`. The trigger is how long the endpoint has been failing without interruption, not a delivery count. A single `2xx` resets the window, so one event that fails intermittently can’t disable the endpoint.
441441 
442 All three are reversible: re-enable the endpoint in Console after you resolve the issue. Events emitted while the endpoint was disabled aren't replayed.
442 All three are reversible: re-enable the endpoint in Console after you resolve the issue. Events emitted while the endpoint was disabled aren’t replayed.
443443 

managed-agents/workflow-runs Changed · +80 / -80 lines

## A run’s threads ## A run's threads

from line 10
1010 betaHeader: managed-agents-2026-04-01
1111---
1212 
13A **workflow** is a program that an agent writes to run many agents and combine what they return. A **workflow run** is the execution of one workflow. **[Dynamic workflows](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#dynamic-workflows)** is the feature that lets an agent write workflows and start runs. You turn it on or off with the `workflows` (csharp, go: `Workflows`) setting in the agent's `multiagent` (csharp, go: `Multiagent`) block.
13A **workflow** is a program that an agent writes to run many agents and combine what they return. A **workflow run** is the execution of one workflow. **[Dynamic workflows](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#dynamic-workflows)** is the feature that lets an agent write workflows and start runs. You turn it on or off with the `workflows` (csharp, go: `Workflows`) setting in the agent’s `multiagent` (csharp, go: `Multiagent`) block.
1414 
15The server runs a workflow in the background. Its agents work in [session threads](https://platform.claude.com/docs/en/managed-agents/session-threads) that the server creates as the workflow needs them. You follow runs on the session's [event stream](https://platform.claude.com/docs/en/managed-agents/events-and-streaming). To stop a run, ask the agent to stop it (see [Interrupt a session with runs open](https://platform.claude.com/docs/en/managed-agents/workflow-runs#interrupt-a-session-with-runs-open)).
15The server runs a workflow in the background. Its agents work in [session threads](https://platform.claude.com/docs/en/managed-agents/session-threads) that the server creates as the workflow needs them. You follow runs on the session’s [event stream](https://platform.claude.com/docs/en/managed-agents/events-and-streaming). To stop a run, ask the agent to stop it (see [Interrupt a session with runs open](https://platform.claude.com/docs/en/managed-agents/workflow-runs#interrupt-a-session-with-runs-open)).
1616 
1717## How dynamic workflows work
1818 
from line 25
2525The diagram shows one example. Each workflow that the agent writes has its own phases and agents. A run has these layers:
2626 
2727* **Workflow run:** The server runs the workflow in the background, as one workflow run. A session can have several runs open at the same time.
28* **Phases:** A workflow can divide its work into phases. A phase is a named stage of the run, such as "Read the contracts." You follow a run's progress by its phase events.
29* **Agent threads:** In a phase, the program runs agents. Each agent works in its own [session thread](https://platform.claude.com/docs/en/managed-agents/session-threads), on a prompt that the program wrote. An agent in a run can be an inline agent, which the program defines itself, or a [predefined agent](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#predefined-and-inline-agents), which you list in the `predefined_agents` (java, php: `predefinedAgents`; csharp, go: `PredefinedAgents`) list of `workflows` (csharp, go: `Workflows`). For what each thread shows, see [A run's threads](https://platform.claude.com/docs/en/managed-agents/workflow-runs#a-runs-threads).
28* **Phases:** A workflow can divide its work into phases. A phase is a named stage of the run, such as “Read the contracts.” You follow a run’s progress by its phase events.
29* **Agent threads:** In a phase, the program runs agents. Each agent works in its own [session thread](https://platform.claude.com/docs/en/managed-agents/session-threads), on a prompt that the program wrote. An agent in a run can be an inline agent, which the program defines itself, or a [predefined agent](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#predefined-and-inline-agents), which you list in the `predefined_agents` (java, php: `predefinedAgents`; csharp, go: `PredefinedAgents`) list of `workflows` (csharp, go: `Workflows`). For what each thread shows, see [A run’s threads](https://platform.claude.com/docs/en/managed-agents/workflow-runs#a-runs-threads).
3030 
3131The program can do the following:
3232 
3333* **Run agents at the same time:** The program can run many agents at the same time, which is called fanning out. In the diagram, three agents read contracts in the first phase.
34* **Pass results from one agent to another:** Each agent returns its result to the program. The program can pass that result on to another agent. In the diagram, the agent in the second phase works with what the first three returned. A run's agents also work with the same files, in the session's sandbox.
35* **Take the next step by itself:** An agent's result goes to the program, not to the agent that the session runs. The program determines which agents run next, and it writes their prompts.
34* **Pass results from one agent to another:** Each agent returns its result to the program. The program can pass that result on to another agent. In the diagram, the agent in the second phase works with what the first three returned. A run’s agents also work with the same files, in the session’s sandbox.
35* **Take the next step by itself:** An agent’s result goes to the program, not to the agent that the session runs. The program determines which agents run next, and it writes their prompts.
3636* **Repeat and choose:** Inside a phase, the program can repeat work and choose its next step from what an agent returned. For example, it can have a draft revised until a review passes or a set number of rounds is used up. In the diagram, the program can repeat a step inside the second phase.
37* **Handle a failed agent:** When one of its agents fails, the server usually runs that agent once more, on a new thread, while the run's other agents keep working. If it fails again, the program can handle the failure or let it end the run. If the program handles a failure, the run can still end `completed`, so tell the agent that the session runs to report what failed.
37* **Handle a failed agent:** When one of its agents fails, the server usually runs that agent once more, on a new thread, while the run’s other agents keep working. If it fails again, the program can handle the failure or let it end the run. If the program handles a failure, the run can still end `completed`, so tell the agent that the session runs to report what failed.
3838 
39When the run ends, the agent that the session runs gets a turn to read what the run did. It can then answer you or start another run. [Run events](https://platform.claude.com/docs/en/managed-agents/workflow-runs#run-events) lists the cases where that turn comes later or doesn't come.
39When the run ends, the agent that the session runs gets a turn to read what the run did. It can then answer you or start another run. [Run events](https://platform.claude.com/docs/en/managed-agents/workflow-runs#run-events) lists the cases where that turn comes later or doesn’t come.
4040 
4141You can guide how a run does the work, for example how it splits the work and what it does when an agent fails. See [Tell the agent when to use a run](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#tell-the-agent-when-to-use-a-run).
4242 
43There's no approval step before a run starts: the agent starts a run in the same turn that it writes the workflow. To review a plan first, tell the agent to describe the run and wait for your approval. As a run starts, `workflow_run.created` shows its name, description, and phases. If a run starts that you didn't approve, ask the agent to stop it (see [Interrupt a session with runs open](https://platform.claude.com/docs/en/managed-agents/workflow-runs#interrupt-a-session-with-runs-open)).
43There’s no approval step before a run starts: the agent starts a run in the same turn that it writes the workflow. To review a plan first, tell the agent to describe the run and wait for your approval. As a run starts, `workflow_run.created` shows its name, description, and phases. If a run starts that you didn’t approve, ask the agent to stop it (see [Interrupt a session with runs open](https://platform.claude.com/docs/en/managed-agents/workflow-runs#interrupt-a-session-with-runs-open)).
4444 
4545## How a run moves through its states
4646 
from line 50
5050 
5151A run starts as running or as idle. Reaching the budget, for example, pauses a running run, which makes it idle; raising or removing the budget then makes it run again, unless an interrupt paused it too. A running run ends when its workflow completes, the agent stops it, it fails, its lifetime passes, or the session is archived. An idle run can end too, for example when the agent stops it or the session is archived.
5252 
53A run is **open** from its `workflow_run.created` event until its `workflow_run.status_ended` event, whether it's running or idle. A run is idle while it's paused, for example at the session's budget. A run has a [lifetime](https://platform.claude.com/docs/en/managed-agents/workflow-runs#limits), which the agent can set when it starts the run. Time that a run spends waiting on your client counts toward that lifetime. A pause doesn't stop a run's lifetime from passing, so a run that stays paused can end with `timeout_error`. The following events report a run's start, its phases, and its end. A pause at the budget sends one too. A pause after an interrupt might send none. Every `workflow_run.*` event includes `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`), which is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) only on a `workflow_run.error` when no run was created.
53A run is **open** from its `workflow_run.created` event until its `workflow_run.status_ended` event, whether it’s running or idle. A run is idle while it’s paused, for example at the session’s budget. A run has a [lifetime](https://platform.claude.com/docs/en/managed-agents/workflow-runs#limits), which the agent can set when it starts the run. Time that a run spends waiting on your client counts toward that lifetime. A pause doesn’t stop a run’s lifetime from passing, so a run that stays paused can end with `timeout_error`. The following events report a run’s start, its phases, and its end. A pause at the budget sends one too. A pause after an interrupt might send none. Every `workflow_run.*` event includes `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`), which is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) only on a `workflow_run.error` when no run was created.
5454 
5555## Run events
5656 
57Run events arrive on the session's event stream, which is the primary thread's stream, and listing the session's events returns them too. Run events don't trigger [webhooks](https://platform.claude.com/docs/en/managed-agents/webhooks). Status events from the run's threads arrive on the same stream. Each names its thread in `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`), and a run's threads are the ones whose `session.thread_created` event had the run's `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`).
57Run events arrive on the session’s event stream, which is the primary thread’s stream, and listing the session’s events returns them too. Run events don’t trigger [webhooks](https://platform.claude.com/docs/en/managed-agents/webhooks). Status events from the run’s threads arrive on the same stream. Each names its thread in `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`), and a run’s threads are the ones whose `session.thread_created` event had the run’s `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`).
5858 
5959| Event | When it arrives | What to do |
6060| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
61| `workflow_run.created` | The agent started a run. Includes `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) (`wrun_…`), the run's `name` (csharp, go: `Name`) and `description` (csharp, go: `Description`), and `phases` (csharp, go: `Phases`), the phases the workflow declares, each with an `id` (csharp, go: `ID`), a `name` (csharp, go: `Name`), and a `description` (csharp, go: `Description`). A `description` (csharp, go: `Description`) is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) when the workflow gives none. `phases` (csharp, go: `Phases`) is always present and can be empty. The run's and phases' `name` (csharp, go: `Name`) and `description` (csharp, go: `Description`) are text the model wrote, so they can repeat words from your request. A run's `name` (csharp, go: `Name`) can also be one the server assigned. | Track the run as open. Show its `name` (csharp, go: `Name`), and progress against `phases` (csharp, go: `Phases`). |
61| `workflow_run.created` | The agent started a run. Includes `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) (`wrun_…`), the run’s `name` (csharp, go: `Name`) and `description` (csharp, go: `Description`), and `phases` (csharp, go: `Phases`), the phases the workflow declares, each with an `id` (csharp, go: `ID`), a `name` (csharp, go: `Name`), and a `description` (csharp, go: `Description`). A `description` (csharp, go: `Description`) is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) when the workflow gives none. `phases` (csharp, go: `Phases`) is always present and can be empty. The run’s and phases’ `name` (csharp, go: `Name`) and `description` (csharp, go: `Description`) are text the model wrote, so they can repeat words from your request. A run’s `name` (csharp, go: `Name`) can also be one the server assigned. | Track the run as open. Show its `name` (csharp, go: `Name`), and progress against `phases` (csharp, go: `Phases`). |
6262| `workflow_run.status_running` | When the run starts its work, which can be a while after `created`, and each time it resumes after a pause at the budget. A resume after an interrupt might not send it. A run that starts idle might get `workflow_run.status_idle` first. | Show the run as running. |
63| `workflow_run.status_idle` | The run was paused, for example at the session's budget. The event doesn't say why. A pause after an interrupt might not send it. | To continue, see [Cost and budgets](https://platform.claude.com/docs/en/managed-agents/workflow-runs#cost-and-budgets) or [Interrupt a session with runs open](https://platform.claude.com/docs/en/managed-agents/workflow-runs#interrupt-a-session-with-runs-open). |
64| `workflow_run.phase_started`, `workflow_run.phase_ended` | The workflow entered or left a phase, or the run's end closed a phase that was still open. The end event doesn't say whether the phase's work completed. Both include `workflow_run_phase_id` (java: `workflowRunPhaseId`; php: `workflowRunPhaseID`; csharp, go: `WorkflowRunPhaseID`). The end also has `phase_started_id` (java: `phaseStartedId`; php: `phaseStartedID`; csharp, go: `PhaseStartedID`), the `id` (csharp, go: `ID`) of the start event it closes. Neither has the phase's name: look it up by `workflow_run_phase_id` (java: `workflowRunPhaseId`; php: `workflowRunPhaseID`; csharp, go: `WorkflowRunPhaseID`) in the `phases` (csharp, go: `Phases`) of `workflow_run.created`. | Update progress. Phases run one at a time, in the order of `phases` (csharp, go: `Phases`), each at most once, but the API doesn't guarantee it. Match a phase's end to its start by `phase_started_id` (java: `phaseStartedId`; php: `phaseStartedID`; csharp, go: `PhaseStartedID`). Handle more than one open phase, a phase that isn't in `phases` (csharp, go: `Phases`), and a listed phase that never starts, even in a run that completes. Every phase that starts also ends, before the run's `workflow_run.status_ended`. |
65| `workflow_run.status_ended` | The run ended. Always the last of the run's `workflow_run.*` events. Includes `result` (csharp, go: `Result`). | Read `result` (csharp, go: `Result`) (next table). The agent then gets a turn to read how the run ended. At the budget, or while the primary thread waits on your client, that turn comes later. After an interrupt, that turn might not come: send a `user.message`, or read `result` (csharp, go: `Result`) yourself. After an archive or termination, it doesn't come. |
66| `workflow_run.error` | The server reports an error of a run, or a start that it refused. A run that ends in `error` gets this event, with the same error, before its `workflow_run.status_ended`. Includes `error` (csharp, go: `Error`): a `type` (csharp, go: `Type`) and a `message` (csharp, go: `Message`) that is safe to log. `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) when no run was created. | Log it, and don't take it as the run's end. If `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`), no run started. Otherwise keep tracking the run until its `workflow_run.status_ended`. |
63| `workflow_run.status_idle` | The run was paused, for example at the session’s budget. The event doesn’t say why. A pause after an interrupt might not send it. | To continue, see [Cost and budgets](https://platform.claude.com/docs/en/managed-agents/workflow-runs#cost-and-budgets) or [Interrupt a session with runs open](https://platform.claude.com/docs/en/managed-agents/workflow-runs#interrupt-a-session-with-runs-open). |
64| `workflow_run.phase_started`, `workflow_run.phase_ended` | The workflow entered or left a phase, or the run’s end closed a phase that was still open. The end event doesn’t say whether the phase’s work completed. Both include `workflow_run_phase_id` (java: `workflowRunPhaseId`; php: `workflowRunPhaseID`; csharp, go: `WorkflowRunPhaseID`). The end also has `phase_started_id` (java: `phaseStartedId`; php: `phaseStartedID`; csharp, go: `PhaseStartedID`), the `id` (csharp, go: `ID`) of the start event it closes. Neither has the phase’s name: look it up by `workflow_run_phase_id` (java: `workflowRunPhaseId`; php: `workflowRunPhaseID`; csharp, go: `WorkflowRunPhaseID`) in the `phases` (csharp, go: `Phases`) of `workflow_run.created`. | Update progress. Phases run one at a time, in the order of `phases` (csharp, go: `Phases`), each at most once, but the API doesn’t guarantee it. Match a phase’s end to its start by `phase_started_id` (java: `phaseStartedId`; php: `phaseStartedID`; csharp, go: `PhaseStartedID`). Handle more than one open phase, a phase that isn’t in `phases` (csharp, go: `Phases`), and a listed phase that never starts, even in a run that completes. Every phase that starts also ends, before the run’s `workflow_run.status_ended`. |
65| `workflow_run.status_ended` | The run ended. Always the last of the run’s `workflow_run.*` events. Includes `result` (csharp, go: `Result`). | Read `result` (csharp, go: `Result`) (next table). The agent then gets a turn to read how the run ended. At the budget, or while the primary thread waits on your client, that turn comes later. After an interrupt, that turn might not come: send a `user.message`, or read `result` (csharp, go: `Result`) yourself. After an archive or termination, it doesn’t come. |
66| `workflow_run.error` | The server reports an error of a run, or a start that it refused. A run that ends in `error` gets this event, with the same error, before its `workflow_run.status_ended`. Includes `error` (csharp, go: `Error`): a `type` (csharp, go: `Type`) and a `message` (csharp, go: `Message`) that is safe to log. `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) when no run was created. | Log it, and don’t take it as the run’s end. If `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`), no run started. Otherwise keep tracking the run until its `workflow_run.status_ended`. |
6767 
6868| `result` | Meaning |
6969| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
70| `{"type": "completed"}` | The workflow finished running. The result doesn't say whether the work passed. A run can end `completed` even though work on its threads failed, or a thread couldn't be created. To find failed work, read the events of each of the [run's threads](https://platform.claude.com/docs/en/managed-agents/workflow-runs#a-runs-threads). |
71| `{"type": "stopped"}` | The agent stopped the run, or the session was archived. The event doesn't say which. Don't treat these as the only causes. |
70| `{"type": "completed"}` | The workflow finished running. The result doesn’t say whether the work passed. A run can end `completed` even though work on its threads failed, or a thread couldn’t be created. To find failed work, read the events of each of the [run’s threads](https://platform.claude.com/docs/en/managed-agents/workflow-runs#a-runs-threads). |
71| `{"type": "stopped"}` | The agent stopped the run, or the session was archived. The event doesn’t say which. Don’t treat these as the only causes. |
7272| `error` with `timeout_error` | The run reached its [lifetime](https://platform.claude.com/docs/en/managed-agents/workflow-runs#limits), which the agent can set. |
73| `error` with `program_error` | The workflow failed. Its code failed, or it broke a rule for workflows, other than a limit. Or one of the run's threads failed, or couldn't be created, and the workflow let that end the run. |
73| `error` with `program_error` | The workflow failed. Its code failed, or it broke a rule for workflows, other than a limit. Or one of the run’s threads failed, or couldn’t be created, and the workflow let that end the run. |
7474| `error` with `thread_limit_error` | The run went over its [limit on the agents that a workflow starts](https://platform.claude.com/docs/en/managed-agents/workflow-runs#limits). |
75| `error` with `unknown_error` | The server couldn't continue the run, or the run went over one of the server's other limits on workflows. |
75| `error` with `unknown_error` | The server couldn’t continue the run, or the run went over one of the server’s other limits on workflows. |
7676 
77An error result looks like `{"type": "error", "error": {"type": "timeout_error", "message": "..."}}`, where `message` is safe to log. Treat an unrecognized `result.type` as a run that ended some other way, and an unrecognized `error.type` as an error. When something the session depends on fails, such as the model, an MCP server, credentials, or billing, the failing thread's stream gets a `session.error`. That doesn't end a run by itself. But if it makes one of the run's threads fail, and the workflow lets that end the run, the run ends with `program_error`.
77An error result looks like `{"type": "error", "error": {"type": "timeout_error", "message": "..."}}`, where `message` is safe to log. Treat an unrecognized `result.type` as a run that ended some other way, and an unrecognized `error.type` as an error. When something the session depends on fails, such as the model, an MCP server, credentials, or billing, the failing thread’s stream gets a `session.error`. That doesn’t end a run by itself. But if it makes one of the run’s threads fail, and the workflow lets that end the run, the run ends with `program_error`.
7878 
7979For example, you ask the [contract-review agent](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#turn-on-dynamic-workflows) which of 300 contracts have a change-of-control clause, and the agent starts a run:
8080 
811. `workflow_run.created` names the run "Find change-of-control clauses" and lists the phases "Read the contracts" and "Reconcile the findings" in `phases` (csharp, go: `Phases`). Then `workflow_run.status_running` follows.
822. Phase events mark each phase, and each thread the run creates sends `session.thread_created` with the run's `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`).
811. `workflow_run.created` names the run “Find change-of-control clauses” and lists the phases “Read the contracts” and “Reconcile the findings” in `phases` (csharp, go: `Phases`). Then `workflow_run.status_running` follows.
822. Phase events mark each phase, and each thread the run creates sends `session.thread_created` with the run’s `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`).
83833. `workflow_run.status_ended` arrives with `result: {"type": "completed"}`.
844. The agent answers, "41 of the 300 contracts have one," and `session.status_idle` arrives with `end_turn`.
844. The agent answers, “41 of the 300 contracts have one,” and `session.status_idle` arrives with `end_turn`.
8585 
86The run's first event lists its phases:
86The run’s first event lists its phases:
8787 
8888```json
8989{
from line 104
104104}
105105```
106106 
107Each phase event names its phase by `workflow_run_phase_id`. That is an `id` in `phases`, but the API doesn't guarantee it:
107Each phase event names its phase by `workflow_run_phase_id`. That is an `id` in `phases`, but the API doesn’t guarantee it:
108108 
109109```json
110110{
from line 116
116116}
117117```
118118 
119The run's last event reports how it ended:
119The run’s last event reports how it ended:
120120 
121121```json
122122{
from line 128
128128}
129129```
130130 
131## A run's threads
131## A run’s threads
132132 
133Each agent in a run works in its own [session thread](https://platform.claude.com/docs/en/managed-agents/session-threads), which the server creates as the workflow needs it. You can list, read, and stream a run's threads like any child thread, and answer their tool calls from the primary stream. To stop them, ask the agent to stop the run (see [Interrupt a session with runs open](https://platform.claude.com/docs/en/managed-agents/workflow-runs#interrupt-a-session-with-runs-open)).
133Each agent in a run works in its own [session thread](https://platform.claude.com/docs/en/managed-agents/session-threads), which the server creates as the workflow needs it. You can list, read, and stream a run’s threads like any child thread, and answer their tool calls from the primary stream. To stop them, ask the agent to stop the run (see [Interrupt a session with runs open](https://platform.claude.com/docs/en/managed-agents/workflow-runs#interrupt-a-session-with-runs-open)).
134134 
135* **Grouping:** A run's thread has the run's `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`), as does the `session.thread_created` event that announces it. Other threads, and the `session.thread_created` events that announce them, have `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) set to `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`).
136* **Agent:** `agent` (csharp, go: `Agent`) shows the agent the thread runs. For an agent you listed in the [`predefined_agents` (java, php: `predefinedAgents`; csharp, go: `PredefinedAgents`) list of `workflows` (csharp, go: `Workflows`)](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#turn-on-dynamic-workflows) in `multiagent` (csharp, go: `Multiagent`), `agent` (csharp, go: `Agent`) has that agent's `id` (csharp, go: `ID`) and `version` (csharp, go: `Version`), as on the thread of a subagent you listed. For an agent the workflow defines (an inline agent), `agent` (csharp, go: `Agent`) has `type` `inline` and no `id` (csharp, go: `ID`) or `version` (csharp, go: `Version`). It has the system prompt the workflow wrote, not the session agent's. It also has the name and description the workflow gave it. The server assigns a name if the workflow gave none. It uses the model of the session agent, the agent the session runs. Its tools, MCP servers, and skills are a subset of the session agent's. It gets all of them, but the API doesn't guarantee that. Its tools keep their permission policies.
137* **What the threads share:** A run's threads work in the session's sandbox, so every thread works with the same files. That includes the files of a memory store the session mounts. An agent the workflow defines uses its MCP servers with the credentials the session resolves for them. Each thread has its own conversation history.
138* **Events:** A run thread's `session.thread_created`, `session.thread_status_running`, `session.thread_status_idle`, and `session.thread_status_terminated` events also arrive on the primary stream (see [Run events](https://platform.claude.com/docs/en/managed-agents/workflow-runs#run-events)). Its message events stay on its own stream. Its thread webhooks are sent as for any child thread. For what the thread's own stream records, see [Session thread events](https://platform.claude.com/docs/en/managed-agents/session-threads#session-thread-events).
139* **Phases:** No event or field says which phase a thread works in, and threads of one run can have the same `agent_name`. Follow a run's progress by its phase events, and tell its threads apart by `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`).
140* **Archiving:** The server archives each thread no later than the end of its run. It can archive one sooner, once the thread returns its result or the run finishes with it. If the thread is still running or waiting on your client at that point, the server stops it first. An archived thread stays in the thread list, with status `terminated`. You don't need to archive a run's threads yourself.
135* **Grouping:** A run’s thread has the run’s `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`), as does the `session.thread_created` event that announces it. Other threads, and the `session.thread_created` events that announce them, have `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`) set to `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`).
136* **Agent:** `agent` (csharp, go: `Agent`) shows the agent the thread runs. For an agent you listed in the [`predefined_agents` (java, php: `predefinedAgents`; csharp, go: `PredefinedAgents`) list of `workflows` (csharp, go: `Workflows`)](https://platform.claude.com/docs/en/managed-agents/multiagent-orchestration#turn-on-dynamic-workflows) in `multiagent` (csharp, go: `Multiagent`), `agent` (csharp, go: `Agent`) has that agent’s `id` (csharp, go: `ID`) and `version` (csharp, go: `Version`), as on the thread of a subagent you listed. For an agent the workflow defines (an inline agent), `agent` (csharp, go: `Agent`) has `type` `inline` and no `id` (csharp, go: `ID`) or `version` (csharp, go: `Version`). It has the system prompt the workflow wrote, not the session agent’s. It also has the name and description the workflow gave it. The server assigns a name if the workflow gave none. It uses the model of the session agent, the agent the session runs. Its tools, MCP servers, and skills are a subset of the session agent’s. It gets all of them, but the API doesn’t guarantee that. Its tools keep their permission policies.
137* **What the threads share:** A run’s threads work in the session’s sandbox, so every thread works with the same files. That includes the files of a memory store the session mounts. An agent the workflow defines uses its MCP servers with the credentials the session resolves for them. Each thread has its own conversation history.
138* **Events:** A run thread’s `session.thread_created`, `session.thread_status_running`, `session.thread_status_idle`, and `session.thread_status_terminated` events also arrive on the primary stream (see [Run events](https://platform.claude.com/docs/en/managed-agents/workflow-runs#run-events)). Its message events stay on its own stream. Its thread webhooks are sent as for any child thread. For what the thread’s own stream records, see [Session thread events](https://platform.claude.com/docs/en/managed-agents/session-threads#session-thread-events).
139* **Phases:** No event or field says which phase a thread works in, and threads of one run can have the same `agent_name`. Follow a run’s progress by its phase events, and tell its threads apart by `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`).
140* **Archiving:** The server archives each thread no later than the end of its run. It can archive one sooner, once the thread returns its result or the run finishes with it. If the thread is still running or waiting on your client at that point, the server stops it first. An archived thread stays in the thread list, with status `terminated`. You don’t need to archive a run’s threads yourself.
141141* **Tools:** A run can create more than one thread for the same piece of work, so make the tools your agents call safe to call twice.
142142 
143143<Tip>
from line 150
150150 
151151## Know when the work is done
152152 
153While a run is running, expect the session to stay `running`, even while none of its threads is working. It goes `idle` with `requires_action` when no thread is working and a thread waits on your client. An idle by itself doesn't mean that the work is done. The work is done when both are true:
153While a run is running, expect the session to stay `running`, even while none of its threads is working. It goes `idle` with `requires_action` when no thread is working and a thread waits on your client. An idle by itself doesn’t mean that the work is done. The work is done when both are true:
154154 
1551. Every run you've seen created has its `workflow_run.status_ended`.
1562. After that, a `session.status_idle` arrives with `stop_reason` (java, php: `stopReason`; csharp, go: `StopReason`) `end_turn`, and your own request, such as an interrupt, didn't cause it. After you interrupt, count only an idle that comes after your next `user.message` or `user.define_outcome`.
1551. Every run you’ve seen created has its `workflow_run.status_ended`.
1562. After that, a `session.status_idle` arrives with `stop_reason` (java, php: `stopReason`; csharp, go: `StopReason`) `end_turn`, and your own request, such as an interrupt, didn’t cause it. After you interrupt, count only an idle that comes after your next `user.message` or `user.define_outcome`.
157157 
158* **Paused runs:** A paused run doesn't keep the session `running`, so the session can go idle while the run is still open. At the budget, for example, the session goes idle with `budget_reached`. The work isn't done until the run ends.
158* **Paused runs:** A paused run doesn’t keep the session `running`, so the session can go idle while the run is still open. At the budget, for example, the session goes idle with `budget_reached`. The work isn’t done until the run ends.
159159* **Another run:** The agent can start a new run when it reads a result, so check again.
160* **Outcomes:** If you [defined an outcome](https://platform.claude.com/docs/en/managed-agents/define-outcomes), no evaluation starts while a run is open, whether it's running or idle. The turn in which the agent reads the run's result can start one.
161* **`retries_exhausted`:** The agent's turn failed on an error: retries ran out, or the error can't be retried, such as a billing failure. A run might still be running when this idle comes. If a run ended and the agent hasn't read its result yet, the server starts a new turn with no input from you. The session goes `running` again, so wait for the next idle. If the session stays idle, read the `session.error` that came before it and fix the cause. Then send a `user.message`, or read each run's `result` (csharp, go: `Result`) yourself.
160* **Outcomes:** If you [defined an outcome](https://platform.claude.com/docs/en/managed-agents/define-outcomes), no evaluation starts while a run is open, whether it’s running or idle. The turn in which the agent reads the run’s result can start one.
161* **`retries_exhausted`:** The agent’s turn failed on an error: retries ran out, or the error can’t be retried, such as a billing failure. A run might still be running when this idle comes. If a run ended and the agent hasn’t read its result yet, the server starts a new turn with no input from you. The session goes `running` again, so wait for the next idle. If the session stays idle, read the `session.error` that came before it and fix the cause. Then send a `user.message`, or read each run’s `result` (csharp, go: `Result`) yourself.
162162 
163163## Follow a run
164164 
165This sample follows a session from your message to the agent's answer. It opens the stream and sends the message. Then it does the following:
165This sample follows a session from your message to the agent’s answer. It opens the stream and sends the message. Then it does the following:
166166 
167167* **Tracks each run** from its `workflow_run.created` to its `workflow_run.status_ended`, and prints each phase as it starts.
168* **Answers custom tool calls** when each `agent.custom_tool_use` arrives, because a run's thread can wait on your client while the session stays `running`. If your agent's tools [ask for confirmation](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#tool-confirmation), add a branch that answers each `agent.tool_use` or `agent.mcp_tool_use` whose `evaluated_permission` (java, php: `evaluatedPermission`; csharp, go: `EvaluatedPermission`) is `ask`. The sample has none, because a branch that allows every call would turn `always_ask` into always allow.
168* **Answers custom tool calls** when each `agent.custom_tool_use` arrives, because a run’s thread can wait on your client while the session stays `running`. If your agent’s tools [ask for confirmation](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#tool-confirmation), add a branch that answers each `agent.tool_use` or `agent.mcp_tool_use` whose `evaluated_permission` (java, php: `evaluatedPermission`; csharp, go: `EvaluatedPermission`) is `ask`. The sample has none, because a branch that allows every call would turn `always_ask` into always allow.
169169* **Stops** when the [work is done](https://platform.claude.com/docs/en/managed-agents/workflow-runs#know-when-the-work-is-done): no run is open, and the session goes idle with `end_turn`. It also stops if the session terminates. On an idle with any other stop reason except `requires_action`, such as `budget_reached`, `retries_exhausted`, or `refusal`, it prints the reason and stops, so handle those in your own code. It stops on `retries_exhausted` even when the server is about to start a new turn by itself. It keeps waiting on `requires_action`, and on `end_turn` while a run is open.
170170 
171171<CodeGroup exclude="shell">
from line 750
750750 
751751## Interrupt a session with runs open
752752 
753Send [`user.interrupt`](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#interrupt-the-agent) with no `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`), or with the primary thread's ID. It stops the agent's turn. It ends no run. The session's runs might pause or keep running, and their events might not show which. A paused run's lifetime keeps passing, so the run can end with `timeout_error` while it's paused.
753Send [`user.interrupt`](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#interrupt-the-agent) with no `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`), or with the primary thread’s ID. It stops the agent’s turn. It ends no run. The session’s runs might pause or keep running, and their events might not show which. A paused run’s lifetime keeps passing, so the run can end with `timeout_error` while it’s paused.
754754 
755* **Waiting tool calls:** After the interrupt, a run thread's tool call might still wait on your client. Answer each one. To cancel a call that asks for confirmation, deny it. To cancel a custom tool call, send a result with `is_error` (java, php: `isError`; csharp, go: `IsError`) set to `true` and a text in `content` (csharp, go: `Content`) that says why. While the session is `idle` with `requires_action`, a `user.message` returns 400, so answer the calls first.
755* **Waiting tool calls:** After the interrupt, a run thread’s tool call might still wait on your client. Answer each one. To cancel a call that asks for confirmation, deny it. To cancel a custom tool call, send a result with `is_error` (java, php: `isError`; csharp, go: `IsError`) set to `true` and a text in `content` (csharp, go: `Content`) that says why. While the session is `idle` with `requires_action`, a `user.message` returns 400, so answer the calls first.
756756* **To stop the runs:** Send a `user.message` asking the agent to stop its runs. A stopped run ends with `result` `{"type": "stopped"}`. While the session is `idle` with `budget_reached`, a `user.message` returns 400 until you raise or remove the budget. Raising or removing it also resumes the runs that the budget paused, unless the interrupt also paused them.
757757* **To continue:** Send a `user.message` asking the agent to continue its runs. After an interrupt, the runs might wait for this message. If the session is `idle` with `budget_reached`, raise or remove the budget first.
758758* **Run results:** A run that ends after the interrupt still sends `workflow_run.status_ended`.
from line 761
761761 
762762| Request | While a run is open | What to do |
763763| ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
764| Archive or delete the session | Might return 400 while a run is open, whatever the session's status. The error's `error.details.error_code` can be `"workflow_run_open"`. Might also succeed. | Ask the agent to stop its runs, or wait until each run has ended. A paused run ends by itself only when its lifetime passes. Then send the request once the session is `idle`. An archive that succeeds ends each open run with `{"type": "stopped"}`. After an archive, a run's `workflow_run.status_ended`, and the `workflow_run.phase_ended` of a phase that was still open, don't arrive on the stream. List the session's events to read them. After a delete that succeeds, no `workflow_run` event reports the end of the session's runs. |
765| Archive one of a run's threads | Returns 400 with `error.details.error_code: "workflow_run_open"` while the run is open, running or idle, unless the server has already archived the thread. | Nothing. The server archives a run's threads. |
766| Update the session's `agent` (csharp, go: `Agent`) | Returns 400 with `error.details.error_code: "workflow_run_open"` while any run is open, even a paused one. Updating the underlying agent is still accepted, and the session keeps its own copy. A request that also sends other fields, such as `budget` (csharp, go: `Budget`), is rejected whole. | Wait until every run has its `workflow_run.status_ended`, or ask the agent to stop its runs. |
767| Answer a tool call or tool confirmation from a run's thread | Allowed. It arrives on the primary stream, and its `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`) names the thread. | Answer as soon as the event arrives, passing the event's `id` (csharp, go: `ID`) as `tool_use_id` (java: `toolUseId`; php: `toolUseID`; csharp, go: `ToolUseID`) or `custom_tool_use_id` (java: `customToolUseId`; php: `customToolUseID`; csharp, go: `CustomToolUseID`). Don't wait for `session.status_idle`: the session can stay `running` while the run's other threads work. Once the server has archived the thread, a tool result for one of its calls has no effect, and it can return 400. When a tool result returns 400, find the call's thread in the thread list. If its status is `terminated`, the result came too late, so drop it. Send each tool result in a request of its own, because the server refuses a whole request when it refuses one of its events. A tool confirmation that comes too late returns 200, which doesn't mean that the tool ran. |
764| Archive or delete the session | Might return 400 while a run is open, whatever the session’s status. The error’s `error.details.error_code` can be `"workflow_run_open"`. Might also succeed. | Ask the agent to stop its runs, or wait until each run has ended. A paused run ends by itself only when its lifetime passes. Then send the request once the session is `idle`. An archive that succeeds ends each open run with `{"type": "stopped"}`. After an archive, a run’s `workflow_run.status_ended`, and the `workflow_run.phase_ended` of a phase that was still open, don’t arrive on the stream. List the session’s events to read them. After a delete that succeeds, no `workflow_run` event reports the end of the session’s runs. |
765| Archive one of a run’s threads | Returns 400 with `error.details.error_code: "workflow_run_open"` while the run is open, running or idle, unless the server has already archived the thread. | Nothing. The server archives a run’s threads. |
766| Update the session’s `agent` (csharp, go: `Agent`) | Returns 400 with `error.details.error_code: "workflow_run_open"` while any run is open, even a paused one. Updating the underlying agent is still accepted, and the session keeps its own copy. A request that also sends other fields, such as `budget` (csharp, go: `Budget`), is rejected whole. | Wait until every run has its `workflow_run.status_ended`, or ask the agent to stop its runs. |
767| Answer a tool call or tool confirmation from a run’s thread | Allowed. It arrives on the primary stream, and its `session_thread_id` (java: `sessionThreadId`; php: `sessionThreadID`; csharp, go: `SessionThreadID`) names the thread. | Answer as soon as the event arrives, passing the event’s `id` (csharp, go: `ID`) as `tool_use_id` (java: `toolUseId`; php: `toolUseID`; csharp, go: `ToolUseID`) or `custom_tool_use_id` (java: `customToolUseId`; php: `customToolUseID`; csharp, go: `CustomToolUseID`). Don’t wait for `session.status_idle`: the session can stay `running` while the run’s other threads work. Once the server has archived the thread, a tool result for one of its calls has no effect, and it can return 400. When a tool result returns 400, find the call’s thread in the thread list. If its status is `terminated`, the result came too late, so drop it. Send each tool result in a request of its own, because the server refuses a whole request when it refuses one of its events. A tool confirmation that comes too late returns 200, which doesn’t mean that the tool ran. |
768768 
769769### Rebuild run state after you reconnect
770770 
771Rebuild each run's state from the session's events. The stream doesn't replay what you missed: a new connection delivers only events emitted after it opened. So list the events with a `types` (curl: `types[]`; cli: `--type`; csharp, go: `Types`) filter, one entry for each event type, as in [List past events](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#list-past-events). Pass each response's `next_page` (ruby: `next_page_`; java, php: `nextPage`; csharp, go: `NextPage`) as `page` (cli: `--page`; csharp, go: `Page`) until `next_page` (ruby: `next_page_`; java, php: `nextPage`; csharp, go: `NextPage`) is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) or missing. `workflow_run.created`, `workflow_run.status_running`, `workflow_run.status_idle`, and `workflow_run.status_ended` give each run's state, except that a run paused after an interrupt might still show as running. `workflow_run.phase_started` and `workflow_run.phase_ended` rebuild progress. A run with no status event yet hasn't started running. No endpoint lists runs.
771Rebuild each run’s state from the session’s events. The stream doesn’t replay what you missed: a new connection delivers only events emitted after it opened. So list the events with a `types` (curl: `types[]`; cli: `--type`; csharp, go: `Types`) filter, one entry for each event type, as in [List past events](https://platform.claude.com/docs/en/managed-agents/events-and-streaming#list-past-events). Pass each response’s `next_page` (ruby: `next_page_`; java, php: `nextPage`; csharp, go: `NextPage`) as `page` (cli: `--page`; csharp, go: `Page`) until `next_page` (ruby: `next_page_`; java, php: `nextPage`; csharp, go: `NextPage`) is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) or missing. `workflow_run.created`, `workflow_run.status_running`, `workflow_run.status_idle`, and `workflow_run.status_ended` give each run’s state, except that a run paused after an interrupt might still show as running. `workflow_run.phase_started` and `workflow_run.phase_ended` rebuild progress. A run with no status event yet hasn’t started running. No endpoint lists runs.
772772 
773773## Cost and budgets
774774 
775A run's model requests count toward the [session's budget](https://platform.claude.com/docs/en/managed-agents/budgets). A run has no price of its own. The tokens its agents use are billed like the session's other tokens, at each model's rates. For all of a session's charges, see [Claude Managed Agents pricing](https://platform.claude.com/docs/en/about-claude/pricing#claude-managed-agents-pricing).
775A run’s model requests count toward the [session’s budget](https://platform.claude.com/docs/en/managed-agents/budgets). A run has no price of its own. The tokens its agents use are billed like the session’s other tokens, at each model’s rates. For all of a session’s charges, see [Claude Managed Agents pricing](https://platform.claude.com/docs/en/about-claude/pricing#claude-managed-agents-pricing).
776776 
777* **One run's usage:** List the session's threads and add up the token counts in `usage` (csharp, go: `Usage`) of the threads with the run's `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`). The list includes archived threads, whose status is `terminated`, so a finished run's threads are counted. Pass each response's `next_page` (ruby: `next_page_`; java, php: `nextPage`; csharp, go: `NextPage`) as `page` (cli: `--page`; csharp, go: `Page`) until `next_page` (ruby: `next_page_`; java, php: `nextPage`; csharp, go: `NextPage`) is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) or missing, and skip a thread with no `usage` (csharp, go: `Usage`). If you add up the threads' `list_cost` (java, php: `listCost`; csharp, go: `ListCost`) instead, the total leaves out session runtime, and each figure is rounded separately.
778* **At the budget:** Every open run pauses, and the session reports `idle` with `budget_reached`, or `requires_action` if a tool call is also waiting. Each thread completes the model request it already started, so a run can pass the budget by one request for each working thread. Raising or removing the budget resumes the runs it paused, unless an interrupt also paused them. If the session's usage includes a model with no list price, only removing the budget does; see [Models without a list price](https://platform.claude.com/docs/en/managed-agents/budgets#models-without-a-list-price). A paused run's lifetime keeps passing, so the run can end with `timeout_error` while it's paused.
777* **One run’s usage:** List the session’s threads and add up the token counts in `usage` (csharp, go: `Usage`) of the threads with the run’s `workflow_run_id` (java: `workflowRunId`; php: `workflowRunID`; csharp, go: `WorkflowRunID`). The list includes archived threads, whose status is `terminated`, so a finished run’s threads are counted. Pass each response’s `next_page` (ruby: `next_page_`; java, php: `nextPage`; csharp, go: `NextPage`) as `page` (cli: `--page`; csharp, go: `Page`) until `next_page` (ruby: `next_page_`; java, php: `nextPage`; csharp, go: `NextPage`) is `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`) or missing, and skip a thread with no `usage` (csharp, go: `Usage`). If you add up the threads’ `list_cost` (java, php: `listCost`; csharp, go: `ListCost`) instead, the total leaves out session runtime, and each figure is rounded separately.
778* **At the budget:** Every open run pauses, and the session reports `idle` with `budget_reached`, or `requires_action` if a tool call is also waiting. Each thread completes the model request it already started, so a run can pass the budget by one request for each working thread. Raising or removing the budget resumes the runs it paused, unless an interrupt also paused them. If the session’s usage includes a model with no list price, only removing the budget does; see [Models without a list price](https://platform.claude.com/docs/en/managed-agents/budgets#models-without-a-list-price). A paused run’s lifetime keeps passing, so the run can end with `timeout_error` while it’s paused.
779779 
780780## Limits
781781 
782782| Limit | Value | At the limit |
783783| -------------------------------------------------- | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
784| Threads working at once in one run | 64 | The run creates no more until one finishes. The API doesn't guarantee this number. |
785| Agents a workflow starts over the run's whole life | 1,000 | When the workflow asks for more, the server doesn't start another agent, and the run ends with `thread_limit_error`. The server can run a failed agent again on a new thread, so a run might have more than 1,000 threads. |
784| Threads working at once in one run | 64 | The run creates no more until one finishes. The API doesn’t guarantee this number. |
785| Agents a workflow starts over the run’s whole life | 1,000 | When the workflow asks for more, the server doesn’t start another agent, and the run ends with `thread_limit_error`. The server can run a failed agent again on a new thread, so a run might have more than 1,000 threads. |
786786| Run lifetime | 24 hours by default, or the lifetime the agent sets | The run ends with `timeout_error`. No event says what lifetime the agent set. |
787| Runs open at once in a session | 10 by default | The server refuses to start another run. The agent's tool call gets an error, and you get a `workflow_run.error` whose `error.type` is `max_workflow_runs_error`. Idle runs count toward the limit. |
787| Runs open at once in a session | 10 by default | The server refuses to start another run. The agent’s tool call gets an error, and you get a `workflow_run.error` whose `error.type` is `max_workflow_runs_error`. Idle runs count toward the limit. |
788788 
789The server shortens a run's or phase's `name` (csharp, go: `Name`) to 64 characters and its `description` (csharp, go: `Description`) to 256. The server has other limits on workflows, and rules for them, that aren't listed here. What you see depends on when the server finds the problem:
789The server shortens a run’s or phase’s `name` (csharp, go: `Name`) to 64 characters and its `description` (csharp, go: `Description`) to 256. The server has other limits on workflows, and rules for them, that aren’t listed here. What you see depends on when the server finds the problem:
790790 
791791| What happens | What you see |
792792| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
from line 796
796796 
797797A session can start any number of runs over its life.
798798 
799* **Starting runs:** Only the agent on the session's primary thread starts runs. An agent working in a run's thread can't start a run of its own, so runs don't nest.
799* **Starting runs:** Only the agent on the session’s primary thread starts runs. An agent working in a run’s thread can’t start a run of its own, so runs don’t nest.
800800* **Ending runs:** No event you send ends a run; archiving the session can.
801* **A run's threads:** You can't [stop a thread by its ID](https://platform.claude.com/docs/en/managed-agents/session-threads#interrupt-a-session-thread), or archive one while its run is open.
802* **Thread limit:** A run's threads are exempt from the session's [child-thread limit](https://platform.claude.com/docs/en/managed-agents/session-threads#primary-thread-and-session-threads).
803* **Visibility:** You don't see the workflow's code, but you can ask the agent for the workflow, as the tip in [A run's threads](https://platform.claude.com/docs/en/managed-agents/workflow-runs#a-runs-threads) describes. You also don't see the tool calls the agent makes to start and manage runs, or the result each thread returns to the workflow.
801* **A run’s threads:** You can’t [stop a thread by its ID](https://platform.claude.com/docs/en/managed-agents/session-threads#interrupt-a-session-thread), or archive one while its run is open.
802* **Thread limit:** A run’s threads are exempt from the session’s [child-thread limit](https://platform.claude.com/docs/en/managed-agents/session-threads#primary-thread-and-session-threads).
803* **Visibility:** You don’t see the workflow’s code, but you can ask the agent for the workflow, as the tip in [A run’s threads](https://platform.claude.com/docs/en/managed-agents/workflow-runs#a-runs-threads) describes. You also don’t see the tool calls the agent makes to start and manage runs, or the result each thread returns to the workflow.
804804 
805805### Rate limits
806806 
807A run's work counts toward rate limits that your organization already has.
807A run’s work counts toward rate limits that your organization already has.
808808 
809809| What | Counts toward | What to do |
810810| ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
811| Your client's requests to retrieve or list the session, its threads, and their events | The read limit for [Managed Agents endpoints](https://platform.claude.com/docs/en/managed-agents/reference#rate-limits) | Follow a run on the session's event stream instead of polling. |
812| Model requests from a run's threads | Your [Messages API rate limits](https://platform.claude.com/docs/en/api/rate-limits) for the model each thread uses, along with your other traffic | Leave room for a run in those limits, or [request higher limits](https://platform.claude.com/docs/en/api/rate-limits#requesting-higher-limits). |
811| Your client’s requests to retrieve or list the session, its threads, and their events | The read limit for [Managed Agents endpoints](https://platform.claude.com/docs/en/managed-agents/reference#rate-limits) | Follow a run on the session’s event stream instead of polling. |
812| Model requests from a run’s threads | Your [Messages API rate limits](https://platform.claude.com/docs/en/api/rate-limits) for the model each thread uses, along with your other traffic | Leave room for a run in those limits, or [request higher limits](https://platform.claude.com/docs/en/api/rate-limits#requesting-higher-limits). |
813813 
814When a model request from one of a run's threads is rate limited, or the model is overloaded, the thread's own stream can get a `session.error` of type `model_rate_limited_error` or `model_overloaded_error`:
814When a model request from one of a run’s threads is rate limited, or the model is overloaded, the thread’s own stream can get a `session.error` of type `model_rate_limited_error` or `model_overloaded_error`:
815815 
816816* If its `retry_status.type` is `retrying`, the server is retrying the request, and the thread is still working.
817* If it's `exhausted`, the thread has failed. If the workflow lets that failure end the run, the run ends with `program_error`, which doesn't name the cause. Read the failed threads' events to find it.
817* If it’s `exhausted`, the thread has failed. If the workflow lets that failure end the run, the run ends with `program_error`, which doesn’t name the cause. Read the failed threads’ events to find it.
818818 
819The server also limits how much all of your organization's sessions do each minute. A thread that meets this limit stops, with a `session.error` on its own stream whose message names a rate limit. Wait a minute before you ask the agent to continue.
819The server also limits how much all of your organization’s sessions do each minute. A thread that meets this limit stops, with a `session.error` on its own stream whose message names a rate limit. Wait a minute before you ask the agent to continue.
820820 

models/fable-5-1/migration-guide Changed · +45 / -45 lines

from line 14
1414/claude-api migrate this project to claude-fable-5-1
1515```
1616 
17[Claude Fable 5.1](https://platform.claude.com/docs/en/models/fable-5-1/whats-new-fable-5-1) succeeds Claude Fable 5 at the same input and output prices, with cache reads at a quarter of the cost. It's available on the Claude API, [Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock), [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws), [Claude Models on Google Cloud (Anthropic managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/anthropic-managed), [Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/google-managed), and [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry). [Claude Mythos 5.1](https://platform.claude.com/docs/en/models/mythos-5-1/overview) shares the same capabilities and is available only to organizations verified through Anthropic's verification programs, such as the [Cyber Verification Program](https://support.claude.com/en/articles/14604842). For behavioral differences and prompting patterns, see [Prompting Claude Fable 5.1](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-fable-5-1).
17[Claude Fable 5.1](https://platform.claude.com/docs/en/models/fable-5-1/whats-new-fable-5-1) succeeds Claude Fable 5 at the same input and output prices, with cache reads at a quarter of the cost. It’s available on the Claude API, [Amazon Bedrock](https://platform.claude.com/docs/en/build-with-claude/claude-in-amazon-bedrock), [Claude Platform on AWS](https://platform.claude.com/docs/en/build-with-claude/claude-platform-on-aws), [Claude Models on Google Cloud (Anthropic managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/anthropic-managed), [Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/en/build-with-claude/claude-models-on-google-cloud/google-managed), and [Microsoft Foundry](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry). [Claude Mythos 5.1](https://platform.claude.com/docs/en/models/mythos-5-1/overview) shares the same capabilities and is available only to organizations verified through Anthropic’s verification programs, such as the [Cyber Verification Program](https://support.claude.com/en/articles/14604842). For behavioral differences and prompting patterns, see [Prompting Claude Fable 5.1](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-fable-5-1).
1818 
1919The baseline settings shared by `claude-fable-5-1` and `claude-mythos-5-1`:
2020 
from line 21
2121* **Thinking:** [Adaptive thinking](https://platform.claude.com/docs/en/build-with-claude/thinking) is always on, unchanged from Claude Fable 5. The model determines when and how much to think. No `thinking` configuration is required. Both `thinking: {type: "disabled"}` and manual extended thinking (`thinking: {type: "enabled", budget_tokens: N}`) return a 400 error.
2222* **Prefill:** Prefilling the assistant message returns a 400 error, unchanged from Claude Fable 5. Use system prompt instructions instead.
2323* **Tool choice:** `{type: "auto"}` (the default) and `{type: "none"}` are supported. Forcing a tool call with `{type: "any"}` or `{type: "tool", name: "..."}` returns a 400 error. See [Breaking changes](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-breaking-changes).
24* **Preserved thinking across models:** Claude Fable 5.1 reads thinking blocks from Claude Opus 5, Claude Fable 5, Claude Mythos 5, and earlier Claude models. None of those models can read Claude Fable 5.1's blocks. See [Breaking changes](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-breaking-changes).
24* **Preserved thinking across models:** Claude Fable 5.1 reads thinking blocks from Claude Opus 5, Claude Fable 5, Claude Mythos 5, and earlier Claude models. None of those models can read Claude Fable 5.1’s blocks. See [Breaking changes](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-breaking-changes).
2525* **Context window and output:** A [1M token context window](https://platform.claude.com/docs/en/build-with-claude/context-windows) by default, and up to 128k output tokens for each request.
2626* **Pricing:** $10 USD per million input tokens and $50 USD per million output tokens, the same as Claude Fable 5. Prompt cache reads are $0.25 USD per million tokens, a quarter of the Claude Fable 5 rate. See [Claude pricing](https://platform.claude.com/docs/en/about-claude/pricing).
27* **Data retention:** Both models require 30-day data retention, aren't available under zero data retention (ZDR) arrangements unless expressly authorized by Anthropic, and are designated Covered Models, the same as Claude Fable 5 and Claude Mythos 5. On the Claude API, a request from an organization or workspace without 30-day retention returns a 400 `invalid_request_error`. Organizations with a ZDR arrangement should contact their Anthropic account team, or configure retention for individual workspaces. See [Model-specific data retention requirements](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#model-specific-data-retention-requirements) for per-platform details.
27* **Data retention:** Both models require 30-day data retention, aren’t available under zero data retention (ZDR) arrangements unless expressly authorized by Anthropic, and are designated Covered Models, the same as Claude Fable 5 and Claude Mythos 5. On the Claude API, a request from an organization or workspace without 30-day retention returns a 400 `invalid_request_error`. Organizations with a ZDR arrangement should contact their Anthropic account team, or configure retention for individual workspaces. See [Model-specific data retention requirements](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#model-specific-data-retention-requirements) for per-platform details.
2828* **Priority Tier:** Neither model is supported on [Priority Tier](https://platform.claude.com/docs/en/api/service-tiers#supported-models). Claude Fable 5 is.
2929 
3030Where the two models diverge:
3131 
32* **Availability:** Claude Fable 5.1 doesn't require access approval. Claude Mythos 5.1 is available only to organizations verified through Anthropic's verification programs, such as the [Cyber Verification Program](https://support.claude.com/en/articles/14604842). To request access, apply to the program that covers your use case, or contact your Anthropic account team.
33* **Conversation check on thinking blocks:** [Editing earlier turns](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-preserved-thinking) invalidates Claude Fable 5.1's thinking blocks. Claude Mythos 5.1 doesn't run this check.
32* **Availability:** Claude Fable 5.1 doesn’t require access approval. Claude Mythos 5.1 is available only to organizations verified through Anthropic’s verification programs, such as the [Cyber Verification Program](https://support.claude.com/en/articles/14604842). To request access, apply to the program that covers your use case, or contact your Anthropic account team.
33* **Conversation check on thinking blocks:** [Editing earlier turns](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-preserved-thinking) invalidates Claude Fable 5.1’s thinking blocks. Claude Mythos 5.1 doesn’t run this check.
3434 
3535## Migrating to Claude Fable 5.1 from Claude Fable 5
3636 
from line 37
3737Migration is mostly drop-in. The API surface, limits, per-token pricing, tokenizer, always-on adaptive thinking, refusal handling, and `stop_details` categories all match Claude Fable 5. The following changes apply:
3838 
3939* Forced tool choice returns a 400 error.
40* Only Claude Fable 5.1 and Claude Mythos 5.1 read Claude Fable 5.1's thinking blocks, and only in the conversation that produced them.
40* Only Claude Fable 5.1 and Claude Mythos 5.1 read Claude Fable 5.1’s thinking blocks, and only in the conversation that produced them.
4141* Cache reads cost less.
4242* The advisor tool (beta) accepts fewer advisors.
4343* Agent-loop behavior differs in three ways.
4444 
45The same changes apply to the [Claude Mythos 5.1 migration](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#migrating-from-claude-mythos-5-to-claude-mythos-5-1), except the conversation check on thinking blocks, which Claude Mythos 5.1 doesn't run.
45The same changes apply to the [Claude Mythos 5.1 migration](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#migrating-from-claude-mythos-5-to-claude-mythos-5-1), except the conversation check on thinking blocks, which Claude Mythos 5.1 doesn’t run.
4646 
4747### Update your model name
4848 
from line 917
917917 
918918 Keep the `role: "system"` message in the history on later requests, as with any other turn. Mid-conversation system messages need no beta header. `tool_choice: {"type": "none"}` still works for a turn that must not call tools.
919919 
9202. **Only Claude Fable 5.1 and Claude Mythos 5.1 read Claude Fable 5.1's thinking blocks:** Every `thinking` block records which model produced it. Claude Fable 5.1 reads its own blocks and those from Claude Mythos 5.1, Claude Opus 5, Claude Fable 5, Claude Mythos 5, and earlier Claude models. A conversation moving onto `claude-fable-5-1` from any of those keeps its earlier reasoning. The condition is one-way: apart from Claude Mythos 5.1, none of those models can read Claude Fable 5.1's blocks.
9202. **Only Claude Fable 5.1 and Claude Mythos 5.1 read Claude Fable 5.1’s thinking blocks:** Every `thinking` block records which model produced it. Claude Fable 5.1 reads its own blocks and those from Claude Mythos 5.1, Claude Opus 5, Claude Fable 5, Claude Mythos 5, and earlier Claude models. A conversation moving onto `claude-fable-5-1` from any of those keeps its earlier reasoning. The condition is one-way: apart from Claude Mythos 5.1, none of those models can read Claude Fable 5.1’s blocks.
921921 
922 A conversation that ran on Claude Fable 5.1 can land on another model, older or newer, through a router switch, a client-side retry, or a [classifier refusal fallback](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback), including a [server-side fallback](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#server-side-fallback). The API removes the blocks that model can't read before it receives them, the request succeeds, and you aren't billed for the dropped input tokens. The target model re-plans without that reasoning, which can raise cost and latency on the first turn after the switch. To see what was dropped, send the `thinking-binding-controls-2026-08-01` [beta header](https://platform.claude.com/docs/en/api/beta-headers): responses then carry an `input_transformations` array naming each dropped block with `reason: "model_binding_mismatch"`. See [Switching models mid-conversation](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#switching-models).
922 A conversation that ran on Claude Fable 5.1 can land on another model, older or newer, through a router switch, a client-side retry, or a [classifier refusal fallback](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback), including a [server-side fallback](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#server-side-fallback). The API removes the blocks that model can’t read before it receives them, the request succeeds, and you aren’t billed for the dropped input tokens. The target model re-plans without that reasoning, which can raise cost and latency on the first turn after the switch. To see what was dropped, send the `thinking-binding-controls-2026-08-01` [beta header](https://platform.claude.com/docs/en/api/beta-headers): responses then carry an `input_transformations` array naming each dropped block with `reason: "model_binding_mismatch"`. See [Switching models mid-conversation](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking#switching-models).
923923 
9249243. **Editing earlier turns invalidates thinking blocks:** Each `thinking` block from Claude Fable 5.1 is valid only against the `system` prompt, `tools`, and conversation history that preceded it. If Claude Code, claude.ai, [Claude Managed Agents](https://platform.claude.com/docs/en/managed-agents/overview), or the [Claude Agent SDK](https://code.claude.com/docs/en/agent-sdk/overview) manages your conversation history, it already keeps that prefix intact. If your code builds the `messages` array itself, this item applies to you, and [Preserved thinking](https://platform.claude.com/docs/en/build-with-claude/preserved-thinking) is the full integration guide. Where the check is enforced, a request that sends the block back after any of those changed is rejected with a 400 error:
925925 
from line 927
927927 messages.5.content.0: Invalid `signature` in `thinking` block. The block is bound to a different conversation. Remove the block, or set `thinking.block_binding.prefix_mismatch_behavior` to "drop_block". That setting requires the `thinking-binding-controls-2026-08-01` value in the `anthropic-beta` header.
928928 ```
929929 
930 The API enforces the check for new accounts created on or after August 31, 2026. For accounts created earlier, the API records the mismatch but doesn't act on it unless the request sets `thinking.block_binding.prefix_mismatch_behavior`, which opts into enforcement. On those accounts, if you send the `thinking-binding-controls-2026-08-01` beta header and leave that field unset, the response lists each block that failed the check in `input_transformations` as a `thinking_mismatch_allowed` entry. Make your application compatible with the check regardless of your account's age: the same patterns keep the prompt cache warm, and you can test against the check from any account by sending `prefix_mismatch_behavior`. If you ship a tool or framework that people run with their own API key, test that way before launch: your key is probably on an older account, and your users on new ones hit the check before you do. To see whether your own account is enforced by default, send a request that edits history without the beta header: a 400 that names the header means it is.
930 The API enforces the check for new accounts created on or after August 31, 2026. For accounts created earlier, the API records the mismatch but doesn’t act on it unless the request sets `thinking.block_binding.prefix_mismatch_behavior`, which opts into enforcement. On those accounts, if you send the `thinking-binding-controls-2026-08-01` beta header and leave that field unset, the response lists each block that failed the check in `input_transformations` as a `thinking_mismatch_allowed` entry. Make your application compatible with the check regardless of your account’s age: the same patterns keep the prompt cache warm, and you can test against the check from any account by sending `prefix_mismatch_behavior`. If you ship a tool or framework that people run with their own API key, test that way before launch: your key is probably on an older account, and your users on new ones hit the check before you do. To see whether your own account is enforced by default, send a request that edits history without the beta header: a 400 that names the header means it is.
931931 
932 The error is permanent for that request body: an automatic retry loop won't clear it. To continue without the invalidated reasoning instead of failing, strip the `thinking` blocks from the history and retry once, or send the `thinking-binding-controls-2026-08-01` [beta header](https://platform.claude.com/docs/en/api/beta-headers) and set `prefix_mismatch_behavior` to `"drop_block"` (the default is `"error"`). With `"drop_block"`, the API drops the mismatched block and every thinking block after it in the conversation, and reports each with `reason: "prefix_binding_mismatch"` in the response's `input_transformations` array:
932 The error is permanent for that request body: an automatic retry loop won’t clear it. To continue without the invalidated reasoning instead of failing, strip the `thinking` blocks from the history and retry once, or send the `thinking-binding-controls-2026-08-01` [beta header](https://platform.claude.com/docs/en/api/beta-headers) and set `prefix_mismatch_behavior` to `"drop_block"` (the default is `"error"`). With `"drop_block"`, the API drops the mismatched block and every thinking block after it in the conversation, and reports each with `reason: "prefix_binding_mismatch"` in the response’s `input_transformations` array:
933933 
934934 <CodeGroup>
935935 ```bash cURL
from line 1181
11811181 ```
11821182 </CodeGroup>
11831183 
1184 The [token counting](https://platform.claude.com/docs/en/build-with-claude/token-counting) endpoint runs the same check. See [Controls for blocks that aren't preserved (beta)](https://platform.claude.com/docs/en/build-with-claude/thinking#preserved-thinking-controls) for the response shape and streaming placement.
1184 The [token counting](https://platform.claude.com/docs/en/build-with-claude/token-counting) endpoint runs the same check. See [Controls for blocks that aren’t preserved (beta)](https://platform.claude.com/docs/en/build-with-claude/thinking#preserved-thinking-controls) for the response shape and streaming placement.
11851185 
11861186 Patterns that invalidate later thinking blocks, and what to do instead:
11871187 
11881188 * Editing, reordering, or removing earlier turns. This includes deleting old tool results, snipping turns out of the middle of the transcript, and client-side compaction that keeps recent turns and their thinking blocks verbatim behind a summary (including background compaction that swaps its summary in a few turns later). Instead, use server-side [compaction](https://platform.claude.com/docs/en/build-with-claude/compaction) or [context editing](https://platform.claude.com/docs/en/build-with-claude/context-editing) ([tool result clearing](https://platform.claude.com/docs/en/build-with-claude/context-editing#tool-result-clearing) for old tool results), or one of the client-side compaction shapes in [Trim context on the server](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-trim-context).
1189 * Injecting content you don't persist, for example a per-turn reminder appended after the `tool_result` blocks and removed on the next request. Instead, send the reminder as a [turn-scoped system message](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages#turn-scoped-system-messages) and leave it in the history.
1190 * Rebuilding the top-level `system` prompt or the `tools` array between requests in the same conversation, for example to update the current date or to add or remove a tool. Instead, append a [mid-conversation system message](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages) that carries the new instruction ("The current date is 2026-09-14.") or `tool_addition` and `tool_removal` blocks. A tool that wasn't declared in `tools` at the start can be [defined inside the `tool_addition` block](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages#define-tools-in-a-message-beta) (beta header `inline-tools-2026-09-15`).
1189 * Injecting content you don’t persist, for example a per-turn reminder appended after the `tool_result` blocks and removed on the next request. Instead, send the reminder as a [turn-scoped system message](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages#turn-scoped-system-messages) and leave it in the history.
1190 * Rebuilding the top-level `system` prompt or the `tools` array between requests in the same conversation, for example to update the current date or to add or remove a tool. Instead, append a [mid-conversation system message](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages) that carries the new instruction (“The current date is 2026-09-14.”) or `tool_addition` and `tool_removal` blocks. A tool that wasn’t declared in `tools` at the start can be [defined inside the `tool_addition` block](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages#define-tools-in-a-message-beta) (beta header `inline-tools-2026-09-15`).
11911191 * An image or document URL that serves different bytes on a later request. The check covers the bytes, not the URL string, so a rotating signed URL for the same file is fine. For content you reference across turns, upload it once with the [Files API](https://platform.claude.com/docs/en/build-with-claude/files) and send the `file_id`, or send base64.
11921192 
11931193 Each replacement also keeps earlier turns byte-identical and preserves the [prompt cache](https://platform.claude.com/docs/en/build-with-claude/prompt-caching) hits that editing the history, `system` prompt, or `tools` array would lose.
from line 1197
11971197 * Append-only histories: adding turns and passing earlier turns back exactly as sent and received, including appended `role: "system"` messages.
11981198 * Removing thinking blocks from earlier assistant turns, oldest first.
11991199 * Changing `effort`, `max_tokens`, or any other request parameter outside `model`, `system`, `tools`, and `messages`, and adding or moving `cache_control` markers.
1200 * Server-side compaction and context editing, including [thinking block clearing](https://platform.claude.com/docs/en/build-with-claude/context-editing#thinking-block-clearing). They don't count as edits, because the check compares the conversation as you sent it.
1200 * Server-side compaction and context editing, including [thinking block clearing](https://platform.claude.com/docs/en/build-with-claude/context-editing#thinking-block-clearing). They don’t count as edits, because the check compares the conversation as you sent it.
12011201 
12021202 To check an existing integration:
12031203 
12041204 1. Capture the exact request bodies it sends over a few normal turns, including a compaction or a tool change if your product has them. For each pair of consecutive requests, compare the `system` prompt, the `tools` array, and the shared prefix of `messages`. They should be byte-identical up to the newly appended turns. An expected exception is a request that swaps in a signed `compaction` block from [on-demand compaction](https://platform.claude.com/docs/en/build-with-claude/compaction-on-demand): the block replaces the messages it summarizes at the front of `messages`, and everything after it should still match.
1205 2. Run a normal multi-turn session against `claude-fable-5-1` with the `thinking-binding-controls-2026-08-01` beta header and `prefix_mismatch_behavior: "drop_block"`, and log `input_transformations` on every response. An empty array on every turn means the history is intact. An entry with `reason: "prefix_binding_mismatch"` means something before the block at `path` changed since the previous request. An entry with `reason: "model_binding_mismatch"` means the conversation switched models, which isn't a bug in your code. This works from any account, because setting the field opts the request into enforcement. In CI, set `"error"` instead so an edit fails the run.
1205 2. Run a normal multi-turn session against `claude-fable-5-1` with the `thinking-binding-controls-2026-08-01` beta header and `prefix_mismatch_behavior: "drop_block"`, and log `input_transformations` on every response. An empty array on every turn means the history is intact. An entry with `reason: "prefix_binding_mismatch"` means something before the block at `path` changed since the previous request. An entry with `reason: "model_binding_mismatch"` means the conversation switched models, which isn’t a bug in your code. This works from any account, because setting the field opts the request into enforcement. In CI, set `"error"` instead so an edit fails the run.
12061206 3. Choose a production setting. Leave the default `"error"` if a prefix mismatch can only mean a bug in your code, or set `"drop_block"` to drop the affected blocks instead of failing, and monitor the 400s or the `input_transformations` entries either way.
12071207 
12081208 Dropping thinking blocks once, at a compaction boundary for example, has little effect. An integration that invalidates prior thinking on every request restarts the prompt cache each time, which can raise cost per task (see [Keep the conversation history append-only](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-fable-5-1#keep-the-conversation-history-append-only)).
12091209 
12104. **The advisor tool accepts fewer advisors:** With the [advisor tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/advisor-tool) (beta), the advisor must be at least as capable as the executor. With a `claude-fable-5-1` executor, a less capable advisor, such as `claude-fable-5` or `claude-opus-5-5`, returns a 400 `invalid_request_error`. Choose an advisor from the executor's row in the [compatibility table](https://platform.claude.com/docs/en/agents-and-tools/tool-use/advisor-tool#model-compatibility).
12104. **The advisor tool accepts fewer advisors:** With the [advisor tool](https://platform.claude.com/docs/en/agents-and-tools/tool-use/advisor-tool) (beta), the advisor must be at least as capable as the executor. With a `claude-fable-5-1` executor, a less capable advisor, such as `claude-fable-5` or `claude-opus-5-5`, returns a 400 `invalid_request_error`. Choose an advisor from the executor’s row in the [compatibility table](https://platform.claude.com/docs/en/agents-and-tools/tool-use/advisor-tool#model-compatibility).
12111211 
12121212### Behavior changes
12131213 
from line 1217
12171217 
121812183. **Fewer search and retrieval calls at low effort:** At `low` effort Claude Fable 5.1 answers from memory more often than Claude Fable 5 instead of calling a search or retrieval tool. If your product relies on retrieval at low effort, raise effort for those requests or tell the model when to search. See [Search triggering at low effort](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/prompting-claude-fable-5-1#search-triggering-at-low-effort).
12191219 
1220For the differences in prose density, chat formatting, quoting in summaries, and file edits, which don't affect API integration, see [Changed from Claude Fable 5](https://platform.claude.com/docs/en/models/fable-5-1/whats-new-fable-5-1#changed-from-claude-fable-5).
1220For the differences in prose density, chat formatting, quoting in summaries, and file edits, which don’t affect API integration, see [Changed from Claude Fable 5](https://platform.claude.com/docs/en/models/fable-5-1/whats-new-fable-5-1#changed-from-claude-fable-5).
12211221 
12221222### Recommended changes
12231223 
1224These changes aren't required, but each one lowers cost or latency or removes a failure mode:
1224These changes aren’t required, but each one lowers cost or latency or removes a failure mode:
12251225 
122612261. **Change effort mid-conversation (beta):** On Claude Fable 5, `output_config.effort` is request-level, and changing it between requests drops cached prefixes from earlier turns. On `claude-fable-5-1`, a `role: "system"` message carrying only `output_config` raises effort for a hard step or lowers it for routine ones without invalidating the [prompt cache](https://platform.claude.com/docs/en/build-with-claude/prompt-caching):
12271227 
from line 1491
14911491 ```
14921492 </CodeGroup>
14931493 
1494 Placed between an `assistant` turn and the next `user` turn, as here, the message takes effect from that `user` turn. Placed directly after a `user` turn with new input, it sets the level for Claude's reply to that turn. A `user` turn that holds only tool results doesn't count as new input: the change waits for the next `user` turn with new input. The level then holds until another `role: "system"` message changes it. Only the named levels are accepted (`low`, `medium`, `high`, `xhigh`, `max`), and the `mid-conversation-output-config-2026-07-01` beta header is required. See [Per-message effort](https://platform.claude.com/docs/en/build-with-claude/effort#change-effort-mid-conversation-beta).
1494 Placed between an `assistant` turn and the next `user` turn, as here, the message takes effect from that `user` turn. Placed directly after a `user` turn with new input, it sets the level for Claude’s reply to that turn. A `user` turn that holds only tool results doesn’t count as new input: the change waits for the next `user` turn with new input. The level then holds until another `role: "system"` message changes it. Only the named levels are accepted (`low`, `medium`, `high`, `xhigh`, `max`), and the `mid-conversation-output-config-2026-07-01` beta header is required. See [Per-message effort](https://platform.claude.com/docs/en/build-with-claude/effort#change-effort-mid-conversation-beta).
14951495 
14962. **Change instructions and tools with mid-conversation system messages:** To change instructions or tools partway through a session, append a [`role: "system"` message](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages), with `tool_addition` and `tool_removal` blocks for tool changes (beta header `inline-tools-2026-09-15` on the Claude API). A `tool_addition` block can name a tool declared in `tools` at session start or [carry the tool's full definition](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages#define-tools-in-a-message-beta), so a tool that is unknown at session start doesn't need to be in `tools`. This preserves prompt cache hits on earlier turns and keeps the conversation history append-only. The older `mid-conversation-tool-changes-2026-07-01` header still works for changes that name a tool by reference, on the Claude API, Amazon Bedrock, and Claude Models on Google Cloud (Google managed). The same message replaces forced `tool_choice` when a specific tool must run on the current turn (see [Breaking changes](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-breaking-changes)). For a reminder that applies to one turn only, send it as a separate text-only `role: "system"` message with `clear_at: "next_user_message"` ([turn-scoped system messages](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages#turn-scoped-system-messages), beta header `mid-conversation-system-clear-at-2026-08-21`) and leave it in the history: it stops rendering after the next user message and costs no tokens once cleared. A message that carries `tool_addition` or `tool_removal` blocks can't be turn-scoped.
14962. **Change instructions and tools with mid-conversation system messages:** To change instructions or tools partway through a session, append a [`role: "system"` message](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages), with `tool_addition` and `tool_removal` blocks for tool changes (beta header `inline-tools-2026-09-15` on the Claude API). A `tool_addition` block can name a tool declared in `tools` at session start or [carry the tool’s full definition](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages#define-tools-in-a-message-beta), so a tool that is unknown at session start doesn’t need to be in `tools`. This preserves prompt cache hits on earlier turns and keeps the conversation history append-only. The older `mid-conversation-tool-changes-2026-07-01` header still works for changes that name a tool by reference, on the Claude API, Amazon Bedrock, and Claude Models on Google Cloud (Google managed). The same message replaces forced `tool_choice` when a specific tool must run on the current turn (see [Breaking changes](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-breaking-changes)). For a reminder that applies to one turn only, send it as a separate text-only `role: "system"` message with `clear_at: "next_user_message"` ([turn-scoped system messages](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages#turn-scoped-system-messages), beta header `mid-conversation-system-clear-at-2026-08-21`) and leave it in the history: it stops rendering after the next user message and costs no tokens once cleared. A message that carries `tool_addition` or `tool_removal` blocks can’t be turn-scoped.
14971497 
14983. **Use `fallbacks: "default"` for refusals:** Keep handling `stop_reason: "refusal"` and reading `stop_details.category` before response content. To re-run refused requests on another model automatically, set `fallbacks: "default"` (beta, `server-side-fallback-2026-07-01` header). `"default"` retries a declined request on the model Anthropic recommends for that category. The permitted fallback targets for Claude Fable 5.1 are Claude Opus 4.8 (`claude-opus-4-8`) and Claude Opus 5 (`claude-opus-5`). An explicit `fallbacks` list may name either. The fallback model doesn't receive Claude Fable 5.1's thinking blocks. The `fallbacks` parameter isn't available on Amazon Bedrock, Claude Models on Google Cloud (Google managed), or Microsoft Foundry. On those platforms, use [client-side fallback](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#client-side-fallback) instead. If you build the retry yourself, [fallback credit](https://platform.claude.com/docs/en/build-with-claude/fallback-credit) applies on the same terms as Claude Fable 5. See [Refusals and fallback](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback).
14983. **Use `fallbacks: "default"` for refusals:** Keep handling `stop_reason: "refusal"` and reading `stop_details.category` before response content. To re-run refused requests on another model automatically, set `fallbacks: "default"` (beta, `server-side-fallback-2026-07-01` header). `"default"` retries a declined request on the model Anthropic recommends for that category. The permitted fallback targets for Claude Fable 5.1 are Claude Opus 4.8 (`claude-opus-4-8`) and Claude Opus 5 (`claude-opus-5`). An explicit `fallbacks` list may name either. The fallback model doesn’t receive Claude Fable 5.1’s thinking blocks. The `fallbacks` parameter isn’t available on Amazon Bedrock, Claude Models on Google Cloud (Google managed), or Microsoft Foundry. On those platforms, use [client-side fallback](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#client-side-fallback) instead. If you build the retry yourself, [fallback credit](https://platform.claude.com/docs/en/build-with-claude/fallback-credit) applies on the same terms as Claude Fable 5. See [Refusals and fallback](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback).
14991499 
15004. **Start at `high` effort and sweep:** The [effort parameter](https://platform.claude.com/docs/en/build-with-claude/effort) default is `high`, and all five levels are supported. Keep the Claude Fable 5 guidance: `high` for most work, and `medium` as a cost control worth testing. Claude Fable 5.1's gains over Claude Fable 5 are largest at `xhigh` and `max`, but those levels also add thinking time and time-to-first-response, so step up to them for the most capability-sensitive tasks and where your evals show the gain. Run a fresh sweep on your own evals rather than carrying over a setting tuned for Claude Fable 5. See [Recommended effort levels for Claude Fable 5.1](https://platform.claude.com/docs/en/build-with-claude/effort#recommended-effort-levels-for-claude-fable-5-1).
15004. **Start at `high` effort and sweep:** The [effort parameter](https://platform.claude.com/docs/en/build-with-claude/effort) default is `high`, and all five levels are supported. Keep the Claude Fable 5 guidance: `high` for most work, and `medium` as a cost control worth testing. Claude Fable 5.1’s gains over Claude Fable 5 are largest at `xhigh` and `max`, but those levels also add thinking time and time-to-first-response, so step up to them for the most capability-sensitive tasks and where your evals show the gain. Run a fresh sweep on your own evals rather than carrying over a setting tuned for Claude Fable 5. See [Recommended effort levels for Claude Fable 5.1](https://platform.claude.com/docs/en/build-with-claude/effort#recommended-effort-levels-for-claude-fable-5-1).
15011501 
15025. **Trim context on the server, or compact in a shape that carries no stale thinking:** If your code truncates or summarizes older turns on the client, the simplest fix is to move that work to server-side [compaction](https://platform.claude.com/docs/en/build-with-claude/compaction) or [context editing](https://platform.claude.com/docs/en/build-with-claude/context-editing). Neither counts as an edit, because the [history check](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-preserved-thinking) compares the conversation as you sent it, so nothing they remove invalidates later thinking blocks, and compaction's [`instructions` parameter](https://platform.claude.com/docs/en/build-with-claude/compaction-threshold#custom-summarization-instructions) accepts your own summarization prompt. If you keep recent turns verbatim behind the summary, or summarize in the background while the conversation continues, use [on-demand compaction](https://platform.claude.com/docs/en/build-with-claude/compaction-on-demand) (beta header `compact-2026-09-04`) rather than a client-written summary. The API writes a signed summary block that you put in place of the messages it summarizes. The thinking blocks in the turns you keep can stay valid, under the conditions in [Compaction and preserved thinking](https://platform.claude.com/docs/en/build-with-claude/compaction-thinking-blocks#conditions-for-kept-thinking-to-stay-valid). If you keep compaction on the client, pick one of three shapes:
15025. **Trim context on the server, or compact in a shape that carries no stale thinking:** If your code truncates or summarizes older turns on the client, the simplest fix is to move that work to server-side [compaction](https://platform.claude.com/docs/en/build-with-claude/compaction) or [context editing](https://platform.claude.com/docs/en/build-with-claude/context-editing). Neither counts as an edit, because the [history check](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-preserved-thinking) compares the conversation as you sent it, so nothing they remove invalidates later thinking blocks, and compaction’s [`instructions` parameter](https://platform.claude.com/docs/en/build-with-claude/compaction-threshold#custom-summarization-instructions) accepts your own summarization prompt. If you keep recent turns verbatim behind the summary, or summarize in the background while the conversation continues, use [on-demand compaction](https://platform.claude.com/docs/en/build-with-claude/compaction-on-demand) (beta header `compact-2026-09-04`) rather than a client-written summary. The API writes a signed summary block that you put in place of the messages it summarizes. The thinking blocks in the turns you keep can stay valid, under the conditions in [Compaction and preserved thinking](https://platform.claude.com/docs/en/build-with-claude/compaction-thinking-blocks#conditions-for-kept-thinking-to-stay-valid). If you keep compaction on the client, pick one of three shapes:
15031503 
15041504 * **Simple compaction (recommended):** replace the whole history with one summary message plus the new user turn and replay nothing else. No thinking blocks are carried over, so nothing fails. Claude models are trained on long-horizon tasks with this scheme, and it performs comparably to more elaborate ones for most workloads.
15051505 * **Keep-tail compaction:** if you keep the most recent turns verbatim behind a summary, strip the `thinking` and `redacted_thinking` blocks from those turns (text and tool calls can stay), or set `prefix_mismatch_behavior: "drop_block"`. Their thinking was produced against the full history and fails behind the summary otherwise.
15061506 * **Background compaction:** if you build the summary off the critical path and swap it in later, every turn produced in the meantime carries thinking that predates the swap. Send `"drop_block"` on every request that still carries thinking blocks produced before the swap (or strip those blocks yourself; `input_transformations` on the first response after the swap lists exactly which ones), or compact synchronously.
15071507 
1508 Don't snip individual turns out of the middle of the transcript: that invalidates every later thinking block and no client-side shape avoids it. Use a [mid-conversation system message](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages) for the instruction change you were making, or server-side [context editing](https://platform.claude.com/docs/en/build-with-claude/context-editing) for selective removal. See [Passing compaction blocks back](https://platform.claude.com/docs/en/build-with-claude/compaction-threshold#passing-compaction-blocks-back).
1508 Don’t snip individual turns out of the middle of the transcript: that invalidates every later thinking block and no client-side shape avoids it. Use a [mid-conversation system message](https://platform.claude.com/docs/en/build-with-claude/mid-conversation-system-messages) for the instruction change you were making, or server-side [context editing](https://platform.claude.com/docs/en/build-with-claude/context-editing) for selective removal. See [Passing compaction blocks back](https://platform.claude.com/docs/en/build-with-claude/compaction-threshold#passing-compaction-blocks-back).
15091509 
15101510### Migration checklist
15111511 
from line 1515
15151515* Keep passing `thinking` blocks back unchanged on every turn, including empty ones. Claude Fable 5.1 reads blocks from Claude Opus 5, Claude Fable 5, Claude Mythos 5, and earlier models. Moving a conversation from Claude Fable 5.1 to any model other than Claude Mythos 5.1 drops its blocks.
15161516* If your code builds the `messages` array itself, check whether it [edits earlier turns](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-preserved-thinking): run a session with the `thinking-binding-controls-2026-08-01` beta header and `prefix_mismatch_behavior: "drop_block"`, log `input_transformations`, and fix every `prefix_binding_mismatch`. `model_binding_mismatch` entries after a model switch are expected.
15171517* Keep conversation history append-only. Freeze `system` and `tools` at session start, and move mid-session changes to `role: "system"` messages and `tool_addition` / `tool_removal` blocks. Send per-turn reminders as turn-scoped system messages you never remove. Trim context server-side, or strip thinking blocks from any turns you carry across a client-side summary. Reference cross-turn files by `file_id`.
1518* Pick a production `prefix_mismatch_behavior` (`"error"` by default, or `"drop_block"`) and monitor it. If you maintain a tool that others run with their own API key, test with the field set: new accounts are enforced by default even if yours isn't.
1518* Pick a production `prefix_mismatch_behavior` (`"error"` by default, or `"drop_block"`) and monitor it. If you maintain a tool that others run with their own API key, test with the field set: new accounts are enforced by default even if yours isn’t.
15191519* Review agent loops for one-tool-call-per-turn behavior and add the batching instruction.
15201520* If your interface renders progress text between tool calls, set `thinking.display` to `"updates"` (beta) or `"summarized"` and prompt for updates.
15211521* If you change effort between requests, move the change to a [per-message effort](https://platform.claude.com/docs/en/build-with-claude/effort#change-effort-mid-conversation-beta) `role: "system"` message (beta) to keep cache hits.
15221522* Handle `stop_reason: "refusal"` and read `stop_details.category`. Consider `fallbacks: "default"` (beta).
15231523* Re-evaluate `effort` with a fresh sweep, starting at `high`, and re-baseline cost and latency on your own workloads. The tokenizer is unchanged. Prompt cache reads cost a quarter of the Claude Fable 5 rate.
1524* If you have a [Priority Tier commitment](https://platform.claude.com/docs/en/api/service-tiers#existing-priority-tier-commitments) for your current model, it doesn't cover Claude Fable 5.1, which isn't supported on Priority Tier.
1524* If you have a [Priority Tier commitment](https://platform.claude.com/docs/en/api/service-tiers#existing-priority-tier-commitments) for your current model, it doesn’t cover Claude Fable 5.1, which isn’t supported on Priority Tier.
15251525 
15261526## Migrating to Claude Fable 5.1 from Claude Opus 5
15271527 
from line 1543
15431543 
154415442. **Forced tool choice is not supported:** Claude Opus 5 accepts `tool_choice` `any` and `tool`. `claude-fable-5-1` returns a 400 error. See [Breaking changes](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-breaking-changes).
15451545 
15463. **Preserved thinking across models:** Claude Fable 5.1 reads Claude Opus 5's thinking blocks: conversations moving from `claude-opus-5` to `claude-fable-5-1` keep their reasoning. Claude Opus 5 can't read Claude Fable 5.1's blocks. Claude Fable 5.1's blocks also [stop being valid when earlier turns change](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-preserved-thinking): if your code edits earlier messages, rebuilds `system` or `tools`, or compacts on the client between requests, Claude Opus 5 returns no error, but `claude-fable-5-1` rejects or drops every later thinking block. Run the three-step check in that section before switching traffic. See [Breaking changes](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-breaking-changes).
15463. **Preserved thinking across models:** Claude Fable 5.1 reads Claude Opus 5’s thinking blocks: conversations moving from `claude-opus-5` to `claude-fable-5-1` keep their reasoning. Claude Opus 5 can’t read Claude Fable 5.1’s blocks. Claude Fable 5.1’s blocks also [stop being valid when earlier turns change](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-preserved-thinking): if your code edits earlier messages, rebuilds `system` or `tools`, or compacts on the client between requests, Claude Opus 5 returns no error, but `claude-fable-5-1` rejects or drops every later thinking block. Run the three-step check in that section before switching traffic. See [Breaking changes](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-breaking-changes).
15471547 
154815484. **Text between tool calls is returned in thinking blocks:** On Claude Opus 5, text the model writes between tool calls comes back as `text` blocks. On `claude-fable-5-1`, as on Claude Fable 5, that narration comes back as progress-update `thinking` blocks, one before each tool call. Under the default `thinking.display` of `"omitted"`, they carry no readable text. If your interface renders that narration, set `display: "updates"` (beta) to receive progress updates as text while reasoning stays hidden, or `"summarized"` to receive both. Then render the non-empty `thinking` blocks between `tool_use` blocks. See [Progress updates between tool calls](https://platform.claude.com/docs/en/build-with-claude/thinking#progress-updates).
15491549 
15505. **Safety classifiers and fallback routing:** Claude Fable 5.1 runs safety classifiers covering the same `stop_details` categories as Claude Fable 5, a broader set than Claude Opus 5's classifiers. Expect additional `stop_details.category` values, such as `"bio"`; see the [refusal category table](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#refusal-response) for the full set. For `fallbacks` configuration and permitted targets, see [Use `fallbacks: "default"` for refusals](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-recommended-changes).
15505. **Safety classifiers and fallback routing:** Claude Fable 5.1 runs safety classifiers covering the same `stop_details` categories as Claude Fable 5, a broader set than Claude Opus 5’s classifiers. Expect additional `stop_details.category` values, such as `"bio"`; see the [refusal category table](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback#refusal-response) for the full set. For `fallbacks` configuration and permitted targets, see [Use `fallbacks: "default"` for refusals](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-recommended-changes).
15511551 
155215526. **Pricing:** $10 USD per million input tokens and $50 USD per million output tokens, compared with $5 USD and $25 USD for Claude Opus 5. Prompt cache reads are $0.25 USD per million tokens, half the Claude Opus 5 rate. See [Claude pricing](https://platform.claude.com/docs/en/about-claude/pricing).
15531553 
15547. **Data retention:** Claude Fable 5.1 and Claude Mythos 5.1 require 30-day data retention, aren't available under zero data retention (ZDR) arrangements unless expressly authorized by Anthropic, and are designated Covered Models. Claude Opus 5 is available under ZDR. See [Model-specific data retention requirements](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#model-specific-data-retention-requirements).
15547. **Data retention:** Claude Fable 5.1 and Claude Mythos 5.1 require 30-day data retention, aren’t available under zero data retention (ZDR) arrangements unless expressly authorized by Anthropic, and are designated Covered Models. Claude Opus 5 is available under ZDR. See [Model-specific data retention requirements](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#model-specific-data-retention-requirements).
15551555 
15561556### Migration checklist
15571557 
1558* If your organization has a zero data retention (ZDR) arrangement, confirm eligibility first: these models aren't available under ZDR unless expressly authorized by Anthropic. See [Model-specific data retention requirements](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#model-specific-data-retention-requirements).
1558* If your organization has a zero data retention (ZDR) arrangement, confirm eligibility first: these models aren’t available under ZDR unless expressly authorized by Anthropic. See [Model-specific data retention requirements](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention#model-specific-data-retention-requirements).
15591559* Update the model name from `claude-opus-5` to `claude-fable-5-1` (or `claude-mythos-5-1`).
15601560* Remove any `thinking: {type: "disabled"}` configuration: it returns a 400 error on `claude-fable-5-1`. Control token spend with lower [effort](https://platform.claude.com/docs/en/build-with-claude/effort) levels, and revisit `max_tokens`.
15611561* If you removed `thinking: {type: "disabled"}`, update response parsing that reads content by position, such as `content[0].text`: a response can now start with `thinking` blocks, so select content blocks by `type` instead.
from line 1580
15801580 
15811581### Migration checklist
15821582 
1583* If your organization has a zero data retention (ZDR) arrangement, confirm eligibility first: these models aren't available under ZDR unless expressly authorized by Anthropic. Claude Opus 4.8 is available under ZDR.
1583* If your organization has a zero data retention (ZDR) arrangement, confirm eligibility first: these models aren’t available under ZDR unless expressly authorized by Anthropic. Claude Opus 4.8 is available under ZDR.
15841584* Update the model name from `claude-opus-4-8` to `claude-fable-5-1` (or `claude-mythos-5-1`).
15851585* Remove any `thinking: {type: "disabled"}` configuration and revisit `max_tokens`. Requests without a `thinking` field run with adaptive thinking.
15861586* Update response parsing that reads content by position, such as `content[0].text`: a response can now start with `thinking` blocks, so select content blocks by `type` instead.
15871587* Replace forced `tool_choice` (`any` or `tool`) with `auto` plus an explicit instruction (`user` turn or mid-conversation system message) and `strict: true` tools, or with JSON outputs.
1588* Pass `thinking` blocks back unchanged and treat their text as display-only. Claude Fable 5.1 reads Claude Opus 4.8's thinking blocks: a conversation that moves onto `claude-fable-5-1` keeps its earlier reasoning. Claude Opus 4.8 can't read Claude Fable 5.1's blocks.
1588* Pass `thinking` blocks back unchanged and treat their text as display-only. Claude Fable 5.1 reads Claude Opus 4.8’s thinking blocks: a conversation that moves onto `claude-fable-5-1` keeps its earlier reasoning. Claude Opus 4.8 can’t read Claude Fable 5.1’s blocks.
15891589* If your code builds the `messages` array itself, check whether it [edits earlier turns](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-preserved-thinking). Integrations written for Claude Opus 4.8 and earlier often truncate old turns, strip or rebuild earlier messages, or refresh the `system` prompt each request, and Claude Opus 4.8 returns no error for any of them. On `claude-fable-5-1` each of those invalidates later thinking blocks.
15901590* Handle `stop_reason: "refusal"`, read `stop_details.category`, and consider `fallbacks: "default"` (beta).
15911591* Apply the advisor, Priority Tier, preserved-thinking, history-editing, behavior, per-message effort, and progress-update items from the [Claude Fable 5 checklist](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#migration-checklist-fable-5-1-from-fable-5).
from line 1593
15931593 
15941594## Migrating to Claude Mythos 5.1 from Claude Mythos 5
15951595 
1596[Claude Mythos 5.1](https://platform.claude.com/docs/en/models/mythos-5-1/overview) is the counterpart to Claude Fable 5.1 for organizations verified through Anthropic's verification programs, such as the [Cyber Verification Program](https://support.claude.com/en/articles/14604842). Confirm that your organization has access to Claude Mythos 5.1 before you switch model IDs.
1596[Claude Mythos 5.1](https://platform.claude.com/docs/en/models/mythos-5-1/overview) is the counterpart to Claude Fable 5.1 for organizations verified through Anthropic’s verification programs, such as the [Cyber Verification Program](https://support.claude.com/en/articles/14604842). Confirm that your organization has access to Claude Mythos 5.1 before you switch model IDs.
15971597 
15981598The API-level delta matches [Migrating to Claude Fable 5.1 from Claude Fable 5](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#migrating-from-claude-fable-5-to-claude-fable-5-1):
15991599 
16001600* Forced tool choice returns a 400 error.
16011601* The advisor tool accepts fewer advisors.
1602* Only Claude Mythos 5.1 and Claude Fable 5.1 read Claude Mythos 5.1's thinking blocks (Claude Mythos 5.1 reads Claude Mythos 5's blocks, not the reverse).
1602* Only Claude Mythos 5.1 and Claude Fable 5.1 read Claude Mythos 5.1’s thinking blocks (Claude Mythos 5.1 reads Claude Mythos 5’s blocks, not the reverse).
16031603 
1604Unlike Claude Fable 5.1, Claude Mythos 5.1 doesn't run the conversation check, so editing earlier turns doesn't [invalidate thinking blocks](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-preserved-thinking), though it still restarts the prompt cache.
1604Unlike Claude Fable 5.1, Claude Mythos 5.1 doesn’t run the conversation check, so editing earlier turns doesn’t [invalidate thinking blocks](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#fable-5-1-preserved-thinking), though it still restarts the prompt cache.
16051605 
16061606### Update your model name
16071607 
from line 1616
16161616* Replace forced `tool_choice` (`any` or `tool`) with `auto` plus an explicit instruction (`user` turn or mid-conversation system message) and `strict: true` tools, or with JSON outputs.
16171617* Handle `stop_reason: "refusal"` and read `stop_details.category` before response content. See [Refusals and fallback](https://platform.claude.com/docs/en/build-with-claude/refusals-and-fallback).
16181618* Keep passing `thinking` blocks back unchanged on every turn, including empty ones.
1619* If your code builds the `messages` array itself, keep conversation history append-only to keep the prompt cache warm. Claude Mythos 5.1 doesn't run the [conversation check](https://platform.claude.com/docs/en/build-with-claude/thinking#preserved-in-conversation), so edits don't invalidate its thinking blocks.
1620* Apply the advisor, behavior, and recommended changes from the [Claude Fable 5 section](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#migrating-from-claude-fable-5-to-claude-fable-5-1), except the history-editing items, which don't apply to Claude Mythos 5.1.
1619* If your code builds the `messages` array itself, keep conversation history append-only to keep the prompt cache warm. Claude Mythos 5.1 doesn’t run the [conversation check](https://platform.claude.com/docs/en/build-with-claude/thinking#preserved-in-conversation), so edits don’t invalidate its thinking blocks.
1620* Apply the advisor, behavior, and recommended changes from the [Claude Fable 5 section](https://platform.claude.com/docs/en/models/fable-5-1/migration-guide#migrating-from-claude-fable-5-to-claude-fable-5-1), except the history-editing items, which don’t apply to Claude Mythos 5.1.
16211621* Re-evaluate `effort` with a fresh sweep and re-baseline cost and latency. Prompt cache reads cost a quarter of the Claude Mythos 5 rate.
16221622 

models/fable-5-1/overview Changed · +5 / -5 lines

from line 16
1616 
1717## Overview
1818 
19Claude Fable 5.1 extends Claude Fable 5 at the same input and output prices, with cache reads at a quarter of the cost, and brings stronger long-running agentic coding, multistep research, and document, spreadsheet, and slide work. For most workloads, start with Claude Opus 5.5 (see [Choosing a model](https://platform.claude.com/docs/en/about-claude/models/choosing-a-model)). Use Claude Fable 5.1 for demanding reasoning and long-horizon agentic work, or when your evals on Claude Opus 5.5 at higher effort still don't meet your requirements. Claude Mythos 5.1 offers the same capabilities only to organizations verified through Anthropic's verification programs, such as the [Cyber Verification Program](https://support.claude.com/en/articles/14604842).
19Claude Fable 5.1 extends Claude Fable 5 at the same input and output prices, with cache reads at a quarter of the cost, and brings stronger long-running agentic coding, multistep research, and document, spreadsheet, and slide work. For most workloads, start with Claude Opus 5.5 (see [Choosing a model](https://platform.claude.com/docs/en/about-claude/models/choosing-a-model)). Use Claude Fable 5.1 for demanding reasoning and long-horizon agentic work, or when your evals on Claude Opus 5.5 at higher effort still don’t meet your requirements. Claude Mythos 5.1 offers the same capabilities only to organizations verified through Anthropic’s verification programs, such as the [Cyber Verification Program](https://support.claude.com/en/articles/14604842).
2020 
2121If you already call Claude Fable 5, four changes are breaking:
2222 
2323* [Forced tool use returns an error](https://platform.claude.com/docs/en/models/fable-5-1/whats-new-fable-5-1#forced-tool-use-is-not-supported).
24* Only Claude Fable 5.1 and Claude Mythos 5.1 can [read Claude Fable 5.1's thinking blocks](https://platform.claude.com/docs/en/models/fable-5-1/whats-new-fable-5-1#thinking-blocks-are-tied-to-the-model-that-produced-them).
24* Only Claude Fable 5.1 and Claude Mythos 5.1 can [read Claude Fable 5.1’s thinking blocks](https://platform.claude.com/docs/en/models/fable-5-1/whats-new-fable-5-1#thinking-blocks-are-tied-to-the-model-that-produced-them).
2525* [Editing earlier turns invalidates thinking blocks](https://platform.claude.com/docs/en/models/fable-5-1/whats-new-fable-5-1#editing-earlier-turns-invalidates-thinking-blocks).
2626* [Some advisor tool pairings are not supported](https://platform.claude.com/docs/en/models/fable-5-1/whats-new-fable-5-1#advisor-tool-pairings).
2727 
from line 33
3333* A [lower cache read price](https://platform.claude.com/docs/en/models/fable-5-1/whats-new-fable-5-1#pricing)
3434* [Content provenance](https://platform.claude.com/docs/en/models/fable-5-1/whats-new-fable-5-1#content-provenance)
3535 
36[What's new in Claude Fable 5.1](https://platform.claude.com/docs/en/models/fable-5-1/whats-new-fable-5-1)
36[What’s new in Claude Fable 5.1](https://platform.claude.com/docs/en/models/fable-5-1/whats-new-fable-5-1)
3737 
3838## Claude Fable 5.1 and Claude Mythos 5.1
3939 
40[Claude Mythos 5.1](https://platform.claude.com/docs/en/models/mythos-5-1/overview) offers the same capabilities only to organizations verified through Anthropic's verification programs, such as the [Cyber Verification Program](https://support.claude.com/en/articles/14604842). It shares Claude Fable 5.1's specifications and pricing. To request access, apply to the program that covers your use case, or contact your Anthropic, AWS, or Google Cloud account team.
40[Claude Mythos 5.1](https://platform.claude.com/docs/en/models/mythos-5-1/overview) offers the same capabilities only to organizations verified through Anthropic’s verification programs, such as the [Cyber Verification Program](https://support.claude.com/en/articles/14604842). It shares Claude Fable 5.1’s specifications and pricing. To request access, apply to the program that covers your use case, or contact your Anthropic, AWS, or Google Cloud account team.
4141 
4242## How it compares
4343 
from line 116
116116 </Card>
117117 
118118 <Card title="Preserved thinking" icon="brain" href="https://platform.claude.com/docs/en/build-with-claude/thinking#preserved-thinking">
119 When this model's thinking blocks stay usable: across model switches and across changes to the conversation.
119 When this model’s thinking blocks stay usable: across model switches and across changes to the conversation.
120120 </Card>
121121 
122122 <Card title="Per-message effort" icon="sliders" href="https://platform.claude.com/docs/en/build-with-claude/effort#change-effort-mid-conversation-beta">
Feedback