# Anthropic Managed Agents (beta) Status: DOCUMENTED · BETA (anthropic-beta: managed-agents-2026-04-01) — live probe results are appended in section "Live verification" by the parent agent Sources (all retrieved 2026-09-18, offline copies under `sources/anthropic/pages/managed-agents/**` and `sources/anthropic/pages/api/beta/**`): - Guides: https://platform.claude.com/docs/en/managed-agents/overview · quickstart · agent-setup · sessions · session-operations · events-and-streaming · environments · cloud-sandboxes-reference · self-hosted-sandboxes · self-hosted-sandboxes-security · tools · mcp-connector · skills · memory · files · multiagent-orchestration · budgets · define-outcomes · permission-policies · vaults · scheduled-deployments · dreams · webhooks · github · migration · onboarding · reference (all under `https://platform.claude.com/docs/en/managed-agents/`) - REST reference: `https://platform.claude.com/docs/en/api/beta/{agents,sessions,environments,deployments,deployment_runs,dreams,memory_stores,vaults,tunnels,user_profiles,webhooks}/**` (pre-parsed to `tmp/platform-anthropic/ref/*.json`) - MCP tunnels: https://platform.claude.com/docs/en/agents-and-tools/mcp-tunnels/{overview,concepts,reference} - Machine-readable twins produced with this page: `generated/fragments/streaming-events/anthropic-managed-agents.json` (88 event records), `tmp/platform-anthropic/objects-managed-agents.json` (37 object records), `tmp/platform-anthropic/examples-agents.json` + `examples/anthropic/agents/*` Last verified: 2026-09-18 (documentation only; no live call was made while writing this page) --- ## 1. What Managed Agents is Claude Managed Agents is a **pre-built, configurable agent harness that runs in Anthropic-managed infrastructure**. Instead of writing an agent loop against the Messages API (maintain history, iterate `tool_use` blocks, run tools, loop), you create an **Agent** (model + system prompt + tools + MCP servers + skills), an **Environment** (where the sandbox runs), start a **Session**, and exchange **Events** over REST + SSE. The harness provides prompt caching, context compaction, a Linux sandbox with pre-installed runtimes, server-side persisted history, budgets, outcomes/grading, multi-agent threads, memory stores, scheduled runs and webhooks. | | Messages API | Claude Managed Agents | |---|---|---| | What it is | Direct model prompting access | Pre-built agent harness in managed infrastructure | | Best for | Custom agent loops, fine-grained control | Long-running tasks, asynchronous work | | Loop / tool execution | You | Anthropic (built-in tools in sandbox); you only handle `custom` tools | | History | You pass `messages` every call | Persisted server-side; you send/receive events | | End of work | You decide | `session.status_idle` event | Relation to the **Claude Agent SDK** (from the migration guide): `ClaudeAgentOptions` → `POST /v1/agents` (persisted, versioned); `ClaudeSDKClient`/`query()` → `POST /v1/sessions` + events; `@tool` functions → `{"type":"custom",...}` on the agent + `agent.custom_tool_use` / `user.custom_tool_result` events; built-in tools → `agent_toolset_20260401` in the sandbox against `/workspace`; `cwd`/`add_dirs` → file / repo resources; `system_prompt` + `CLAUDE.md` → single `system` string (versioned); `mcp_servers` → declared on the agent, authenticated via a **Vault** on the session; `permission_mode`/`can_use_tool` → per-tool `permission_policy` (`always_allow` | `always_ask` | `auto`) + `user.tool_confirmation`. Things that move to your client: plan mode (run a planning session first), output styles / slash commands, `PreToolUse`/`PostToolUse` hooks (use `always_ask` or custom-tool handling), `max_turns` (count client-side). **Beta access.** All Managed Agents endpoints require `anthropic-beta: managed-agents-2026-04-01` (SDKs set it). Enabled by default for all API accounts. Within the beta, **MCP tunnels** and **dreaming** are a more limited research preview (request access). Also available on Claude Platform on AWS with differences (self-hosted workers authenticate with IAM SigV4 / AWS-console API key; memory stores cannot be attached to self-hosted sessions there). **Data retention.** Stateful by design (history, sandbox state, outputs stored server-side) → **not eligible for Zero Data Retention or HIPAA BAA**. You can delete sessions and uploaded files at any time. Related but separate betas (do not mix headers where noted): | Surface | Beta header | Notes | |---|---|---| | Managed Agents core (agents, sessions, environments, deployments, vaults, files scope filter, work queue) | `managed-agents-2026-04-01` | | | Memory stores (`/v1/memory_stores/**`) | `agent-memory-2026-07-22` | Sending **both** headers on a memory-store call returns 400. Attaching a store to a session still uses `managed-agents-2026-04-01`. (The REST reference pages list only the generic `anthropic-beta` header.) | | Dreams (`/v1/dreams/**`) | `managed-agents-2026-04-01,dreaming-2026-04-21` | Research preview; `dreaming-2026-04-21` required in addition | | Tunnels API (`/v1/tunnels/**`) | `mcp-tunnels-2026-06-22` + WIF bearer with `workspace:manage_tunnels` | Research preview; Admin API keys not accepted; supersedes `/v1/organizations/tunnels` (`mcp-tunnels-2026-05-19`, `org:manage_tunnels`, deprecation notice) | | User profiles (`/v1/user_profiles/**`) | `user-profiles-2026-09-04` (older `-03-24`, `-08-18`) | Not referenced by any Managed Agents guide; documented in §17 for completeness only | --- ## 2. Architecture ```mermaid flowchart LR subgraph Client["Your application"] APP[REST client / SDK / ant CLI] WH[Webhook endpoint HTTPS:443] WK[Self-hosted worker\nEnvironmentWorker / ant beta:worker] CT[Custom tool executor] end subgraph Anthropic["Anthropic control plane (api.anthropic.com, beta managed-agents-2026-04-01)"] AG[Agent\n/v1/agents (versioned)] SS[Session\n/v1/sessions] TH[Session threads\n/threads (multiagent, advisor)] EV[(Event log\n/events · /events/stream SSE)] ENV[Environment\n/v1/environments] DEP[Deployment (cron)\n/v1/deployments → deployment_runs] VLT[Vault + credentials\n/v1/vaults] MEM[Memory stores\n/v1/memory_stores (+memories, versions)] DRM[Dream\n/v1/dreams] FILES[Files API\n/v1/files (scope_id=session)] SK[Skills\n/v1/skills + Anthropic skills] TUN[MCP tunnels\n/v1/tunnels + certificates + token] WQ[(Work queue\n/environments/{id}/work)] end subgraph Exec["Execution"] CS[Cloud sandbox\nUbuntu 24.04, 8 GB, 10 GB\n/workspace /mnt/session/uploads /mnt/session/outputs /mnt/memory] SH[Self-hosted sandbox\nyour infrastructure] end subgraph Ext["External"] MCP[Remote MCP servers\n(HTTP streamable / SSE fallback)] PMCP[Private MCP servers] GH[GitHub repos + GitHub MCP] WEB[web_search / web_fetch\n(run on Anthropic servers)] end APP -->|create/update/archive| AG APP -->|create/list/update/archive/delete| SS APP -->|send user.* / system.message| EV EV -->|SSE agent.* session.* span.* event_start/delta| APP SS --> TH --> EV SS -->|environment_id| ENV AG -->|snapshot at create| SS DEP -->|schedule / run now| SS SS -->|vault_ids| VLT SS -->|resources: file / github_repository / memory_store| FILES SS --> MEM SS --> GH AG -->|skills[]| SK ENV -->|type: cloud| CS ENV -->|type: self_hosted| WQ WQ -->|poll / ack / heartbeat / stop| WK --> SH WK -->|user.tool_result / custom tool results| EV CS -->|bash read write edit glob grep| CS CS --> WEB SS -->|mcp_servers + mcp_toolset| MCP MCP -.->|tunnel domain| TUN --> PMCP MEM --> DRM DRM -->|new output store| MEM EV -->|agent.custom_tool_use| CT -->|user.custom_tool_result| EV SS -->|session.* deployment.* vault.* agent.* environment.* memory_store.*| WH ``` Core concepts (overview): | Concept | Description | |---|---| | **Agent** | Model, system prompt, tools, MCP servers, skills (+ `multiagent` roster). Versioned, reusable by ID | | **Environment** | Where sessions run: Anthropic-managed **cloud** sandbox or **self_hosted** sandbox (your worker polls a work queue) | | **Session** | A running agent instance in an environment; owns history, sandbox state, usage, budget, threads | | **Events** | Messages exchanged with the agent (`user.*`/`system.message` in; `agent.*`, `session.*`, `span.*`, previews out) | --- ## 3. Session lifecycle **Statuses** (`session.status`): `idle` (waiting for input; sessions created without `initial_events` start here) · `running` · `rescheduling` (transient error, retrying) · `terminated` (unrecoverable error or archived; a session that finishes work goes `idle`, not `terminated`). Thread statuses are the same set. ```mermaid stateDiagram-v2 [*] --> idle: POST /v1/sessions (no initial_events) [*] --> running: POST /v1/sessions with initial_events (max 50) idle --> running: user.message / user.define_outcome / settle events resolve requires_action / budget raised running --> idle: end_turn · requires_action (tool ask / custom tool) · retries_exhausted · budget_reached running --> rescheduling: transient error (session.status_rescheduled) rescheduling --> running: retry running --> terminated: terminal error idle --> terminated: POST /archive idle --> [*]: DELETE (session.deleted ends any stream) ``` Run loop per turn (from events-and-streaming, "Accumulate and reconcile"): `session.status_running` → (`session.thread_status_running`) → for each model request `span.model_request_start` → [`event_start` → `event_delta`* if previews on] → `agent.message` / `agent.thinking` / `agent.tool_use` + `agent.tool_result` / `agent.mcp_tool_use` + `agent.mcp_tool_result` / `agent.custom_tool_use` → `span.model_request_end` → … → `session.thread_status_idle` → **`session.usage`** (always immediately before idle) → `session.status_idle{stop_reason}`. Key rules: | Topic | Rule | |---|---| | Starting work | Creating a session registers it and starts provisioning the sandbox; work starts on the first `user.message`/`user.define_outcome` (or via `initial_events`) | | `initial_events` | `user.message` and `user.define_outcome` only (max 50, ≤1 define_outcome, rubric required, ≤100 file-sourced `document` blocks, body ≤32 MB → 413). Validation all-or-nothing. Not echoed in the create response (list events to see them). Unlike deployments, sessions' `initial_events` do not accept `system.message` | | Interrupt | `user.interrupt` (optionally `session_thread_id`) stops the model response immediately; tool calls may delay it; turn ends with `session.status_idle` `stop_reason.type = end_turn` (no interrupt-specific reason). Against a thread blocked on `requires_action`, pending tool calls are closed with an error tool result. No-op on an idle thread. Ignored while the whole session is paused at budget | | requires_action | `stop_reason: {type:"requires_action", event_ids:[…]}`; resolve every id with `user.tool_confirmation` (tool_use_id), `user.custom_tool_result` (custom_tool_use_id) or `user.tool_result` (self-hosted). Resolving fewer than all re-emits `session.status_idle` with the remainder. The session waits indefinitely | | Resume | Send another `user.message`; history persists until deletion. Sandbox state checkpointed on idle but **preserved only 30 days after sandbox creation** (not extended by activity) → write deliverables to `/mnt/session/outputs` | | Update while running | Agent `tools`/`mcp_servers` and archive/delete require `idle`; send `user.interrupt` alone, wait for idle | | Reconnect | Open a new stream, list `/events` to seed seen IDs, then tail; only events emitted after the stream opens are delivered (open the stream before sending) | | Threads (multiagent) | Session-level stream = **primary thread** (condensed view + cross-posted blocking events). Each child thread has `/threads/{id}/events` and `/threads/{id}/stream`. Max **25 concurrent threads** (advisor threads exempt); archive idle threads to free slots | | processed_at | Set when the event finishes processing; null while queued, except `user.define_outcome`, `user.custom_tool_result`, `user.tool_result` (processed on receipt) | | Redacted blocks | Platform may emit `{"type":"redacted"}` (model policy). Clients cannot send one (400) | --- ## 4. Endpoint inventory (resource tree) All paths relative to `https://api.anthropic.com`. Headers on every call: `x-api-key`, `anthropic-version: 2023-06-01`, `anthropic-beta: managed-agents-2026-04-01` (exceptions in §1 table), optional `anthropic-workspace-id`. Pagination on list endpoints: `limit`, opaque `page` cursor; responses carry `data[]`, `next_page`, `prev_page` (null at ends); `order` (`asc`|`desc`, default `desc` by creation time) where offered; a cursor encodes the `order` it was created with (changing it → 400). Rate limits (per organization): **create endpoints 300 req/min; read endpoints (retrieve, list, stream) 1,200 req/min**. | Resource | Endpoints | Count | |---|---|---| | Agents | list, create, retrieve (`?version=`), update, archive, versions.list | 6 | | Sessions | list, create, retrieve, update, archive, delete | 6 | | Session events | list, send, stream | 3 | | Session resources | list, add, retrieve, update, delete | 5 | | Session threads | list, retrieve, archive, events.list, stream | 5 | | Environments | list, create, retrieve, update, archive, delete | 6 | | Environment work queue (self-hosted) | list, poll, stats, retrieve, update, ack, heartbeat, stop | 8 | | Deployments | list, create, retrieve, update, archive, pause, unpause, run | 8 | | Deployment runs | list, retrieve | 2 | | Dreams | list, create, retrieve, archive, cancel | 5 | | Memory stores | list, create, retrieve, update, archive, delete | 6 | | Memories | list, create, retrieve, update, delete | 5 | | Memory versions | list, retrieve, redact | 3 | | Vaults | list, create, retrieve, update, archive, delete | 6 | | Credentials | list, create, retrieve, update, archive, delete, mcp_oauth_validate | 7 | | Tunnels (`/v1/tunnels`) | list, create, retrieve, archive, certificates.{list,create,retrieve,archive}, reveal_token, rotate_token | 10 | | Org tunnels (legacy `/v1/organizations/tunnels`) | list, retrieve, archive, certificates.{list,create,retrieve,archive}, reveal_token, rotate_token | 9 | | User profiles (separate beta) | list, create, retrieve, update, enrollment_url | 5 | | **Total** | | **105** (96 excluding legacy org tunnels) | Delete endpoints return `{type: "_deleted"/…, id}` confirmation objects (`BetaManagedAgentsDeletedSession`, `BetaEnvironmentDeleteResponse`, `BetaManagedAgentsDeletedMemoryStore`, `BetaManagedAgentsDeletedMemory`, `BetaManagedAgentsDeletedVault`, `BetaManagedAgentsDeletedCredential`, `BetaManagedAgentsDeleteSessionResource`). --- ## 5. Agents Guide: https://platform.claude.com/docs/en/managed-agents/agent-setup | Method | Path | Title | Key params | Pagination | Status | |---|---|---|---|---|---| | GET | `/v1/agents` | List Agents | query `include_archived`, `created_at[gte]`, `created_at[lte]`, `limit`, `page` | cursor | DOCUMENTED, BETA | | POST | `/v1/agents` | Create Agent | body `name`*, `model`*, `system`, `description`, `tools[]`, `mcp_servers[]`, `skills[]`, `multiagent`, `metadata` | — | DOCUMENTED, BETA | | GET | `/v1/agents/{agent_id}` | Get Agent | query `version` (fetch a specific version) | — | DOCUMENTED, BETA | | POST | `/v1/agents/{agent_id}` | Update Agent | body: any create field (nullable arrays) + optional `version` (optimistic concurrency → 409 on mismatch) | — | DOCUMENTED, BETA | | POST | `/v1/agents/{agent_id}/archive` | Archive Agent | — (irreversible; read-only; existing sessions continue) | — | DOCUMENTED, BETA | | GET | `/v1/agents/{agent_id}/versions` | List Agent Versions | `limit`, `page` | cursor | DOCUMENTED, BETA | **Agent object** (`BetaManagedAgentsAgent`, `type: "agent"`): | Field | Type | Notes | |---|---|---| | `id` | string (`agent_…`) | | | `version` | integer | Starts at 1; increments on each update that changes configuration; no-op updates return the existing version | | `name`* | string | Mandatory, not clearable | | `model`* | `ModelConfig {id, effort, speed, inference_geo}` | Request accepts a model id string or object. `id` enum in reference (14 ids incl. `claude-fable-5-1`, `claude-fable-5`, `claude-sonnet-5`, `claude-opus-5`, `claude-opus-4-8`, `claude-opus-4-7`, `claude-opus-4-6`, `claude-opus-4-5`, `claude-sonnet-4-6`, `claude-haiku-4-5`, `claude-haiku-4-5-20251001`) or any string; Claude 4.5+ supported. `effort`: `low`|`medium`|`high`|`xhigh`|`max` (string or `{type}`); `speed`: `standard`|`fast` (fast mode: Opus 5 / Opus 4.8); `inference_geo`: `"us"`|`"global"` (validated against workspace `allowed_inference_geos` at save, session create and every turn) | | `system` | string or null | ≤100,000 chars (per overrides docs) | | `description`, `metadata` | string/null, map (≤16 pairs, keys ≤64, values ≤512) | metadata merges key-wise on update (`null` deletes a key) | | `tools[]` | union `agent_toolset_20260401` \| `mcp_toolset` \| `custom` | ≤128 entries across toolsets; arrays are fully replaced on update | | `mcp_servers[]` | `{type:"url", name (1–255, unique), url (≤2,048)}` | ≤20; every server must be referenced by an `mcp_toolset` and vice versa | | `skills[]` | `{type:"anthropic"\|"custom", skill_id, version?}` | `version` defaults to `latest`; ≤500 skills per session (deduplicated across agents) | | `multiagent` | `{type:"coordinator", agents[]}` or null | Roster of 1–20 entries: agent id string, `{type:"agent",id,version?}`, `{type:"self"}`, `{type:"advisor", model}` (max one). Pinned at coordinator save time | | `created_at`, `updated_at`, `archived_at` | RFC 3339 | | Update semantics: omitted fields preserved; scalars replaced (`system`/`description` clearable with null); within `model`, omitting `effort` keeps it when `id` unchanged, resets to default when `id` changes; supplying `model` without `inference_geo` clears the pin; arrays replaced wholesale (`null`/`[]` clears); `multiagent` replaced as a whole; coordinator rosters keep their pinned versions until the coordinator is updated. Archiving a deployment's agent archives the deployment. --- ## 6. Sessions Guides: https://platform.claude.com/docs/en/managed-agents/sessions · https://platform.claude.com/docs/en/managed-agents/session-operations | Method | Path | Title | Key params | Pagination | Status | |---|---|---|---|---|---| | GET | `/v1/sessions` | List Sessions | `agent_id`, `agent_version`, `deployment_id`, `memory_store_id`, `statuses[]` (rescheduling\|running\|idle\|terminated), `include_archived`, `created_at[gt\|gte\|lt\|lte]`, `order`, `limit`, `page` | cursor + `order` | DOCUMENTED, BETA | | POST | `/v1/sessions` | Create Session | `agent`* (id string \| `{type:"agent",id,version}` \| `{type:"agent_with_overrides",id,version?,model?,system?,tools?,mcp_servers?,skills?}`), `environment_id`*, `title`, `metadata`, `resources[]`, `vault_ids[]`, `budget`, `initial_events[]` | — | DOCUMENTED, BETA | | GET | `/v1/sessions/{session_id}` | Get Session | — | — | DOCUMENTED, BETA | | POST | `/v1/sessions/{session_id}` | Update Session | `agent.{tools,mcp_servers}` (full replacement, session must be idle), `budget` (replace or `null`), `title`, `metadata` (patch), `vault_ids` (reserved: rejected) | — | DOCUMENTED, BETA | | POST | `/v1/sessions/{session_id}/archive` | Archive Session | — (not while running) | — | DOCUMENTED, BETA | | DELETE | `/v1/sessions/{session_id}` | Delete Session | — (not while running; removes record, events, sandbox and session-produced files) | — | DOCUMENTED, BETA | **Session object** (`BetaManagedAgentsSession`, `type: "session"`): | Field | Type | Notes | |---|---|---| | `id` | `sesn_…` | | | `agent` | `SessionAgent` snapshot `{type:"agent", id, version, name, description, model, system, tools, mcp_servers, skills, multiagent}` | Configuration the session runs with (after overrides); `id`/`version` still identify the base agent | | `environment_id` | string | | | `status` | `idle`\|`running`\|`rescheduling`\|`terminated` | Aggregate of all threads | | `title`, `metadata` | | | | `budget` | `{type:"limit", max_list_cost:{amount (cents string), currency:"USD"}}` or null | See §13 | | `resources[]` | `file` \| `github_repository` \| `memory_store` resource objects (each with `id` `sesrsc_…`) | memory_store resource echoes `mount_path`, `access`, `instructions`, snapshotted `name`/`description` | | `vault_ids[]` | | Attached at creation | | `outcome_evaluations[]` | `{type:"outcome_evaluation", outcome_id, description, iteration, result, explanation, completed_at}` | `result`: pending \| running \| evaluating \| satisfied \| needs_revision \| max_iterations_reached \| failed \| interrupted | | `stats` | `{active_seconds, duration_seconds}` | active_seconds here sums per-thread activity | | `usage` | `{input_tokens, output_tokens, cache_read_input_tokens, cache_creation{ephemeral_5m_input_tokens, ephemeral_1h_input_tokens}, list_cost{amount,currency}, active_seconds, server_tool_use{web_search_requests, web_fetch_requests}}` | `usage.active_seconds` deduplicates overlapping threads and is what runtime cost is priced on; `web_fetch_requests` reads 0 (not metered) | | `deployment_id` | string or null | Set when created by a deployment | | `created_at`, `updated_at`, `archived_at` | | | Override rules (`agent_with_overrides`): omit = inherit; `null`/`[]` = clear (except `model` never clearable → 400 `agent_model_required`; clearing `tools` fails while `skills` non-empty because skills need `read`; clearing `mcp_servers` fails while an `mcp_toolset` still references one); a value replaces in full (no merge). `effort` inside a `model` override is not applied (session runs at the model default). A `model` override also sets/clears `inference_geo`. Overrides never modify the agent resource; in multiagent sessions they apply to the coordinator and its `self` copies only. ### 6.1 Session resources | Method | Path | Title | Key params | Status | |---|---|---|---|---| | GET | `/v1/sessions/{session_id}/resources` | List Session Resources | `limit`, `page` | DOCUMENTED, BETA | | POST | `/v1/sessions/{session_id}/resources` | Add Session Resource | body `{type:"file", file_id*, mount_path?}` (files only; repos and memory stores are creation-time only) | DOCUMENTED, BETA | | GET | `/v1/sessions/{session_id}/resources/{resource_id}` | Get Session Resource | — | DOCUMENTED, BETA | | POST | `/v1/sessions/{session_id}/resources/{resource_id}` | Update Session Resource | body `{authorization_token*}` (rotate a GitHub token) | DOCUMENTED, BETA | | DELETE | `/v1/sessions/{session_id}/resources/{resource_id}` | Delete Session Resource | — (remove a file) | DOCUMENTED, BETA | Resource variants: `file {file_id, mount_path}` (mounted read-only under `/mnt/session/uploads/`, ≤500 files/session; a new session-scoped `file_id` copy is created, not counted against storage limits), `github_repository {url (https://github.com//, no .git), authorization_token (write-only), mount_path (default /workspace/), checkout {type:"branch",name} | {type:"commit",sha}}`, `memory_store {memory_store_id, access: read_write (default) | read_only, instructions (≤4,096)}` (≤8 stores/session; self-hosted environments accept **only** `memory_store` resources → file/repo → 400). ### 6.2 Session threads (multiagent) | Method | Path | Title | Key params | Status | |---|---|---|---|---| | GET | `/v1/sessions/{session_id}/threads` | List Session Threads | `limit`, `page` (includes primary; `parent_thread_id` null for primary) | DOCUMENTED, BETA | | GET | `/v1/sessions/{session_id}/threads/{thread_id}` | Get Session Thread | — | DOCUMENTED, BETA | | POST | `/v1/sessions/{session_id}/threads/{thread_id}/archive` | Archive Session Thread | thread must be idle (requires_action counts as idle) | DOCUMENTED, BETA | | GET | `/v1/sessions/{session_id}/threads/{thread_id}/events` | List Session Thread Events | `limit`, `page` | DOCUMENTED, BETA | | GET | `/v1/sessions/{session_id}/threads/{thread_id}/stream` | Stream Session Thread Events | `event_deltas[]` (SSE) — note path is `/threads/{id}/stream`, **not** `/events/stream` | DOCUMENTED, BETA | **SessionThread** (`type: "session_thread"`): `id` (`sthr_…`), `session_id`, `parent_thread_id`, `agent` (`SessionThreadAgent` snapshot or `{type:"advisor", model}`), `status`, `stats {active_seconds, duration_seconds, startup_seconds}`, `usage` (same shape as session usage; per-thread `list_cost` excludes runtime cost and does not sum exactly to the session figure), timestamps. --- ## 7. Events (full catalogue) Guide: https://platform.claude.com/docs/en/managed-agents/events-and-streaming · reference tabs: https://platform.claude.com/docs/en/managed-agents/reference#event-types · REST: `GET/POST /v1/sessions/{id}/events`, `GET /v1/sessions/{id}/events/stream`. | Method | Path | Title | Key params | Status | |---|---|---|---|---| | GET | `/v1/sessions/{session_id}/events` | List Events | `types[]` filter, `created_at[gt\|gte\|lt\|lte]`, `order`, `limit`, `page` → `data[]` of persisted events | DOCUMENTED, BETA | | POST | `/v1/sessions/{session_id}/events` | Send Events | body `{events:[…]}` → `{data:[echoed events with ids]}`; returns as soon as queued | DOCUMENTED, BETA | | GET | `/v1/sessions/{session_id}/events/stream` | Stream Events | SSE (`accept: text/event-stream`, `data: {json}` lines); query `event_deltas[]` ∈ {`agent.message`, `agent.thinking`} (≤100 values; other → 400) | DOCUMENTED, BETA | Naming: persisted types follow `{domain}.{action}`; the stream-only previews `event_start`/`event_delta` are the exception. Every persisted event has `id` (`sevt_…`), `type`, `processed_at`. ### 7.1 Client → server (7 types; `POST …/events`, also `initial_events`) | Event | Params | Notes | |---|---|---| | `user.message` | `content[]`: `text {text}`, `image {source: base64 \| url \| file}`, `document {source: base64 \| text \| url \| file, title?, context?}` (`redacted` blocks rejected) | Starts/continues work. Rejected with 400 while the session is at its budget | | `user.interrupt` | `session_thread_id?` | Stops the agent; no stop reason of its own | | `user.tool_confirmation` | `tool_use_id`* (1–128), `result`* `allow`\|`deny`, `deny_message?` (≤10,000, deny only) | For `agent.tool_use`/`agent.mcp_tool_use` with `evaluated_permission: "ask"`; several per request OK; server routes to the right thread | | `user.custom_tool_result` | `custom_tool_use_id`*, `content[]` (`text`, `image`, `document`, `search_result {source,title,content[],citations{enabled}}`), `is_error?` | Answers `agent.custom_tool_use` | | `user.define_outcome` | `description`*, `rubric`* `{type:"text",content}` \| `{type:"file",file_id}`, `max_iterations?` (default 3, max 20) | Agent starts immediately; echoed with `outcome_id` (`outc_…`); one outcome at a time (chain after terminal `span.outcome_evaluation_end`) | | `user.tool_result` | `tool_use_id`*, `content[]`, `is_error?` | **Self-hosted environments only**: your worker returns agent-toolset results | | `system.message` | `content[]` of `{type:"text", text}` (1–1000 items) | Appended as a `role:"system"` turn for this and later turns; at most one per request, must be last; while `requires_action`, only accepted trailing a tool-result event. Supported models: Claude Fable 5.1, Mythos 5.1, Fable 5, Mythos 5, Opus 5, Opus 4.8 — else 400 `model_does_not_support_mid_conversation_system`. Deployments' `initial_events` accept it; sessions' `initial_events` do not | ### 7.2 Server → client (37 variants in `BetaManagedAgentsStreamSessionEvents`; 35 persisted + 2 stream-only) Echoes of the 7 client events above appear on the stream/history with server ids (`user.*`, `system.message`). The remaining server-originated types: | Group | Event | Key fields | Description | |---|---|---|---| | agent | `agent.message` | `content[]` (`text` \| `redacted`) | Buffered response content; authoritative record for previews | | agent | `agent.thinking` | — | Progress signal only (no thinking content) | | agent | `agent.tool_use` | `name`, `input`, `evaluated_permission` (allow\|ask\|deny), `evaluation` (`{type:"always_allow"}` \| `{type:"always_ask"}` \| `{type:"auto", evaluated_permission:{type:allow\|ask\|deny, reason_code?}}`; absent when tool not enabled or on old events), `session_thread_id?` (cross-posted) | Pre-built tool call | | agent | `agent.tool_result` | `tool_use_id`, `content[]`, `is_error` | e.g. `url_not_allowed` for blocked web_fetch; outputs >100,000 chars written to a sandbox file | | agent | `agent.mcp_tool_use` | `mcp_server_name`, `name`, `input`, `evaluated_permission`, `evaluation`, `session_thread_id?` | | | agent | `agent.mcp_tool_result` | `mcp_tool_use_id`, `content[]`, `is_error` | | | agent | `agent.custom_tool_use` | `name`, `input`, `session_thread_id?` | Session idles with `requires_action` until `user.custom_tool_result`; no permission fields | | agent | `agent.thread_context_compacted` | — | Context compaction happened | | agent | `agent.thread_message_received` | `from_session_thread_id`, `from_agent_name?`, `content[]` | Message arrived from another thread (advice from `anthropic.advisor` arrives this way) | | agent | `agent.thread_message_sent` | `to_session_thread_id`, `to_agent_name?`, `content[]` | This thread sent a message | | session | `session.status_running` | — | Turn opens | | session | `session.status_idle` | `stop_reason`: `{type:"end_turn"}` \| `{type:"requires_action", event_ids[]}` \| `{type:"retries_exhausted"}` \| `{type:"budget_reached"}` | | | session | `session.status_rescheduled` | — | Transient error, retrying | | session | `session.status_terminated` | — | Unrecoverable error or archived | | session | `session.deleted` | — | Ends any stream | | session | `session.updated` | `agent?`, `budget?`, `title?`, `metadata?` (only changed fields) | Applies from next turn | | session | `session.error` | `error {type, message, retry_status {type: retrying\|exhausted\|terminal}, …}` | Types: `unknown_error`, `model_overloaded_error`, `model_rate_limited_error`, `model_request_failed_error`, `mcp_connection_failed_error {mcp_server_name}`, `mcp_authentication_failed_error {mcp_server_name}`, `billing_error`, `credential_host_unreachable_error {credential_id, vault_id}` | | session | `session.usage` | `usage` (SessionUsageSnapshot), `budget` or null | Emitted immediately before every idle and when a thread pauses at budget | | session | `session.thread_created` | `session_thread_id`, `agent_name` | | | session | `session.thread_status_running` / `_idle {stop_reason}` / `_rescheduled` / `_terminated` | `session_thread_id`, `agent_name` | Emitted on the thread's own stream and cross-posted to the primary for child threads | | span | `span.model_request_start` | — | | | span | `span.model_request_end` | `model_request_start_id`, `is_error`, `model_usage {input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens, speed}` | Also closes unreconciled previews | | span | `span.outcome_evaluation_start` | `outcome_id`, `iteration` (0-indexed) | | | span | `span.outcome_evaluation_ongoing` | `outcome_id`, `iteration` | Heartbeat | | span | `span.outcome_evaluation_end` | `outcome_evaluation_start_id` (empty string if interrupted before start), `outcome_id`, `iteration`, `result` (satisfied \| needs_revision \| max_iterations_reached \| failed \| interrupted), `explanation`, `usage` | | | preview | `event_start` | `event {type: agent.message \| agent.thinking, id}` | Stream-only, never persisted, no own id | | preview | `event_delta` | `event_id`, `delta {type:"content_delta", index, content {type:"text", text}}` | Stream-only; only for `agent.message` (thinking previews are start-only) | **Event deltas (previews)** — opt in per connection with `event_deltas[]=agent.message` (percent-encode `%5B%5D`). Sequence per model request: `span.model_request_start` → `event_start` → `event_delta`* → buffered `agent.message` (same `id`) → `span.model_request_end`. Accumulate keyed by `(event_id, index)`; the buffered event replaces the preview; close leftovers on `span.model_request_end`. Guarantees: concatenated deltas are a **prefix** of `content[index].text` (deltas may be shed under load); at most one `event_start` per id per connection. Limitations: best effort, no replay on reconnect, one thread and text only, never persisted. Wire format intentionally differs from Messages API streaming (no `content_block_start/stop`, delta type `content_delta` not `content_block_delta`). Troubleshooting: no previews → connection didn't opt in or turn ran on another thread; 404 on stream → wrong path/id or missing beta header (thread endpoints are beta-gated); 400 naming `event_deltas` → only `agent.message`/`agent.thinking` accepted. --- ## 8. Environments (cloud sandboxes) Guides: https://platform.claude.com/docs/en/managed-agents/environments · https://platform.claude.com/docs/en/managed-agents/cloud-sandboxes-reference | Method | Path | Title | Key params | Pagination | Status | |---|---|---|---|---|---| | GET | `/v1/environments` | List Environments | `include_archived`, `limit`, `page` | cursor | DOCUMENTED, BETA | | POST | `/v1/environments` | Create Environment | `name`*, `config` (`{type:"cloud", networking?, packages?}` \| `{type:"self_hosted"}` \| null), `description`, `metadata`, `scope` (`organization`\|`account`) | — | DOCUMENTED, BETA | | GET | `/v1/environments/{environment_id}` | Get Environment | — | — | DOCUMENTED, BETA | | POST | `/v1/environments/{environment_id}` | Update Environment | same fields; omitted config fields preserved; environments are **not versioned** | — | DOCUMENTED, BETA | | POST | `/v1/environments/{environment_id}/archive` | Archive Environment | read-only; existing sessions continue; no new sessions | — | DOCUMENTED, BETA | | DELETE | `/v1/environments/{environment_id}` | Delete Environment | only if no sessions reference it → `BetaEnvironmentDeleteResponse {type,id}` | — | DOCUMENTED, BETA | **Environment object** (`BetaEnvironment`, `type: "environment"`): `id` (`env_…`), `name`, `description`, `metadata`, `scope`, `config`, `created_at`, `updated_at`, `archived_at`. **Cloud config** (`BetaCloudConfig`): | Field | Values | Notes | |---|---|---| | `networking.type` | `unrestricted` (default for API-created; general safety blocklist) \| `limited` | Controls sandbox egress only; **does not affect `web_search`/`web_fetch`** (Anthropic servers) — use per-tool `allowed_domains`/`blocked_domains`. Console-provisioned sandboxes default to `limited` | | `networking.allowed_hosts[]` (limited) | bare hostnames or `*.example.com` wildcards; no scheme/port/path | | | `networking.allow_mcp_servers` | bool, default false | egress to MCP servers declared on the agent | | `networking.allow_package_managers` | bool, default false | egress to public registries; **required true when `packages` set** (else 400, even if registries listed) | | `packages.{apt,cargo,gem,go,npm,pip}[]` | strings, optional version pins (`sqlalchemy==2.0.30`, `express@4.18.0`, `rails:7.1.0`, `hyperfine@1.18.0`, `…@latest`) | Installed before the agent starts, cached across sessions of the environment; managers run alphabetically (apt, cargo, gem, go, npm, pip) | Sandbox spec: Ubuntu 24.04 LTS, x86_64, **up to 8 GB RAM, up to 10 GB disk**; each session gets a fresh isolated container (no shared filesystem between sessions). Pre-installed: Python 3.10–3.13 (pip/uv/poetry + NumPy, pandas, Matplotlib, openpyxl, python-docx, python-pptx, pypdf), Node 20/21/22 (npm/yarn/pnpm/bun), Go 1.24/1.25, Rust stable, OpenJDK 21, Ruby 3.1–3.3, PHP 8.3, GCC 13/Clang; PostgreSQL 16 and Redis 7 installed but not running; SQLite; git, curl, wget, jq, yq, tar/zip, tmux, make/cmake, docker (limited), ripgrep, vim/nano, ffmpeg, ImageMagick, pandoc, LibreOffice headless, Poppler + qpdf, tesseract (eng), TeX Live, Playwright (Python + Node) with Chromium at `/opt/pw-browsers` (`PLAYWRIGHT_BROWSERS_PATH` preset; no Firefox/WebKit). Paths: `/workspace` (default cwd, repos), `/mnt/session/uploads/` (mounted files, read-only), `/mnt/session/outputs/` (deliverables → Files API `scope_id=`), `/mnt/memory//` (memory stores). --- ## 9. Self-hosted sandboxes (work queue) Guides: https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes · https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-security · reference "Self-hosted worker" CLI flags. Model: orchestration and the model stay at Anthropic; tool execution (bash/read/write/edit/glob/grep, custom tools) runs on your host. A `self_hosted` environment is a **work queue**: each session assigned to it becomes a work item; your worker polls, claims, downloads skills to `/skills//`, executes tool calls, posts results (`user.tool_result`) and stops. Workers authenticate with an **environment key** (`ANTHROPIC_ENVIRONMENT_KEY`, `sk-ant-oat01-…`, **generated in the Console only**), not your API key. Claimed work items may carry a per-session `secret` (required to mount memory stores; env key rejected by memory endpoints). Patterns: always-on poller (`ant beta:worker poll`, SDK `EnvironmentWorker.run()`), sandbox-per-session (`ant beta:worker poll --on-work spawn.sh` → `ant beta:worker run` or SDK `handle_item()`), webhook-triggered (wake on `session.status_run_started`). | Method | Path | Title | Key params | Auth | Status | |---|---|---|---|---|---| | GET | `/v1/environments/{environment_id}/work` | List Work Items | `limit`, `page` → `{data[], next_page}` | API key or env key | DOCUMENTED, BETA | | GET | `/v1/environments/{environment_id}/work/poll` | Poll for Work | `block_ms` (1–999; default non-blocking), `reclaim_older_than_ms` (default 5000); header `Anthropic-Worker-ID` (for `workers_polling`) → one `work` item | env key (worker) | DOCUMENTED, BETA | | GET | `/v1/environments/{environment_id}/work/stats` | Get Queue Statistics | → `{type:"work_queue_stats", depth, pending, oldest_queued_at, workers_polling}` | API key (ops) | DOCUMENTED, BETA | | GET | `/v1/environments/{environment_id}/work/{work_id}` | Get Work Item | — | | DOCUMENTED, BETA | | POST | `/v1/environments/{environment_id}/work/{work_id}` | Update Work Item | body `metadata` patch (string upsert / null delete) | | DOCUMENTED, BETA | | POST | `/v1/environments/{environment_id}/work/{work_id}/ack` | Acknowledge Work | queued → starting, removes from queue | env key | DOCUMENTED, BETA | | POST | `/v1/environments/{environment_id}/work/{work_id}/heartbeat` | Record Heartbeat | query `desired_ttl_seconds`, `expected_last_heartbeat` (`NO_HEARTBEAT` for first; echo previous value; optimistic concurrency) → `{type:"work_heartbeat", last_heartbeat, lease_extended, state, ttl_seconds}` | env key | DOCUMENTED, BETA | | POST | `/v1/environments/{environment_id}/work/{work_id}/stop` | Stop Work | body `force` (true = `stopped` immediately; default graceful → `stopping`, worker cancels in-flight tool call and confirms) | API key or env key | DOCUMENTED, BETA | **WorkItem** (`BetaSelfHostedWork`, `type:"work"`): `id` (`work_…`), `environment_id`, `data {type:"session", id}`, `state` (`queued`\|`starting`\|`active`\|`stopping`\|`stopped`), `secret` (only populated on poll), `metadata`, `created_at`, `acknowledged_at`, `started_at`, `latest_heartbeat_at`, `stop_requested_at`, `stopped_at`. CLI flags (`ant beta:worker`): `--environment-id`, `--environment-key`, `--workdir` (default `.`; system default `/workspace`), `--on-work