Capture
One read of Claude Developer Platform
5 pages moved out of 584 read.
manage-claude/app-attest Changed · +1 / -1 lines
from line 6
App Attest authenticates iOS and macOS apps that call the Claude API directly from the device, with usage billed to your workspace. This page explains how App Attest works, how to register your app in the Claude Console, and how to revoke an app integration. -Apps use App Attest through the [Claude for Foundation Models](https://github.com/anthropics/ClaudeForFoundationModels) Swift package, which is in beta: it requires the OS 27 betas, and APIs might change before general availability. For the Swift configuration, see [Apple Foundation Models](https://platform.claude.com/docs/en/cli-sdks-libraries/libraries/apple-foundation-models#app-attest-production). +Apps use App Attest through the [Claude for Foundation Models](https://github.com/anthropics/ClaudeForFoundationModels) Swift package, which is in beta: it requires the OS 27 betas, and APIs might change during the beta. For the Swift configuration, see [Apple Foundation Models](https://platform.claude.com/docs/en/cli-sdks-libraries/libraries/apple-foundation-models#app-attest-production). ## How App Attest works
api/beta/sessions/list Changed · +255 / -43 lines
from line 369
- `configs: array of BetaManagedAgentsAgentToolConfig` - - `enabled: boolean` + - `BetaManagedAgentsBashToolConfig object { enabled, name, permission_policy, type }` - - `name: "bash" or "edit" or "read" or 5 more` + Configuration for the bash tool. - Built-in agent tool identifier. + - `enabled: boolean` - - `"bash"` + - `name: "bash"` - - `"edit"` + - `"bash"` - - `"read"` + - `permission_policy: BetaManagedAgentsAlwaysAllowPolicy or BetaManagedAgentsAlwaysAskPolicy` - - `"write"` + Permission policy for tool execution. - - `"glob"` + - `BetaManagedAgentsAlwaysAllowPolicy object { type }` - - `"grep"` + Tool calls are automatically approved without user confirmation. - - `"web_fetch"` + - `type: "always_allow"` - - `"web_search"` + - `"always_allow"` - - `permission_policy: BetaManagedAgentsAlwaysAllowPolicy or BetaManagedAgentsAlwaysAskPolicy` + - `BetaManagedAgentsAlwaysAskPolicy object { type }` - Permission policy for tool execution. + Tool calls require user confirmation before execution. - - `BetaManagedAgentsAlwaysAllowPolicy object { type }` + - `type: "always_ask"` - Tool calls are automatically approved without user confirmation. + - `"always_ask"` - - `type: "always_allow"` + - `type: "bash"` - - `"always_allow"` + - `"bash"` - - `BetaManagedAgentsAlwaysAskPolicy object { type }` + - `BetaManagedAgentsEditToolConfig object { enabled, name, permission_policy, type }` - Tool calls require user confirmation before execution. + Configuration for the edit tool. - - `type: "always_ask"` + - `enabled: boolean` - - `"always_ask"` + - `name: "edit"` + - `"edit"` + + - `permission_policy: BetaManagedAgentsAlwaysAllowPolicy or BetaManagedAgentsAlwaysAskPolicy` + + Permission policy for tool execution. + + - `BetaManagedAgentsAlwaysAllowPolicy object { type }` + + Tool calls are automatically approved without user confirmation. + + - `BetaManagedAgentsAlwaysAskPolicy object { type }` + + Tool calls require user confirmation before execution. + + - `type: "edit"` + + - `"edit"` + + - `BetaManagedAgentsReadToolConfig object { enabled, name, permission_policy, type }` + + Configuration for the read tool. + + - `enabled: boolean` + + - `name: "read"` + + - `"read"` + + - `permission_policy: BetaManagedAgentsAlwaysAllowPolicy or BetaManagedAgentsAlwaysAskPolicy` + + Permission policy for tool execution. + + - `BetaManagedAgentsAlwaysAllowPolicy object { type }` + + Tool calls are automatically approved without user confirmation. + + - `BetaManagedAgentsAlwaysAskPolicy object { type }` + + Tool calls require user confirmation before execution. + + - `type: "read"` + + - `"read"` + + - `BetaManagedAgentsWriteToolConfig object { enabled, name, permission_policy, type }` + + Configuration for the write tool. + + - `enabled: boolean` + + - `name: "write"` + + - `"write"` + + - `permission_policy: BetaManagedAgentsAlwaysAllowPolicy or BetaManagedAgentsAlwaysAskPolicy` + + Permission policy for tool execution. + + - `BetaManagedAgentsAlwaysAllowPolicy object { type }` + + Tool calls are automatically approved without user confirmation. + + - `BetaManagedAgentsAlwaysAskPolicy object { type }` + + Tool calls require user confirmation before execution. + + - `type: "write"` + + - `"write"` + + - `BetaManagedAgentsGlobToolConfig object { enabled, name, permission_policy, type }` + + Configuration for the glob tool. + + - `enabled: boolean` + + - `name: "glob"` + + - `"glob"` + + - `permission_policy: BetaManagedAgentsAlwaysAllowPolicy or BetaManagedAgentsAlwaysAskPolicy` + + Permission policy for tool execution. + + - `BetaManagedAgentsAlwaysAllowPolicy object { type }` + + Tool calls are automatically approved without user confirmation. + + - `BetaManagedAgentsAlwaysAskPolicy object { type }` + + Tool calls require user confirmation before execution. + + - `type: "glob"` + + - `"glob"` + + - `BetaManagedAgentsGrepToolConfig object { enabled, name, permission_policy, type }` + + Configuration for the grep tool. + + - `enabled: boolean` + + - `name: "grep"` + + - `"grep"` + + - `permission_policy: BetaManagedAgentsAlwaysAllowPolicy or BetaManagedAgentsAlwaysAskPolicy` + + Permission policy for tool execution. + + - `BetaManagedAgentsAlwaysAllowPolicy object { type }` + + Tool calls are automatically approved without user confirmation. + + - `BetaManagedAgentsAlwaysAskPolicy object { type }` + + Tool calls require user confirmation before execution. + + - `type: "grep"` + + - `"grep"` + + - `BetaManagedAgentsWebFetchToolConfig object { enabled, name, permission_policy, 4 more }` + + Configuration for the web_fetch tool. + + - `enabled: boolean` + + - `name: "web_fetch"` + + - `"web_fetch"` + + - `permission_policy: BetaManagedAgentsAlwaysAllowPolicy or BetaManagedAgentsAlwaysAskPolicy` + + Permission policy for tool execution. + + - `BetaManagedAgentsAlwaysAllowPolicy object { type }` + + Tool calls are automatically approved without user confirmation. + + - `BetaManagedAgentsAlwaysAskPolicy object { type }` + + Tool calls require user confirmation before execution. + + - `type: "web_fetch"` + + - `"web_fetch"` + + - `allowed_domains: optional array of string` + + - `blocked_domains: optional array of string` + + - `max_content_tokens: optional number or null` + + - `BetaManagedAgentsWebSearchToolConfig object { enabled, name, permission_policy, 4 more }` + + Configuration for the web_search tool. + + - `enabled: boolean` + + - `name: "web_search"` + + - `"web_search"` + + - `permission_policy: BetaManagedAgentsAlwaysAllowPolicy or BetaManagedAgentsAlwaysAskPolicy` + + Permission policy for tool execution. + + - `BetaManagedAgentsAlwaysAllowPolicy object { type }` + + Tool calls are automatically approved without user confirmation. + + - `BetaManagedAgentsAlwaysAskPolicy object { type }` + + Tool calls require user confirmation before execution. + + - `type: "web_search"` + + - `"web_search"` + + - `allowed_domains: optional array of string` + + - `blocked_domains: optional array of string` + + - `user_location: optional BetaManagedAgentsUserLocation or null` + + Approximate user location for search result localization. + + - `type: "approximate"` + + Location precision. Only "approximate" is supported. + + - `"approximate"` + + - `city: optional string or null` + + City name. + + - `country: optional string or null` + + Two-letter ISO 3166-1 country code, uppercase. + + - `region: optional string or null` + + Region or state name. + + - `timezone: optional string or null` + + IANA timezone identifier, e.g. "America/Los_Angeles". + - `default_config: BetaManagedAgentsAgentToolsetDefaultConfig` Resolved default configuration for agent tools.
from line 1098
"name": "bash", "permission_policy": { "type": "always_allow" - } + }, + "type": "bash" } ], "default_config": {
from line 1139
"name": "bash", "permission_policy": { "type": "always_allow" - } + }, + "type": "bash" } ], "default_config": {
managed-agents/self-hosted-sandboxes Changed · +26 / -20 lines
from line 241
`ant beta:worker poll` claims work items assigned to the environment, downloads skills, executes tool calls in the working directory, and posts results back. It reads `ANTHROPIC_ENVIRONMENT_KEY` and `ANTHROPIC_ENVIRONMENT_ID` from the environment. ```bash - ant beta:worker poll \ - --workdir "/workspace" + ant beta:worker poll --workdir "/workspace" ``` The worker exits cleanly on SIGTERM or SIGINT: it cancels any in-flight tool call, posts its error result, and releases the work item before stopping.
from line 280
Start the poller pointing at the script: ```bash - ant beta:worker poll \ - --on-work ./spawn.sh + ant beta:worker poll --on-work ./spawn.sh ``` </Step> </Steps>
from line 425
```python Python import asyncio import os - import signal import anthropic import standardwebhooks # installed by the anthropic[webhooks] extra
from line 433
client = anthropic.AsyncAnthropic( auth_token=environment_key, ) - # Cancelled on SIGINT or SIGTERM (wired in handle) so an in-flight work item can upload - # changed memory files and remove its store directories before the process exits. + # Cancelled by shutdown() so an in-flight work item can upload changed memory files and + # remove its store directories before the process exits. inflight: set[asyncio.Task[None]] = set() - def cancel_inflight() -> None: + # Await this from the host's shutdown hook, such as an ASGI lifespan shutdown (the code after + # `yield` in a FastAPI lifespan), which uvicorn runs on SIGTERM. uvicorn lets open requests + # finish before that hook runs, so set --timeout-graceful-shutdown to bound the wait. + async def shutdown() -> None: for task in inflight: task.cancel() + await asyncio.gather(*inflight, return_exceptions=True) async def handle(raw: bytes, headers: dict[str, str]) -> tuple[dict[str, str], int]:
from line 454
return {"error": "signature verification failed"}, 401 if event.data.type != "session.status_run_started": return {"status": "ignored"}, 200 - loop = asyncio.get_running_loop() - for signum in (signal.SIGINT, signal.SIGTERM): - loop.add_signal_handler(signum, cancel_inflight) task = asyncio.create_task(run_queued_work()) inflight.add(task) task.add_done_callback(inflight.discard) try: - await task + # Shielded: a dropped or timed-out delivery must not cancel the item; shutdown() does. + await asyncio.shield(task) except asyncio.CancelledError: return {"status": "shutting down"}, 503 return {"status": "ok"}, 200
from line 492
const client = new Anthropic({ authToken: environmentKey }); - // Aborted on SIGINT or SIGTERM so an in-flight work item can upload changed memory - // files and remove its store directories before the process exits. - const shutdown = new AbortController(); - process.once("SIGINT", () => shutdown.abort()); - process.once("SIGTERM", () => shutdown.abort()); + // Call shutdown.abort() from the host's SIGTERM/SIGINT handler, alongside closing the server, + // then wait for in-flight handle() calls before exiting: the abort lets a running work item + // upload changed memory files and remove its store directories first. + export const shutdown = new AbortController(); export async function handle(req: Request): Promise<Response> { + // Never acknowledge a delivery whose work will not run here; a 503 makes the sender retry. + if (shutdown.signal.aborted) { + return Response.json({ status: "shutting down" }, { status: 503 }); + } const body = await req.text(); let event; try {
from line 532
signal: shutdown.signal }); } + // The poller and handleItem return quietly on abort, so a drain cut short lands here. + if (shutdown.signal.aborted) { + return Response.json({ status: "shutting down" }, { status: 503 }); + } return Response.json({ status: "ok" }); } ```
from line 691
* `drain`: whether to stop polling once the queue is empty rather than waiting for new work. * `block_ms`: how long to wait for work to arrive before returning, in milliseconds. Must be between 1 and 999 (per-poll wait; the helper re-polls automatically). Pass `null` (`None` in Python, `param.Null[int64]()` in Go) for a non-blocking check; omitting the parameter uses the default 999 ms long-poll. * `reclaim_older_than_ms`: re-claim work items that were claimed but never acknowledged within this many milliseconds. - * `auto_stop` (`autoStop` in TypeScript, `AutoStop` in Go): whether to post a stop signal for each work item once your loop body finishes with it. Turn it off when the process you launch for the session, rather than the loop body, runs the work item to completion. + * `auto_stop` (`autoStop` in TypeScript, `AutoStop` in Go): whether to post a stop signal for each work item once your loop body finishes with it. Turn it off whenever whatever runs the work item posts the stop itself: `handle_item()` does, so set it to false when you hand claimed items to `handle_item()` as the webhook handlers on this page do, and so does a sandbox you launch that owns the stop call. * **`client.beta.sessions.events.tool_runner()`:** runs tool calls for a single session, given the session ID and a tool list. Use when you've already claimed the work and only need the execution layer.
from line 1156
Do not create the per-store directories yourself. The worker creates each store's `mount_path` directory (for example, `/mnt/memory/user-preferences`) when a session starts, refuses to start the session's work if something already exists at that path, and removes the directory when the session ends. Two operating rules follow: * **Run one session per filesystem when sessions attach the same store.** Two sessions cannot mount the same store on one host at the same time, because both need the same path. Giving each session its own sandbox, as described in [Run one sandbox per session](https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes#run-one-sandbox-per-session), satisfies this rule. -* **Stop workers gracefully.** When you stop a worker while a session runs, `EnvironmentWorker` uploads the session's changed memory files and removes its store directories only if it is cancelled rather than killed: a killed process runs no teardown, and the worker does not install signal handlers itself. Wire SIGTERM and SIGINT to cancellation in the process that runs it: abort the `signal` you pass to the worker in TypeScript, cancel the context in Go, and in Python cancel the task that runs `run()` or `handle_item()` from a signal handler. Then stop workers with SIGTERM and give them at least 30 seconds to exit before any hard kill, because the final upload can take that long. If a worker is killed before its teardown runs, remove the leftover store directory under `/mnt/memory/` before the next session that attaches that store; any edits in it that had not synced are lost. +* **Stop workers gracefully.** When you stop a worker while a session runs, `EnvironmentWorker` uploads the session's changed memory files and removes its store directories only if it is cancelled rather than killed: a killed process runs no teardown, and the worker does not install signal handlers itself. Wire SIGTERM and SIGINT to cancellation in the process that runs it: abort the `signal` you pass to the worker in TypeScript, cancel the context in Go, and in Python cancel the task that runs `run()` or `handle_item()`. Do that from a signal handler when your worker is the process, as the standalone workers on this page do, or from your server's own shutdown hook when the worker runs inside a webhook handler, which must not take over the server's signals. Then stop workers with SIGTERM and give them at least 30 seconds to exit before any hard kill, because the final upload can take that long. If a worker is killed before its teardown runs, remove the leftover store directory under `/mnt/memory/` before the next session that attaches that store; any edits in it that had not synced are lost. ### Run one sandbox per session
from line 1348
### Read-only stores and conflicts -For a store attached with `access: "read_only"`, the `write` and `edit` tools refuse to change files inside its directory, and the worker never uploads anything from it. Changes made through `bash` are not blocked locally: they are never synced to the store, and the next remote change to that memory overwrites them. If you need the local copy itself to stay unchanged during the session, disable the `bash` tool for that agent; do not mount the store path read-only, because the worker itself must create the directory and write the downloaded memories into it. +For a store attached with `access: "read_only"`, the `write` and `edit` tools refuse to change files inside its directory, and the worker never uploads anything from it. Changes made through `bash`, or through a custom tool or MCP server you serve from the sandbox, are not blocked locally: they are never synced to the store, and the next remote change to that memory overwrites them. If you need the local copy itself to stay unchanged during the session, disable the `bash` tool for that agent and give it no custom tool that writes to the sandbox's filesystem; do not mount the store path read-only, because the worker itself must create the directory and write the downloaded memories into it. Conflicts resolve in favor of the store. When the agent changes a memory file that also changed in the store since the session last synced it, the worker keeps the store's version at the next sync, overwrites the local file with it, and logs a warning; the `write` and `edit` tools themselves succeed and no error reaches the agent. If the agent's change still applies, it can re-read the file after the sync and make the change again.
managed-agents/skills Changed · +6 / -8 lines
from line 32
``` ```bash CLI - ant skills create \ - --file example_skill.zip + ant skills create --file example_skill.zip ``` ```python Python
from line 148
``` ```php PHP - // The PHP SDK exposes the Skills API under the beta namespace; field names can differ from other SDKs. use Anthropic\Client; use Anthropic\Core\FileParam; $client = new Client(); - $skill = $client->beta->skills->create( + $skill = $client->skills->create( files: [ - FileParam::fromResource(fopen('example_skill.zip', 'r')) + FileParam::fromResource(fopen('example_skill.zip', 'r')), ], ); echo "Created skill: {$skill->id}\n"; - echo "Latest version: {$skill->latestVersion}\n"; + echo "Latest version: {$skill->latestVersionID}\n"; ``` ```ruby Ruby
from line 347
model: 'claude-opus-5', system: 'You are a financial analysis agent.', skills: [ - ['type' => 'anthropic', 'skill_id' => 'xlsx'], - ['type' => 'custom', 'skill_id' => 'skill_01AbCdEfGhIjKlMnOpQrStUv', 'version' => 'latest'], + ['type' => 'anthropic', 'skillID' => 'xlsx'], + ['type' => 'custom', 'skillID' => 'skill_01AbCdEfGhIjKlMnOpQrStUv', 'version' => 'latest'], ], ); ```
api/admin/analytics/chat_projects Changed · +1 / -1 lines
from line 138
```http curl https://api.anthropic.com/v1/organizations/analytics/apps/chat/projects \ -H 'anthropic-version: 2023-06-01' \ - -H "Authorization: Bearer $ANTHROPIC_OAUTH_TOKEN" + -H "X-Api-Key: $ANTHROPIC_ADMIN_API_KEY" ``` #### Response