mirror of
https://github.com/anthropics/skills
synced 2026-07-04 19:06:54 +00:00
Update claude-api skill: scheduled deployments, vault env-var credentials, system.message events (#1297)
- Add Managed Agents scheduled deployments: new shared/managed-agents-scheduled-deployments.md (cron schedules, deployment runs, pause/auto-pause), Deployments and Deployment Runs API reference, beta-header coverage, and SKILL.md routing - Vault environment_variable credentials: secrets substituted at egress with networking allowlists; secrets guidance in tools, client-patterns, and onboarding docs rewritten around them; self-hosted sandbox caveats noted - Add system.message event for mid-session system prompt updates (Opus 4.8 only) to the events guide and API reference
This commit is contained in:
@@ -249,7 +249,7 @@ For placement patterns, architectural guidance, and the silent-invalidator audit
|
||||
|
||||
**Mandatory flow:** Agent (once) → Session (every run). `model`/`system`/`tools` live on the agent, never the session. See `shared/managed-agents-overview.md` for the full reading guide, beta headers, and pitfalls.
|
||||
|
||||
**Beta headers:** `managed-agents-2026-04-01` — the SDK sets this automatically for all `client.beta.{agents,environments,sessions,vaults,memory_stores}.*` calls. Skills API uses `skills-2025-10-02` and Files API uses `files-api-2025-04-14`, but you don't need to explicitly pass those in for endpoints other than `/v1/skills` and `/v1/files`.
|
||||
**Beta headers:** `managed-agents-2026-04-01` — the SDK sets this automatically for all `client.beta.{agents,environments,sessions,vaults,memory_stores,deployments,deployment_runs}.*` calls. Skills API uses `skills-2025-10-02` and Files API uses `files-api-2025-04-14`, but you don't need to explicitly pass those in for endpoints other than `/v1/skills` and `/v1/files`.
|
||||
|
||||
**Subcommands** — invoke directly with `/claude-api <subcommand>`:
|
||||
|
||||
@@ -257,12 +257,14 @@ For placement patterns, architectural guidance, and the silent-invalidator audit
|
||||
|---|---|
|
||||
| `managed-agents-onboard` | Walk the user through setting up a Managed Agent from scratch. **Read `shared/managed-agents-onboarding.md` immediately** and follow its interview script: mental model → know-or-explore branch → template config → session setup → **pre-flight viability check** → emit code. The viability check (reconcile the stated job against configured tools/credentials/data) catches under-resourced setups — missing a tool, credential, or data access — before the agent burns budget. Do not summarize — run the interview. |
|
||||
|
||||
**Reading guide:** Start with `shared/managed-agents-overview.md`, then the topical `shared/managed-agents-*.md` files (core, environments, tools, events, outcomes, multiagent, webhooks, memory, client-patterns, onboarding, api-reference). For Python, TypeScript, Go, Ruby, PHP, and Java, read `{lang}/managed-agents/README.md` for code examples. For cURL, read `curl/managed-agents.md`. **Agents are persistent — create once, reference by ID.** Store the agent ID returned by `agents.create` and pass it to every subsequent `sessions.create`; do not call `agents.create` in the request path. The Anthropic CLI (`ant`) is one convenient way to create agents and environments from version-controlled YAML — see `shared/anthropic-cli.md`. If a binding you need isn't shown in the language README, WebFetch the relevant entry from `shared/live-sources.md` rather than guess. C# has beta Managed Agents support via `client.Beta.Agents` and related namespaces.
|
||||
**Reading guide:** Start with `shared/managed-agents-overview.md`, then the topical `shared/managed-agents-*.md` files (core, environments, tools, events, outcomes, multiagent, webhooks, memory, scheduled-deployments, client-patterns, onboarding, api-reference). For Python, TypeScript, Go, Ruby, PHP, and Java, read `{lang}/managed-agents/README.md` for code examples. For cURL, read `curl/managed-agents.md`. **Agents are persistent — create once, reference by ID.** Store the agent ID returned by `agents.create` and pass it to every subsequent `sessions.create`; do not call `agents.create` in the request path. The Anthropic CLI (`ant`) is one convenient way to create agents and environments from version-controlled YAML — see `shared/anthropic-cli.md`. If a binding you need isn't shown in the language README, WebFetch the relevant entry from `shared/live-sources.md` rather than guess. C# has beta Managed Agents support via `client.Beta.Agents` and related namespaces.
|
||||
|
||||
**When the user wants to set up a Managed Agent from scratch** (e.g. "how do I get started", "walk me through creating one", "set up a new agent"): read `shared/managed-agents-onboarding.md` and run its interview — same flow as the `managed-agents-onboard` subcommand.
|
||||
|
||||
**When the user asks "how do I write the client code for X":** reach for `shared/managed-agents-client-patterns.md` — covers lossless stream reconnect, `processed_at` queued/processed gate, interrupt, `tool_confirmation` round-trip, the correct idle/terminated break gate, post-idle status race, stream-first ordering, file-mount gotchas, keeping credentials host-side via custom tools, etc.
|
||||
|
||||
**When the user wants the agent to run on a schedule** (cron, "every night", "weekly report"): read `shared/managed-agents-scheduled-deployments.md` — deployments fire sessions autonomously on a cron cadence, with run records, retries, and auto-pause.
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ All endpoints require `x-api-key` and `anthropic-version: 2023-06-01` headers. M
|
||||
anthropic-beta: managed-agents-2026-04-01
|
||||
```
|
||||
|
||||
The SDK adds this header automatically for all `client.beta.{agents,environments,sessions,vaults,memory_stores}.*` calls. Skills endpoints use `skills-2025-10-02`; Files endpoints use `files-api-2025-04-14`.
|
||||
The SDK adds this header automatically for all `client.beta.{agents,environments,sessions,vaults,memory_stores,deployments,deployment_runs}.*` calls. Skills endpoints use `skills-2025-10-02`; Files endpoints use `files-api-2025-04-14`.
|
||||
|
||||
---
|
||||
|
||||
@@ -26,6 +26,8 @@ All resources are under the `beta` namespace. Python and TypeScript share identi
|
||||
| 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` |
|
||||
| Session Resources | `sessions.resources.add` / `retrieve` / `update` / `list` / `delete` | `Sessions.Resources.Add` / `Get` / `Update` / `List` / `Delete` |
|
||||
| Deployments | `deployments.create` / `pause` / `unpause` / `archive` / `run` | Not yet documented — WebFetch the SDK repo (`shared/live-sources.md`) |
|
||||
| Deployment Runs | `deployment_runs.list` (TS: `deploymentRuns.list`) | Not yet documented — WebFetch the SDK repo (`shared/live-sources.md`) |
|
||||
| Vaults | `vaults.create` / `retrieve` / `update` / `list` / `delete` / `archive` | `Vaults.New` / `Get` / `Update` / `List` / `Delete` / `Archive` |
|
||||
| Credentials | `vaults.credentials.create` / `retrieve` / `update` / `list` / `delete` / `archive` / `mcp_oauth_validate` | `Vaults.Credentials.New` / `Get` / `Update` / `List` / `Delete` / `Archive` / `McpOauthValidate` |
|
||||
| Memory Stores | `memory_stores.create` / `retrieve` / `update` / `list` / `delete` / `archive` | `MemoryStores.New` / `Get` / `Update` / `List` / `Delete` / `Archive` |
|
||||
@@ -113,9 +115,29 @@ Per-subagent event streams in multiagent sessions. See `shared/managed-agents-mu
|
||||
|
||||
For `type: "self_hosted"`, `config` is the bare `{"type": "self_hosted"}` — `networking` and `packages` do not apply.
|
||||
|
||||
## Deployments
|
||||
|
||||
Scheduled deployments (`depl_` IDs) run an agent on a recurring cron schedule — each firing creates a session. See `shared/managed-agents-scheduled-deployments.md` for the conceptual guide (cron/DST semantics, failure behavior, lifecycle).
|
||||
|
||||
| Method | Path | Operation | Description |
|
||||
| -------- | ------------------------------------------------ | ---------------- | ---------------------------------------- |
|
||||
| `POST` | `/v1/deployments` | CreateDeployment | Create a scheduled deployment |
|
||||
| `POST` | `/v1/deployments/{deployment_id}/pause` | PauseDeployment | Suppress scheduled triggers (reversible; manual runs still allowed) |
|
||||
| `POST` | `/v1/deployments/{deployment_id}/unpause` | UnpauseDeployment | Resume from the next occurrence (no backfill) |
|
||||
| `POST` | `/v1/deployments/{deployment_id}/archive` | ArchiveDeployment | **Terminal** — schedule stops, deployment becomes immutable |
|
||||
| `POST` | `/v1/deployments/{deployment_id}/run` | RunDeployment | Trigger a manual run immediately (`trigger_context.type: "manual"`); works while paused |
|
||||
|
||||
## Deployment Runs
|
||||
|
||||
Each trigger attempt (scheduled or manual) writes a `deployment_run` record (`drun_` IDs) carrying either the created `session_id` or an `error.type` (`environment_archived`, `agent_archived`, `vault_not_found`, `session_rate_limited`, `service_unavailable`).
|
||||
|
||||
| Method | Path | Operation | Description |
|
||||
| -------- | ------------------------------------------------ | ---------------- | ---------------------------------------- |
|
||||
| `GET` | `/v1/deployment_runs?deployment_id=...` | ListDeploymentRuns | List runs for a deployment (paginated; filter failures with `has_error=true`) |
|
||||
|
||||
## Vaults
|
||||
|
||||
Vaults store MCP credentials that Anthropic manages on your behalf — OAuth credentials with auto-refresh, or static bearer tokens. Attach to sessions via `vault_ids`. See `managed-agents-tools.md` §Vaults for the conceptual guide and credential shapes.
|
||||
Vaults store credentials that Anthropic manages on your behalf — MCP credentials (OAuth with auto-refresh, or static bearer tokens) and `environment_variable` credentials substituted into outbound requests at egress. Attach to sessions via `vault_ids`. See `managed-agents-tools.md` §Vaults for the conceptual guide and credential shapes.
|
||||
|
||||
| Method | Path | Operation | Description |
|
||||
| -------- | ------------------------------------------------ | ---------------- | ---------------------------------------- |
|
||||
@@ -258,7 +280,7 @@ Immutable per-mutation snapshots (`memver_...`) — the audit and rollback surfa
|
||||
"checkout": { "type": "branch", "name": "main" }
|
||||
}
|
||||
],
|
||||
"vault_ids": ["vlt_abc123 (optional — MCP credentials with auto-refresh)"],
|
||||
"vault_ids": ["vlt_abc123 (optional — vault credentials: MCP auth + environment variables)"],
|
||||
"metadata": {
|
||||
"key": "value"
|
||||
}
|
||||
@@ -286,6 +308,26 @@ Immutable per-mutation snapshots (`memver_...`) — the audit and rollback surfa
|
||||
}
|
||||
```
|
||||
|
||||
### CreateDeployment Request Body
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Weekly compliance scan",
|
||||
"agent": "agent_abc123 (required — same shapes as CreateSession)",
|
||||
"environment_id": "env_abc123 (required)",
|
||||
"initial_events": [
|
||||
{ "type": "user.message", "content": [{ "type": "text", "text": "Run the weekly compliance scan." }] }
|
||||
],
|
||||
"schedule": {
|
||||
"type": "cron",
|
||||
"expression": "0 20 * * 5",
|
||||
"timezone": "America/New_York"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> Optional session config (`resources`, `vault_ids`, etc.) is supported the same way as on CreateSession. Response includes `status`, `paused_reason`, and `schedule.upcoming_runs_at` (next fire times). See `shared/managed-agents-scheduled-deployments.md`.
|
||||
|
||||
### SendEvents Request Body
|
||||
|
||||
```json
|
||||
@@ -304,6 +346,8 @@ Immutable per-mutation snapshots (`memver_...`) — the audit and rollback surfa
|
||||
}
|
||||
```
|
||||
|
||||
> `system.message` events (update the system prompt between turns) use the same envelope with `type: "system.message"` — Claude Opus 4.8 only; see `shared/managed-agents-events.md` § Updating the system prompt mid-session.
|
||||
|
||||
### Define Outcome Event
|
||||
|
||||
```json
|
||||
|
||||
@@ -183,7 +183,9 @@ Delete the original via `files.delete(uploaded.id)`; the session-scoped copy is
|
||||
|
||||
## 9. Secrets for non-MCP APIs and CLIs — keep them host-side via custom tools
|
||||
|
||||
**Problem:** you want the agent to call a third-party API or run a CLI that needs a secret (API key, token, service-account credential), but there is currently no way to set environment variables inside the session container, and vaults currently hold MCP credentials only — they are not exposed to the container's shell. So `curl`, installed CLIs, or SDK clients running via the `bash` tool have no first-class place to read a secret from.
|
||||
**Problem:** you want the agent to call a third-party API or run a CLI that needs a secret (API key, token, service-account credential), but you can't or don't want to hand the secret to a vault.
|
||||
|
||||
**First check:** for cloud environments, the first-class answer is now a vault `environment_variable` credential — the agent's shell sees an opaque placeholder and the real secret is substituted at egress. See `shared/managed-agents-tools.md` → Vaults. Use this pattern instead when that doesn't fit: **self-hosted sandboxes** (env-var credentials not yet supported there), clients that reject the placeholder via local format validation, secrets that must never leave your infrastructure, or calls that need host-side binaries.
|
||||
|
||||
**Solution:** move the authenticated call to your side. Declare a custom tool on the agent; when the agent emits `agent.custom_tool_use`, your orchestrator (the process reading the SSE stream) executes the call with its own credentials and responds with `user.custom_tool_result`. The container never sees the key.
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ const session = await client.beta.sessions.create(
|
||||
| `environment_id`| string | **Yes** | Environment ID |
|
||||
| `title` | string | No | Human-readable name (appears in logs/dashboards) |
|
||||
| `resources` | array | No | Files, GitHub repos, or memory stores, attached to the container at startup. Memory stores are session-create-only (not addable via `resources.add()`). |
|
||||
| `vault_ids` | array | No | Vault IDs (`vlt_*`) — MCP credentials with auto-refresh. See `shared/managed-agents-tools.md` → Vaults. |
|
||||
| `vault_ids` | array | No | Vault IDs (`vlt_*`) — MCP credentials with auto-refresh + `environment_variable` secrets substituted at egress. See `shared/managed-agents-tools.md` → Vaults. |
|
||||
| `metadata` | object | No | User-provided key-value pairs |
|
||||
|
||||
**Agent configuration fields** (passed to `agents.create()`, not `sessions.create()`):
|
||||
|
||||
@@ -13,6 +13,31 @@ Send events to a session via `POST /v1/sessions/{id}/events`.
|
||||
| `user.tool_confirmation` | Approve/deny a tool call (when `always_ask` policy) |
|
||||
| `user.custom_tool_result` | Provide result for a custom tool call |
|
||||
| `user.define_outcome` | Start a rubric-graded iterate loop — see `shared/managed-agents-outcomes.md` |
|
||||
| `system.message` | Update the agent's system prompt between turns — **Claude Opus 4.8 only**; see § Updating the system prompt mid-session |
|
||||
|
||||
#### Updating the system prompt mid-session (`system.message`)
|
||||
|
||||
Unlike the `system` field on the agent definition (fixed at session creation), a `system.message` event changes the system prompt **as the session progresses** — a different persona, revised constraints, or runtime-fetched context that should shape behavior going forward:
|
||||
|
||||
```python
|
||||
client.beta.sessions.events.send(
|
||||
session.id,
|
||||
events=[
|
||||
{
|
||||
"type": "system.message",
|
||||
"content": [
|
||||
{"type": "text", "text": "The user's current timezone is America/New_York."},
|
||||
],
|
||||
},
|
||||
],
|
||||
)
|
||||
```
|
||||
|
||||
Constraints:
|
||||
|
||||
- **Claude Opus 4.8 only.** If any model configured on the agent does not support mid-conversation system injection, the event is rejected with a `model_does_not_support_mid_conversation_system` validation error.
|
||||
- **Cannot be sent while the session is idle with `stop_reason: requires_action`** (blocked on `user.custom_tool_result` / `user.tool_confirmation`).
|
||||
- `content` accepts 1–1000 text items.
|
||||
|
||||
### Receiving Events
|
||||
|
||||
|
||||
@@ -83,10 +83,10 @@ Emit as `resources: [{type: "file", file_id, mount_path}]`. Max 999 file resourc
|
||||
|
||||
Per-run. Points at the agent + environment, attaches credentials, kicks off.
|
||||
|
||||
**Vault credentials** (if the agent declared MCP servers):
|
||||
**Vault credentials** (if the agent declared MCP servers, or the job needs an API key for a CLI/SDK/direct API call):
|
||||
- [ ] Existing vault, or create one? (`client.beta.vaults.create()` + `vaults.credentials.create()`)
|
||||
|
||||
Credentials are write-only, matched to MCP servers by URL, auto-refreshed. See `shared/managed-agents-tools.md` → Vaults.
|
||||
Credentials are write-only. MCP credentials are matched to MCP servers by URL and auto-refreshed; `environment_variable` credentials are substituted into outbound requests at egress (the sandbox sees only a placeholder). See `shared/managed-agents-tools.md` → Vaults.
|
||||
|
||||
**Kickoff — pick one:**
|
||||
- [ ] **Conversational:** a first `user.message` to the agent.
|
||||
|
||||
@@ -25,11 +25,11 @@ Managed Agents is in beta. The SDK sets required beta headers automatically:
|
||||
|
||||
| Beta Header | What it enables |
|
||||
| ------------------------------ | ---------------------------------------------------- |
|
||||
| `managed-agents-2026-04-01` | Agents, Environments, Sessions, Events, Session Resources, Session Threads, Outcomes, Multiagent, Vaults, Credentials, Memory Stores |
|
||||
| `managed-agents-2026-04-01` | Agents, Environments, Sessions, Events, Session Resources, Session Threads, Outcomes, Multiagent, Vaults, Credentials, Memory Stores, Deployments |
|
||||
| `skills-2025-10-02` | Skills API (for managing custom skill definitions) |
|
||||
| `files-api-2025-04-14` | Files API for file uploads |
|
||||
|
||||
**Which beta header goes where:** The SDK sets `managed-agents-2026-04-01` automatically on `client.beta.{agents,environments,sessions,vaults,memory_stores}.*` calls, and `files-api-2025-04-14` / `skills-2025-10-02` automatically on `client.beta.files.*` / `client.beta.skills.*` calls. You do NOT need to add the Skills or Files beta header when calling Managed Agents endpoints. **Exception — session-scoped file listing:** `client.beta.files.list({scope_id: session.id})` is a Files endpoint that takes a Managed Agents parameter, so it needs **both** headers. Pass `betas: ["managed-agents-2026-04-01"]` explicitly on that call (the SDK adds the Files header; you add the Managed Agents one). See `shared/managed-agents-environments.md` → Session outputs.
|
||||
**Which beta header goes where:** The SDK sets `managed-agents-2026-04-01` automatically on `client.beta.{agents,environments,sessions,vaults,memory_stores,deployments,deployment_runs}.*` calls, and `files-api-2025-04-14` / `skills-2025-10-02` automatically on `client.beta.files.*` / `client.beta.skills.*` calls. You do NOT need to add the Skills or Files beta header when calling Managed Agents endpoints. **Exception — session-scoped file listing:** `client.beta.files.list({scope_id: session.id})` is a Files endpoint that takes a Managed Agents parameter, so it needs **both** headers. Pass `betas: ["managed-agents-2026-04-01"]` explicitly on that call (the SDK adds the Files header; you add the Managed Agents one). See `shared/managed-agents-environments.md` → Session outputs.
|
||||
|
||||
|
||||
## Reading Guide
|
||||
@@ -53,14 +53,15 @@ Managed Agents is in beta. The SDK sets required beta headers automatically:
|
||||
| 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 |
|
||||
| Define agents/environments as version-controlled YAML; drive the API from the shell | `shared/anthropic-cli.md` — `ant beta:agents create < agent.yaml`, `--transform`, `@file` inlining |
|
||||
| Store MCP credentials | `shared/managed-agents-tools.md` (Vaults section) |
|
||||
| Call a non-MCP API / CLI that needs a secret | `shared/managed-agents-client-patterns.md` Pattern 9 — no container env vars; vaults are MCP-only; keep the secret host-side via a custom tool |
|
||||
| Store credentials (MCP auth, API keys for CLIs/SDKs) | `shared/managed-agents-tools.md` (Vaults section) — `mcp_oauth` / `static_bearer` / `environment_variable` |
|
||||
| Call a non-MCP API / CLI that needs a secret | `shared/managed-agents-tools.md` (Vaults section) — `environment_variable` credential, substituted at egress. If that doesn't fit (e.g. self-hosted sandboxes), `shared/managed-agents-client-patterns.md` Pattern 9 keeps the secret host-side via a custom tool |
|
||||
| Run an agent on a recurring cron schedule | `shared/managed-agents-scheduled-deployments.md` — deployments, deployment runs, pause/auto-pause |
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
- **Agent FIRST, then session — NO EXCEPTIONS** — the session's `agent` field accepts **only** a string ID or `{type: "agent", id, version}`. `model`, `system`, `tools`, `mcp_servers`, `skills` are **top-level fields on `POST /v1/agents`**, never on `sessions.create()`. If the user hasn't created an agent, that is step zero of every example.
|
||||
- **Agent ONCE, not every run** — `agents.create()` is a setup step. Store the returned `agent_id` and reuse it; don't call `agents.create()` at the top of your hot path. If the agent's config needs to change, `POST /v1/agents/{id}` — each update creates a new version, and sessions can pin to a specific version for reproducibility.
|
||||
- **MCP auth goes through vaults** — the agent's `mcp_servers` array declares `{type, name, url}` only (no auth). Credentials live in vaults (`client.beta.vaults.credentials.create`) and attach to sessions via `vault_ids`. Anthropic auto-refreshes OAuth tokens using the stored refresh token.
|
||||
- **MCP auth goes through vaults** — the agent's `mcp_servers` array declares `{type, name, url}` only (no auth). Credentials live in vaults (`client.beta.vaults.credentials.create`) and attach to sessions via `vault_ids`. Anthropic auto-refreshes OAuth tokens using the stored refresh token. Vaults also hold `environment_variable` credentials for non-MCP services (CLIs, SDKs, direct API calls) — substituted at egress, never visible in the sandbox.
|
||||
- **Reconcile resources before the first run** — a session with a clear ask but a missing tool, credential, data mount, or context will discover the gap mid-run, then flail and give up. Before creating the session, check that every action in the task maps to a configured tool/MCP server, every MCP server has a vault credential, and every referenced file/host is mounted/reachable. When helping a user set one up, run the reconciliation in `shared/managed-agents-onboarding.md` → §3 Pre-flight viability check.
|
||||
- **Stream to get events** — `GET /v1/sessions/{id}/events/stream` is the primary way to receive agent output in real-time.
|
||||
- **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.
|
||||
|
||||
144
skills/claude-api/shared/managed-agents-scheduled-deployments.md
Normal file
144
skills/claude-api/shared/managed-agents-scheduled-deployments.md
Normal file
@@ -0,0 +1,144 @@
|
||||
# Managed Agents — Scheduled Deployments
|
||||
|
||||
A **scheduled deployment** runs an agent on a recurring cron schedule — each firing creates a session autonomously. Use it for predictable-cadence work: nightly triage, weekly compliance scans, hourly monitors.
|
||||
|
||||
Requires the `managed-agents-2026-04-01` beta header (the SDK sets it automatically for `client.beta.deployments.*` / `client.beta.deployment_runs.*` calls).
|
||||
|
||||
## Create a deployment
|
||||
|
||||
A deployment bundles everything a session needs (agent, environment, optional files / GitHub / memory stores / vaults) plus a `schedule` and the `initial_events` that kick off each run:
|
||||
|
||||
- `agent` and `environment_id` are required — same shapes as `sessions.create` (see `shared/managed-agents-core.md`).
|
||||
- `initial_events` must contain the starting `user.message`.
|
||||
- `schedule` takes a cron `expression` and an IANA `timezone`. Minute-level granularity is the maximum.
|
||||
|
||||
```bash
|
||||
curl -fsSL https://api.anthropic.com/v1/deployments \
|
||||
-H "x-api-key: $ANTHROPIC_API_KEY" \
|
||||
-H "anthropic-version: 2023-06-01" \
|
||||
-H "anthropic-beta: managed-agents-2026-04-01" \
|
||||
-H "content-type: application/json" \
|
||||
-d @- <<EOF
|
||||
{
|
||||
"name": "Weekly compliance scan",
|
||||
"agent": "$AGENT_ID",
|
||||
"environment_id": "$ENVIRONMENT_ID",
|
||||
"initial_events": [
|
||||
{"type": "user.message", "content": [{"type": "text", "text": "Run the weekly compliance scan."}]}
|
||||
],
|
||||
"schedule": {
|
||||
"type": "cron",
|
||||
"expression": "0 20 * * 5",
|
||||
"timezone": "America/New_York"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
```python
|
||||
deployment = client.beta.deployments.create(
|
||||
name="Weekly compliance scan",
|
||||
agent=agent.id,
|
||||
environment_id=environment.id,
|
||||
initial_events=[
|
||||
{
|
||||
"type": "user.message",
|
||||
"content": [{"type": "text", "text": "Run the weekly compliance scan."}],
|
||||
},
|
||||
],
|
||||
schedule={
|
||||
"type": "cron",
|
||||
"expression": "0 20 * * 5",
|
||||
"timezone": "America/New_York",
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
The response is a deployment object (`depl_` ID prefix). Check `schedule.upcoming_runs_at` — the next fire times — to confirm the schedule parses the way you intended:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "depl_01xyz",
|
||||
"status": "active",
|
||||
"paused_reason": null,
|
||||
"schedule": {
|
||||
"type": "cron",
|
||||
"expression": "0 20 * * 5",
|
||||
"timezone": "America/New_York",
|
||||
"last_run_at": null,
|
||||
"upcoming_runs_at": ["2026-05-09T00:00:00Z", "2026-05-16T00:00:00Z", "2026-05-23T00:00:00Z"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Deployments may apply up to **10 seconds of jitter** to distribute load. Maximum **1000 scheduled deployments per organization** (contact Anthropic support for more).
|
||||
|
||||
### Cron and timezone semantics
|
||||
|
||||
- **Expression:** standard POSIX cron (`minute hour day-of-month month day-of-week`).
|
||||
- **Timezone:** IANA identifier (e.g. `"America/Los_Angeles"`).
|
||||
- **DST:** literal wall-clock matching — `"0 20 * * *"` in `America/New_York` fires at 8:00 PM local regardless of EST/EDT.
|
||||
|
||||
> ⚠️ **DST edge:** wall-clock times that don't exist on a spring-forward day (e.g. 2AM) are **skipped**; times that occur twice on a fall-back day **fire twice**. Schedule outside the 1–3AM local window, or use UTC, when missed or duplicate executions are unacceptable.
|
||||
|
||||
## Deployment runs
|
||||
|
||||
Every trigger attempt — successful or not — writes a **deployment run** record (`drun_` prefix), so you can audit failures independent of the session lifecycle. A successful run carries the created `session_id`; follow that session via the event stream (`shared/managed-agents-events.md`) or webhooks (`shared/managed-agents-webhooks.md`) as usual. A failed run carries an `error` whose `type` explains why session creation was rejected.
|
||||
|
||||
```python
|
||||
# All runs for a deployment
|
||||
for run in client.beta.deployment_runs.list(deployment_id=deployment.id):
|
||||
print(run.created_at, run.session_id or run.error.type)
|
||||
|
||||
# Failures only
|
||||
for run in client.beta.deployment_runs.list(deployment_id=deployment.id, has_error=True):
|
||||
print(run.created_at, run.error.type, run.error.message)
|
||||
```
|
||||
|
||||
```typescript
|
||||
for await (const run of client.beta.deploymentRuns.list({
|
||||
deployment_id: deployment.id,
|
||||
has_error: true,
|
||||
})) {
|
||||
console.log(run.created_at, run.error?.type, run.error?.message);
|
||||
}
|
||||
```
|
||||
|
||||
Raw HTTP: `GET /v1/deployment_runs?deployment_id=...&has_error=true`.
|
||||
|
||||
A failed run looks like:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "deployment_run",
|
||||
"id": "drun_01abc124",
|
||||
"deployment_id": "depl_01xyz",
|
||||
"trigger_context": { "type": "schedule", "scheduled_at": "2026-05-09T00:00:00Z" },
|
||||
"session_id": null,
|
||||
"error": { "type": "environment_archived", "message": "environment `env_01abc` is archived" },
|
||||
"agent": { "type": "agent", "id": "agent_01ghi789", "version": 3 },
|
||||
"created_at": "2026-05-09T00:00:01Z"
|
||||
}
|
||||
```
|
||||
|
||||
Error types include `environment_archived`, `agent_archived`, `vault_not_found`, `session_rate_limited`, and `service_unavailable`.
|
||||
|
||||
## Lifecycle: pause / unpause / archive
|
||||
|
||||
| Operation | SDK | Effect |
|
||||
|---|---|---|
|
||||
| Pause | `client.beta.deployments.pause(id)` | Suppresses scheduled triggers go-forward. Sessions already running continue. **Manual runs are still permitted while paused.** Sets `paused_reason: {"type": "manual"}`. |
|
||||
| Unpause | `client.beta.deployments.unpause(id)` | Resumes from the next scheduled occurrence. **Missed triggers are not backfilled.** Clears `paused_reason`. |
|
||||
| Archive | `client.beta.deployments.archive(id)` | **Terminal** — the schedule stops and the deployment can no longer be modified. Use pause for anything reversible. |
|
||||
|
||||
Raw HTTP: `POST /v1/deployments/{deployment_id}/pause` (likewise `/unpause`, `/archive`).
|
||||
|
||||
### Failure behavior
|
||||
|
||||
- **Rate-limited:** recorded immediately as a `session_rate_limited` run, **no retry** — the schedule simply tries again at the next occurrence. (Rate limits on API calls *inside* a session are handled by the session itself.)
|
||||
- **Other failed runs** (e.g. `environment_archived`, `vault_not_found`, `service_unavailable`): the run records the `error.type` — monitor runs and fix the referenced resource, or pause the deployment.
|
||||
- **Agent archived or deleted:** the deployment is automatically **archived** (terminal) and no further sessions are created.
|
||||
|
||||
## Manual runs
|
||||
|
||||
`POST /v1/deployments/{deployment_id}/run` (SDK: `client.beta.deployments.run(id)`) creates a session immediately and writes a run with `trigger_context.type: "manual"`. Use it to **test a deployment before committing to the schedule** — and remember it works even while the deployment is paused.
|
||||
@@ -156,6 +156,7 @@ These are **control-plane** calls — authenticate with `x-api-key` (not the env
|
||||
| Container lifecycle, hardening, networking | Anthropic | **You** — run non-root, read-only rootfs, drop caps; egress is whatever your VPC/firewall allows |
|
||||
| `file` / `github_repository` resource mounting | Anthropic mounts into the container | **You** — pass pointers via `sessions.create(metadata={...})` and have your orchestrator fetch/clone before dispatch |
|
||||
| `memory_store` resources | Supported | **Not yet supported** |
|
||||
| Vault `environment_variable` credentials | Supported (substituted at Anthropic-managed egress) | **Not yet supported** — egress is yours, so there's nowhere to substitute the secret. Use MCP credentials or a host-side custom tool (`shared/managed-agents-client-patterns.md` Pattern 9) |
|
||||
| Built-in tools | Via `agent_toolset_20260401` | Supplied by your worker (`EnvironmentWorker` default / `beta_agent_toolset(env)` / `ant` CLI fixed set) |
|
||||
| Skills download | Automatic | `EnvironmentWorker` / `AgentToolContext` fetch into `{workdir}/skills/` (needs `client` + `session_id`) |
|
||||
| Claude Platform on AWS | Supported | **Not available** |
|
||||
|
||||
@@ -190,9 +190,14 @@ This keeps secrets out of reusable agent definitions. Each vault credential is t
|
||||
|
||||
> ⚠️ **MCP auth tokens ≠ REST API tokens.** Hosted MCP servers (`mcp.notion.com`, `mcp.linear.app`, etc.) typically require **OAuth bearer tokens**, not the service's native API keys. A Notion `ntn_` integration token authenticates against Notion's REST API but will **not** work as a vault credential for the Notion MCP server. These are different auth systems.
|
||||
|
||||
### Vaults — the MCP credential store
|
||||
### Vaults — the credential store
|
||||
|
||||
**Vaults** store OAuth credentials (access token + refresh token) that Anthropic auto-refreshes on your behalf via standard OAuth 2.0 `refresh_token` grant. This is the only way to authenticate MCP servers in the launch SDK.
|
||||
**Vaults** store credentials that Anthropic manages on your behalf. Two credential categories:
|
||||
|
||||
- **MCP credentials** (`mcp_oauth`, `static_bearer`) — keyed by `mcp_server_url`. When the agent connects to a server at that URL, the token is injected automatically. `mcp_oauth` tokens are auto-refreshed via the standard OAuth 2.0 `refresh_token` grant. This is the only way to authenticate MCP servers.
|
||||
- **Environment variables** (`environment_variable`) — keyed by `secret_name` (the env var name). The sandbox sees only an **opaque placeholder**; the real secret is substituted into the outbound request **at egress**. Use this for any service that authenticates through an environment variable: CLIs (`aws`, `gcloud`, `stripe`), SDKs, or direct `curl` calls from the `bash` tool.
|
||||
|
||||
Secret fields you supply (`token`, `access_token`, `refresh_token`, `client_secret`, `secret_value`) are write-only — never returned in API responses.
|
||||
|
||||
#### Credentials and the sandbox
|
||||
|
||||
@@ -200,11 +205,9 @@ Vaults store credentials; those credentials **never enter the sandbox**. This is
|
||||
|
||||
- **MCP tool calls** are routed through an Anthropic-side proxy that fetches the credential from the vault and adds it to the outbound request.
|
||||
- **Git operations on attached GitHub repositories** (`git pull`, `git push`, GitHub REST calls) are routed through a git proxy that injects the `github_repository` resource's `authorization_token` the same way.
|
||||
- **Environment-variable credentials** appear in the sandbox as an opaque placeholder; the real value replaces the placeholder at egress, on requests to the credential's allowed hosts only.
|
||||
|
||||
**Not yet supported:** running other authenticated CLIs (e.g. `aws`, `gcloud`, `stripe`) directly inside the sandbox. There is currently no way to set container environment variables or expose vault credentials to arbitrary processes. If you need one of these today:
|
||||
|
||||
- **Prefer an MCP server** for that service if one exists — it gets the same vault-backed injection.
|
||||
- **Otherwise, register a custom tool:** the agent emits `agent.custom_tool_use`, your orchestrator (which already holds the credential) executes the call and returns `user.custom_tool_result` over the same authenticated event stream. No public endpoint is exposed; the sandbox never sees the secret. See `shared/managed-agents-client-patterns.md` → Pattern 9.
|
||||
**When vault credentials don't fit** (e.g. self-hosted sandboxes — `environment_variable` is not yet supported there), **register a custom tool:** the agent emits `agent.custom_tool_use`, your orchestrator (which already holds the credential) executes the call and returns `user.custom_tool_result` over the same authenticated event stream. No public endpoint is exposed; the sandbox never sees the secret. See `shared/managed-agents-client-patterns.md` → Pattern 9.
|
||||
|
||||
**Do not put API keys in the system prompt or user messages as a workaround** — they persist in the session's event history.
|
||||
|
||||
@@ -213,11 +216,11 @@ Vaults store credentials; those credentials **never enter the sandbox**. This is
|
||||
**Flow:**
|
||||
|
||||
1. Create a vault (`client.beta.vaults.create(...)`) — one per tenant/user, or one shared, depending on your model
|
||||
2. Add MCP credentials to it (`client.beta.vaults.credentials.create(...)`) — each credential is tied to one MCP server URL
|
||||
2. Add credentials to it (`client.beta.vaults.credentials.create(...)`) — MCP credentials are keyed by MCP server URL; environment-variable credentials by `secret_name`
|
||||
3. Reference the vault on session create via `vault_ids: ["vlt_..."]`
|
||||
4. Anthropic auto-refreshes tokens before they expire; the agent uses the current access token when calling MCP tools
|
||||
4. Anthropic auto-refreshes OAuth tokens before they expire and substitutes secrets at runtime
|
||||
|
||||
**Credential shape**:
|
||||
**MCP OAuth credential shape**:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -249,6 +252,40 @@ Omit `refresh` entirely if you only have an access token with no refresh capabil
|
||||
|
||||
> 💡 **Getting an OAuth token.** How you obtain the initial access and refresh tokens depends on the MCP server — consult its documentation. Once you have them, store them in a vault credential using the shape above; Anthropic auto-refreshes via the `refresh.token_endpoint` from there.
|
||||
|
||||
**Environment-variable credential shape**:
|
||||
|
||||
```json
|
||||
{
|
||||
"display_name": "Twilio API key for sandbox",
|
||||
"auth": {
|
||||
"type": "environment_variable",
|
||||
"secret_name": "TWILIO_API_KEY",
|
||||
"secret_value": "sk-your-secret-here",
|
||||
"networking": {
|
||||
"type": "limited",
|
||||
"allowed_hosts": ["api.twilio.com", "*.twilio.com"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`networking.allowed_hosts` controls which outbound hosts the secret can be substituted for — `{"type": "limited", "allowed_hosts": [...]}` or `{"type": "unrestricted"}` if you can't enumerate the domains in advance. Limiting is strongly recommended: it prevents the key from ever being sent to unauthorized hosts.
|
||||
|
||||
> ⚠️ **Two networking layers, both required.** `networking.allowed_hosts` on the credential controls which requests *use the secret*, not which requests are *allowed*. The agent must also be able to reach the domain at the **environment level** (`unrestricted`, or the host listed in the environment's `allowed_hosts` — see `shared/managed-agents-environments.md`). A domain missing from either layer means the secret-substituted request fails.
|
||||
|
||||
> ⚠️ **Client-side validation caveat.** Substitution happens at egress, not inside the sandbox — clients that validate the credential *format* locally before making a network request (e.g. a CLI that checks the key starts with `sk-`) will see the opaque placeholder and may fail at startup. If a client rejects the credential before any network call, that's why.
|
||||
|
||||
> 💡 **Scope the key minimally.** The agent can do anything the key allows; a key with broader permissions than the task needs increases the blast radius if the agent behaves unexpectedly.
|
||||
|
||||
**Not supported with self-hosted sandboxes** — `environment_variable` credentials require Anthropic-managed egress. See `shared/managed-agents-self-hosted-sandboxes.md`.
|
||||
|
||||
**Constraints (all credential types):**
|
||||
|
||||
- **Unique key per vault.** `mcp_server_url` (MCP credentials) and `secret_name` (environment-variable credentials) must be unique among active credentials in a vault; duplicates return a 409.
|
||||
- **Keys are immutable.** Secret values and `display_name` can be updated (rotation); to change `mcp_server_url`, `secret_name`, `token_endpoint`, or `client_id`, archive the credential and create a new one. Archiving purges the secret and frees the key for a replacement.
|
||||
- **Maximum 20 credentials per vault.**
|
||||
- Credentials are stored as provided and **not validated until session runtime** — an invalid credential surfaces as an authentication or downstream error during the session, which is emitted but does not block the session from continuing.
|
||||
|
||||
**Scoping:** Vaults are workspace-scoped. Anyone with developer+ role in the API workspace can create, read (metadata only — secrets are write-only), and attach vaults. `vault_ids` can be set at session **create** time but not via session update (the SDK docstring says "Not yet supported; requests setting this field are rejected").
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user