diff --git a/skills/claude-api/shared/live-sources.md b/skills/claude-api/shared/live-sources.md index d2f835519..b116d6705 100644 --- a/skills/claude-api/shared/live-sources.md +++ b/skills/claude-api/shared/live-sources.md @@ -82,6 +82,8 @@ Use these when a managed-agents binding, behavior, or wire-level detail isn't co | Define Outcomes | `https://platform.claude.com/docs/en/managed-agents/define-outcomes.md` | "Extract outcome definitions, evaluation hooks, and success criteria configuration" | | Sessions | `https://platform.claude.com/docs/en/managed-agents/sessions.md` | "Extract session lifecycle, status transitions, idle/terminated semantics, and resume rules" | | Environments | `https://platform.claude.com/docs/en/managed-agents/environments.md` | "Extract environment config (cloud/networking), management endpoints, and reuse model" | +| Self-Hosted Sandboxes | `https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes.md` | "Extract config:{type:self_hosted}, ANTHROPIC_ENVIRONMENT_KEY, EnvironmentWorker.run/run_one, beta_agent_toolset, ant beta:worker poll/run, webhook-driven wake" | +| Self-Hosted Sandboxes — Security | `https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes-security.md` | "Extract what the customer owns (hardening, egress, key custody, trust boundaries) vs what Anthropic cannot do" | | Events and Streaming | `https://platform.claude.com/docs/en/managed-agents/events-and-streaming.md` | "Extract event stream types, stream-first ordering, reconnect/dedupe, and steering patterns" | | Tools | `https://platform.claude.com/docs/en/managed-agents/tools.md` | "Extract built-in toolset, custom tool definitions, and tool result wire format" | | Files | `https://platform.claude.com/docs/en/managed-agents/files.md` | "Extract file upload, mount paths, session resources, and listing/downloading session outputs" | diff --git a/skills/claude-api/shared/managed-agents-api-reference.md b/skills/claude-api/shared/managed-agents-api-reference.md index d018d3399..1a40c794d 100644 --- a/skills/claude-api/shared/managed-agents-api-reference.md +++ b/skills/claude-api/shared/managed-agents-api-reference.md @@ -21,6 +21,7 @@ All resources are under the `beta` namespace. Python and TypeScript share identi | Agents | `agents.create` / `retrieve` / `update` / `list` / `archive` | `Agents.New` / `Get` / `Update` / `List` / `Archive` | | Agent Versions | `agents.versions.list` | `Agents.Versions.List` | | Environments | `environments.create` / `retrieve` / `update` / `list` / `delete` / `archive` | `Environments.New` / `Get` / `Update` / `List` / `Delete` / `Archive` | +| Environment Work (self-hosted) | `environments.work.poller` / `stats` / `stop` | See `shared/managed-agents-self-hosted-sandboxes.md` | | Sessions | `sessions.create` / `retrieve` / `update` / `list` / `delete` / `archive` | `Sessions.New` / `Get` / `Update` / `List` / `Delete` / `Archive` | | Session Events | `sessions.events.list` / `send` / `stream` | `Sessions.Events.List` / `Send` / `StreamEvents` | | Session Threads | `sessions.threads.list` / `retrieve` / `archive`; `sessions.threads.events.list` / `stream` | `Sessions.Threads.List` / `Get` / `Archive`; `Sessions.Threads.Events.List` / `StreamEvents` | @@ -35,6 +36,7 @@ All resources are under the `beta` namespace. Python and TypeScript share identi - Agents and Session Threads have **no delete** — only `archive`. Archive is **permanent**: the agent becomes read-only, new sessions cannot reference it, and there is no unarchive. Confirm with the user before archiving a production agent. Environments, Sessions, Vaults, Credentials, and Memory Stores have both `delete` and `archive`; Session Resources, Files, Skills, and Memories are `delete`-only; Memory Versions have neither — only `redact`. - Session resources use `add` (not `create`). - Go's event stream is `StreamEvents` (not `Stream`). +- The self-hosted worker is **not** under `client.beta.*` — it's `EnvironmentWorker` from `anthropic.lib.environments` / `@anthropic-ai/sdk/helpers/beta/environments`; only `environments.work.poller/stats/stop` are client methods. **Agent shorthand:** `agent` on session create accepts either a bare string (`agent="agent_abc123"` — uses latest version) or the full reference object (`{type: "agent", id: "agent_abc123", version: 123}`). @@ -62,7 +64,7 @@ All resources are under the `beta` namespace. Python and TypeScript share identi | `GET` | `/v1/sessions` | ListSessions | List sessions (paginated) | | `POST` | `/v1/sessions` | CreateSession | Create a new session | | `GET` | `/v1/sessions/{session_id}` | GetSession | Get session details | -| `POST` | `/v1/sessions/{session_id}` | UpdateSession | Update session metadata/title | +| `POST` | `/v1/sessions/{session_id}` | UpdateSession | Update session `metadata`/`title`, or `agent.tools`/`agent.mcp_servers`/`vault_ids` (session-local override; session must be `idle`). See `shared/managed-agents-core.md` → Updating the agent configuration mid-session. | | `DELETE` | `/v1/sessions/{session_id}` | DeleteSession | Delete a session | | `POST` | `/v1/sessions/{session_id}/archive` | ArchiveSession | Archive a session | @@ -106,6 +108,10 @@ Per-subagent event streams in multiagent sessions. See `shared/managed-agents-mu | `POST` | `/v1/environments/{environment_id}` | UpdateEnvironment | Update environment | | `DELETE` | `/v1/environments/{environment_id}` | DeleteEnvironment | Delete environment. Returns 204. | | `POST` | `/v1/environments/{environment_id}/archive` | ArchiveEnvironment | Archive environment. Makes it **read-only**; existing sessions continue, new sessions cannot reference it. No unarchive — this is the terminal state. | +| `GET` | `/v1/environments/{environment_id}/work/stats` | WorkQueueStats | Self-hosted work-queue depth/pending/workers. `x-api-key` auth. See `shared/managed-agents-self-hosted-sandboxes.md`. | +| `POST` | `/v1/environments/{environment_id}/work/{work_id}/stop` | StopWork | Self-hosted: stop a claimed work item. `x-api-key` auth. | + +For `type: "self_hosted"`, `config` is the bare `{"type": "self_hosted"}` — `networking` and `packages` do not apply. ## Vaults @@ -270,7 +276,7 @@ Immutable per-mutation snapshots (`memver_...`) — the audit and rollback surfa "name": "string (required)", "description": "string (optional)", "config": { - "type": "cloud", + "type": "cloud | self_hosted", "networking": { "type": "unrestricted | limited (union — see SDK types)" }, diff --git a/skills/claude-api/shared/managed-agents-core.md b/skills/claude-api/shared/managed-agents-core.md index f5e0127e1..94817ed58 100644 --- a/skills/claude-api/shared/managed-agents-core.md +++ b/skills/claude-api/shared/managed-agents-core.md @@ -218,3 +218,21 @@ session = client.beta.sessions.create( ) ``` +### Updating the agent configuration mid-session + +`sessions.update()` can change `agent.tools`, `agent.mcp_servers` (including permission policies), and `vault_ids` on an **existing** session. This is a **session-local override** — it does not create a new agent version and does not propagate back to the agent object. The provided arrays are **full replacements**; to append one tool, `GET` the session, modify, and `POST` back. The session must be `idle` — interrupt first if running. + +```python +client.beta.sessions.update( + session.id, + agent={ + "tools": [ + {"type": "agent_toolset_20260401"}, + {"type": "mcp_toolset", "mcp_server_name": "linear"}, + ], + "mcp_servers": [{"type": "url", "name": "linear", "url": "https://mcp.linear.app/sse"}], + }, + vault_ids=["vlt_..."], +) +``` + diff --git a/skills/claude-api/shared/managed-agents-environments.md b/skills/claude-api/shared/managed-agents-environments.md index 6724503ba..45e8e04b8 100644 --- a/skills/claude-api/shared/managed-agents-environments.md +++ b/skills/claude-api/shared/managed-agents-environments.md @@ -38,6 +38,10 @@ const env = await client.beta.environments.create({ }); ``` +### Self-hosted sandboxes + +To run tool execution in **your own infrastructure** instead of Anthropic's, set `config: {type: "self_hosted"}` — the agent loop stays on Anthropic's side, but `bash` / file ops / code execute in a container you control via an outbound-polling worker. The `networking` block does not apply (you control egress). Resource mounting (`file`, `github_repository`) and memory stores behave differently — see `shared/managed-agents-self-hosted-sandboxes.md` for the worker, credentials, and cloud-vs-self-hosted comparison. + ### Environment CRUD | Operation | Method | Path | Notes | diff --git a/skills/claude-api/shared/managed-agents-onboarding.md b/skills/claude-api/shared/managed-agents-onboarding.md index e6bc3416d..6601ff4f1 100644 --- a/skills/claude-api/shared/managed-agents-onboarding.md +++ b/skills/claude-api/shared/managed-agents-onboarding.md @@ -8,11 +8,11 @@ Use this when a user wants to set up a Managed Agent from scratch. Three steps: --- -Claude Managed Agents is a hosted agent: Anthropic runs the agent loop on its orchestration layer and provisions a sandboxed container per session where the agent's tools execute. You supply the agent config and the environment config; the harness — event stream, sandbox orchestration, prompt caching, context compaction, and extended thinking — is handled for you. +Claude Managed Agents is a hosted agent: Anthropic runs the agent loop on its orchestration layer and provisions a sandboxed container per session where the agent's tools execute (or, with a `self_hosted` environment, your own worker runs the tools — see `shared/managed-agents-self-hosted-sandboxes.md`). You supply the agent config and the environment config; the harness — event stream, sandbox orchestration, prompt caching, context compaction, and extended thinking — is handled for you. **What you supply:** - **An agent config** — tools, skills, model, system prompt. Reusable and versioned. -- **An environment config** — the sandbox your agent's tools execute in (networking, packages). Reusable across agents. +- **An environment config** — the sandbox your agent's tools execute in (`cloud`: networking, packages; or `self_hosted`: your own infra). Reusable across agents. Each run of the agent is a **session**. diff --git a/skills/claude-api/shared/managed-agents-overview.md b/skills/claude-api/shared/managed-agents-overview.md index 689f510df..37f4c74d1 100644 --- a/skills/claude-api/shared/managed-agents-overview.md +++ b/skills/claude-api/shared/managed-agents-overview.md @@ -17,7 +17,7 @@ If you're about to write `sessions.create()` with `model`, `system`, or `tools` **When generating code, separate setup from runtime.** `agents.create()` belongs in a setup script (or a guarded `if agent_id is None:` block), not at the top of the hot path. If the user's code calls `agents.create()` on every invocation, they're accumulating orphaned agents and paying the create latency for nothing. The correct shape is: create once → persist the ID (config file, env var, secrets manager) → every run loads the ID and calls `sessions.create()`. -**To change the agent's behavior, use `POST /v1/agents/{id}` — don't create a new one.** Each update bumps the version; running sessions keep their pinned version, new sessions get the latest (or pin explicitly via `{type: "agent", id, version}`). See `shared/managed-agents-core.md` → Agents → Versioning. +**To change the agent's behavior, use `POST /v1/agents/{id}` — don't create a new one.** Each update bumps the version; running sessions keep their pinned version, new sessions get the latest (or pin explicitly via `{type: "agent", id, version}`). See `shared/managed-agents-core.md` → Agents → Versioning. To change `tools`/`mcp_servers`/`vault_ids` on **one running session** without touching the agent object, use `sessions.update()` — see `shared/managed-agents-core.md` → Updating the agent configuration mid-session. ## Beta Headers @@ -49,6 +49,7 @@ Managed Agents is in beta. The SDK sets required beta headers automatically: | Define an outcome / rubric-graded iterate loop | `shared/managed-agents-outcomes.md` — `user.define_outcome` event, grader, `span.outcome_evaluation_*` events | | Coordinate multiple agents / subagents / threads | `shared/managed-agents-multiagent.md` — `multiagent: {type: "coordinator", agents: [...]}` on the agent, session threads, cross-posted tool confirmations | | Set up environments | `shared/managed-agents-environments.md` + language file | +| Run tool execution in your own infra / VPC (self-hosted sandbox) | `shared/managed-agents-self-hosted-sandboxes.md` — `config:{type:"self_hosted"}`, `ANTHROPIC_ENVIRONMENT_KEY`, `EnvironmentWorker.run()` / `ant beta:worker poll` | | Upload files / attach repos | `shared/managed-agents-environments.md` (Resources) | | Give agents persistent memory across sessions | `shared/managed-agents-memory.md` — memory stores, `memory_store` session resource, preconditions, versions/redact | | Store MCP credentials | `shared/managed-agents-tools.md` (Vaults section) | @@ -63,5 +64,5 @@ Managed Agents is in beta. The SDK sets required beta headers automatically: - **SSE stream has no replay — reconnect with consolidation** — if the stream drops while a `agent.tool_use`, `agent.mcp_tool_use`, or `agent.custom_tool_use` is pending resolution (`user.tool_confirmation` for the first two, `user.custom_tool_result` for the last one), the session deadlocks (client disconnects → session idles → reconnect happens → no client resolution happens). On every (re)connect: open stream with `GET /v1/sessions/{id}/events/stream` , fetch `GET /v1/sessions/{id}/events`, dedupe by event ID, then proceed. See `shared/managed-agents-events.md` → Reconnecting after a dropped stream. - **Don't trust HTTP-library timeouts as wall-clock caps** — `requests` `timeout=(c, r)` and `httpx.Timeout(n)` are *per-chunk* read timeouts; they reset every byte, so a trickling connection can block indefinitely. For a hard deadline on raw-HTTP polling, track `time.monotonic()` at the loop level and bail explicitly. Prefer the SDK's `sessions.events.stream()` / `session.events.list()` over hand-rolled HTTP. See `shared/managed-agents-events.md` → Receiving Events. - **Messages queue** — you can send events while the session is `running` or `idle`; they're processed in order. No need to wait for a response before sending the next message. -- **Cloud environments only** — `config.type: "cloud"` is the only supported environment type. +- **Environment `config.type` is `"cloud"` or `"self_hosted"`** — `cloud` runs the container on Anthropic's infrastructure; `self_hosted` moves tool execution to your own (see `shared/managed-agents-self-hosted-sandboxes.md`). - **Archive is permanent on every resource** — archiving an agent, environment, session, vault, credential, or memory store makes it read-only with no unarchive. For agents, environments, and memory stores specifically, archived resources cannot be referenced by new sessions (existing sessions continue). Do not call `.archive()` on a production agent, environment, or memory store as cleanup — **always confirm with the user before archiving**. diff --git a/skills/claude-api/shared/managed-agents-self-hosted-sandboxes.md b/skills/claude-api/shared/managed-agents-self-hosted-sandboxes.md new file mode 100644 index 000000000..091becc6b --- /dev/null +++ b/skills/claude-api/shared/managed-agents-self-hosted-sandboxes.md @@ -0,0 +1,173 @@ +# Managed Agents — Self-Hosted Sandboxes + +With `config.type: "self_hosted"`, the **agent loop stays on Anthropic's orchestration layer** but **tool execution moves to infrastructure you control** — bash, file ops, and code run inside your container, so filesystem contents and network egress never leave your environment. Contrast with `config.type: "cloud"`, where Anthropic runs the container. Connectivity is **outbound-only**: your worker long-polls Anthropic's work queue; Anthropic never dials into your network. + +## Flow + +``` +1. Create environment: config: {type: "self_hosted"} → env_... +2. Generate environment key (Console, on the environment page) → sk-ant-oat01-... as ANTHROPIC_ENVIRONMENT_KEY +3. Run a worker: EnvironmentWorker.run() or ant beta:worker poll +4. Sessions reference environment_id=env_... exactly as for cloud +``` + +## Create the environment + +```python +client = anthropic.Anthropic() + +environment = client.beta.environments.create( + name="self-hosted", config={"type": "self_hosted"} +) +``` + +`{"type": "self_hosted"}` is the entire config — there are no pool, capacity, or networking sub-fields; you control those on your side. + +## Run a worker — SDK (primary path) + +`EnvironmentWorker` wraps the poll → dispatch → tool-execute loop. `.run()` is the always-on loop; `.run_one()` / `.runOne()` handles one work item (for webhook-driven wake). + +**Python — always-on:** + +```python +import asyncio +import os +from anthropic import AsyncAnthropic +from anthropic.lib.environments import EnvironmentWorker + + +async def main() -> None: + environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"] + environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"] + async with AsyncAnthropic(auth_token=environment_key) as client: + await EnvironmentWorker( + client, + environment_id=environment_id, + environment_key=environment_key, + workdir="/workspace", + ).run() + + +asyncio.run(main()) +``` + +**TypeScript — always-on:** + +```typescript +import Anthropic from "@anthropic-ai/sdk"; +import { EnvironmentWorker } from "@anthropic-ai/sdk/helpers/beta/environments"; + +const environmentKey = process.env.ANTHROPIC_ENVIRONMENT_KEY!; +const environmentId = process.env.ANTHROPIC_ENVIRONMENT_ID!; +const client = new Anthropic({ authToken: environmentKey }); +const ctrl = new AbortController(); +process.once("SIGTERM", () => ctrl.abort()); + +await new EnvironmentWorker({ + client, + environmentId, + environmentKey, + workdir: "/workspace", + signal: ctrl.signal +}).run(); +``` + +**Customizing tools.** `EnvironmentWorker` runs the built-in toolset by default. To add or replace tools, use `AgentToolContext(workdir=, client=, session_id=)` with `beta_agent_toolset(env)` / `betaAgentToolset(env)` and pass the resulting tools to the lower-level `tool_runner()`. Skills attached to the agent are downloaded into `{workdir}/skills//` before tool calls begin (`AgentToolContext` handles this when given `client` and `session_id`). Downloaded skill files are marked executable automatically by the CLI and SDK; if you implement skills download yourself, you set permissions. + +> **Runtime deps:** the SDK helpers require `/bin/bash` at that exact path. The TypeScript SDK additionally requires `unzip`, `tar`, and Node.js 22+. These are resolved at fixed paths and do **not** respect `PATH` overrides. + +## Run a worker — `ant` CLI (fixed tools) + +The `ant` CLI ships a worker with the fixed built-in toolset (`bash`, `read`, `write`, `edit`, `glob`, `grep`). Install per `shared/anthropic-cli.md`, then: + +```sh +export ANTHROPIC_ENVIRONMENT_KEY=sk-ant-oat01-... +ant beta:worker poll --environment-id env_... --workdir /workspace +``` + +- `--workdir` is the directory tools operate in (default `.`); tool calls are sandboxed to it. +- `--environment-key` overrides the env var. +- `--on-work