---
title: セルフホストワーカーをデプロイする
url: https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes-workers
description: セルフホスト型サンドボックスワーカーがワークを取得する方法とセッションの実行場所を選択します。常時稼働またはWebhookトリガー型、単一プロセスまたはセッションごとに1つのサンドボックスから選べます。
featureMetadata:
  topic:
    title: Managed Agents
    url: https://platform.claude.com/docs/en/managed-agents/overview
  status: beta
  betaHeader: managed-agents-2026-04-01
---

[クイックスタート](https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes#quickstart)では、継続的にポーリングし、すべてのセッションを1つのプロセスで実行する `ant` CLIワーカーを1つ実行します。このページでは、ワーカーを実行するその他の方法と、それらの選び方について説明します。

## デプロイパターンを選択する

ワーカーをデプロイする際には、ワーカーがワークを取得する方法と、各セッションを実行する場所の2つを選択する必要があります。

**ワーカーがワークを取得する方法：**

* **常時稼働：** 長時間実行されるプロセスがキューを継続的にポーリングし、必要なのはアウトバウンドHTTPSのみです。これが最もシンプルな構成です。
* **Webhookトリガー型：** ハンドラーが `session.status_run_started` で起動し、ポーリングを開始します。これによりアイドル状態のポーラーを回避できますが、Anthropicから到達可能な[Webhook](https://platform.claude.com/docs/ja/managed-agents/webhooks)エンドポイントが必要です。

**各セッションを実行する場所：**

* **プロセス内：** セッションを取得したワーカーが、そのツール呼び出しも1つの共有作業ディレクトリで実行します。
* **セッションごとのサンドボックス：** ポーラーが、取得したセッションごとに新しいサンドボックスを起動します。新しいファイルシステム、リソース制限、セッションごとのネットワーク制御など、より強力な分離が必要な場合はこちらを選択してください。

CLIワーカーとSDKワーカーは、それぞれ異なる組み合わせをサポートしています：

| 機能                                                                                               | `ant` CLI      | SDK（Python、TypeScript、Go） |
| ------------------------------------------------------------------------------------------------ | -------------- | ------------------------- |
| 常時稼働のポーリング                                                                                       | はい             | はい                        |
| Webhookトリガー型                                                                                     | いいえ            | はい                        |
| セッションごとのサンドボックス                                                                                  | はい             | はい                        |
| [メモリストア](https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes-memory)        | はい（デフォルトの同期設定） | はい（同期を設定可能）               |
| [カスタムツール](https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes-custom-tools) | いいえ            | はい                        |

すべてのCLIフラグとSDKオプションについては、[セルフホストワーカーリファレンス](https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes-reference)を参照してください。より細かく制御したい場合は、[Environments Workエンドポイント](https://platform.claude.com/docs/ja/api/beta/environments/work)を直接呼び出して独自のワーカーを実装してください。

## 常時稼働ワーカーを実行する

キューを継続的にポーリングするワーカーを起動します。ワーカーはクイックスタートで取得した[環境キー](https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes#run-your-first-session)で認証します：

<CodeGroup exclude="shell:cURL, csharp, java, php, ruby">
  ```bash CLI
  ant beta:worker poll --workdir /workspace
  ```

  ```python Python
  import asyncio
  import contextlib
  import os
  import signal
  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:
          worker = EnvironmentWorker(
              client,
              environment_id=environment_id,
              environment_key=environment_key,
              workdir="/workspace",
          )
          task = asyncio.create_task(worker.run())
          # プロセスを強制終了するのではなくタスクをキャンセルすることで、ワーカーは処理中の
          # 作業項目を停止し、変更されたメモリファイルを終了前にアップロードできます。
          loop = asyncio.get_running_loop()
          for signum in (signal.SIGINT, signal.SIGTERM):
              loop.add_signal_handler(signum, task.cancel)
          with contextlib.suppress(asyncio.CancelledError):
              await task


  asyncio.run(main())
  ```

  ```typescript 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 controller = new AbortController();
  // いずれかのシグナルで中断することで、プロセス終了前にワーカーが変更されたメモリファイルをアップロードし、
  // ストアディレクトリを削除できます。
  process.once("SIGINT", () => controller.abort());
  process.once("SIGTERM", () => controller.abort());

  await new EnvironmentWorker({
    client,
    environmentId,
    environmentKey,
    workdir: "/workspace",
    signal: controller.signal
  }).run();
  ```

  <CodeGroupItem language="C#">
    C# SDKには `EnvironmentWorker` がありません。代わりに `ant` CLIワーカーを実行してください：`ant beta:worker poll --workdir /workspace`。
  </CodeGroupItem>

  ```go Go
  package main

  import (
  	"context"
  	"log"
  	"os"
  	"os/signal"
  	"syscall"

  	"github.com/anthropics/anthropic-sdk-go"
  	"github.com/anthropics/anthropic-sdk-go/lib/environments"
  	"github.com/anthropics/anthropic-sdk-go/option"
  )

  func main() {
  	environmentKey := os.Getenv("ANTHROPIC_ENVIRONMENT_KEY")
  	environmentID := os.Getenv("ANTHROPIC_ENVIRONMENT_ID")

  	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
  	defer stop()

  	client := anthropic.NewClient(option.WithAuthToken(environmentKey))

  	worker := environments.NewEnvironmentWorker(client, environments.EnvironmentWorkerOptions{
  		EnvironmentID:  environmentID,
  		EnvironmentKey: environmentKey,
  		Workdir:        "/workspace",
  	})
  	if err := worker.Run(ctx); err != nil {
  		log.Fatalf("worker: %v", err)
  	}
  }
  ```

  <CodeGroupItem language="Java">
    Java SDKには `EnvironmentWorker` がありません。代わりに `ant` CLIワーカーを実行してください：`ant beta:worker poll --workdir /workspace`。
  </CodeGroupItem>

  <CodeGroupItem language="PHP">
    PHP SDKには `EnvironmentWorker` がありません。代わりに `ant` CLIワーカーを実行してください：`ant beta:worker poll --workdir /workspace`。
  </CodeGroupItem>

  <CodeGroupItem language="Ruby">
    Ruby SDKには `EnvironmentWorker` がありません。代わりに `ant` CLIワーカーを実行してください：`ant beta:worker poll --workdir /workspace`。
  </CodeGroupItem>
</CodeGroup>

## Webhookからワーカーをトリガーする

<Steps>
  <Step title="セッションWebhookをサブスクライブする">
    [Console](https://platform.claude.com/settings/workspaces/default/webhooks)で、`session.status_run_started` イベントをリッスンするWebhookエンドポイントを定義します。詳細については[Webhook](https://platform.claude.com/docs/ja/managed-agents/webhooks)を参照してください。
  </Step>

  <Step title="Webhook署名キーをエクスポートする">
    [クイックスタート](https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes#run-your-first-session)で取得した環境IDとキーに加えて、ハンドラーのホストでWebhook署名キーをエクスポートします。ハンドラーはこれを使用して受信ペイロードを検証します。

    ```bash
    export ANTHROPIC_WEBHOOK_SIGNING_KEY="whsec_..."
    ```
  </Step>

  <Step title="Webhookハンドラーを実装する">
    `session.status_run_started` が発火したときにワーカーを呼び出します。ハンドラーはキューを処理し尽くし、取得した各ワークアイテムを `handle_item()` (typescript: `handleItem()`; go: `HandleItem()`) に渡します。これはスキルをダウンロードし、ツール呼び出しを実行し、結果を送り返してから戻ります。

    <CodeGroup exclude="shell, csharp, java, php, ruby">
      <CodeGroupItem>
        Webhook署名を検証するには、webhooksエクストラをインストールしてください：`pip install "anthropic[webhooks]"`。

        ```python Python
        import asyncio
        import os
        import anthropic
        import standardwebhooks  # installed by the anthropic[webhooks] extra

        environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"]
        environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"]
        client = anthropic.AsyncAnthropic(
            auth_token=environment_key,
        )
        # shutdown() によってキャンセルされ、実行中の作業項目が変更されたメモリファイルをアップロードし、
        # プロセス終了前にストアディレクトリを削除できるようにします。
        inflight: set[asyncio.Task[None]] = set()


        # ホストのシャットダウンフックから await してください。例: ASGI lifespan のシャットダウン（FastAPI lifespan の
        # `yield` 以降のコード）。uvicorn は SIGTERM 時にこれを実行します。uvicorn は未完了のリクエストを
        # フック実行前に完了させるため、--timeout-graceful-shutdown を設定して待機時間を制限してください。
        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]:
            try:
                event = client.beta.webhooks.unwrap(raw.decode(), headers=headers)
            except standardwebhooks.WebhookVerificationError:
                return {"error": "signature verification failed"}, 401
            if event.data.type != "session.status_run_started":
                return {"status": "ignored"}, 200
            task = asyncio.create_task(run_queued_work())
            inflight.add(task)
            task.add_done_callback(inflight.discard)
            try:
                # シールド済み: 配信の切断やタイムアウトで項目をキャンセルしてはなりません。キャンセルは shutdown() が行います。
                await asyncio.shield(task)
            except asyncio.CancelledError:
                return {"status": "shutting down"}, 503
            return {"status": "ok"}, 200


        async def run_queued_work() -> None:
            async for work in client.beta.environments.work.poller(
                environment_id=environment_id,
                environment_key=environment_key,
                block_ms=None,
                reclaim_older_than_ms=2000,
                drain=True,
                auto_stop=False,
            ):
                await client.beta.environments.work.worker(workdir="/workspace").handle_item(
                    work_id=work.id,
                    environment_id=environment_id,
                    session_id=work.data.id,
                    environment_key=environment_key,
                    # セッションごとのシークレットにより、ワーカーはセッションのメモリストアをマウントできます。
                    work_secret=work.secret,
                )
        ```
      </CodeGroupItem>

      ```typescript TypeScript
      import Anthropic from "@anthropic-ai/sdk";

      const environmentKey = process.env.ANTHROPIC_ENVIRONMENT_KEY!;
      const environmentId = process.env.ANTHROPIC_ENVIRONMENT_ID!;
      const client = new Anthropic({
        authToken: environmentKey
      });
      // ホストのSIGTERM/SIGINTハンドラーから、サーバーのクローズと併せて shutdown.abort() を呼び出し、
      // 終了前に実行中の handle() 呼び出しを待機します。abortにより、実行中の作業項目が
      // 変更されたメモリファイルをアップロードし、ストアディレクトリを先に削除できます。
      export const shutdown = new AbortController();

      export async function handle(req: Request): Promise<Response> {
        // ここで実行されない作業の配信は決して確認応答しないでください。503を返すと送信側が再試行します。
        if (shutdown.signal.aborted) {
          return Response.json({ status: "shutting down" }, { status: 503 });
        }
        const body = await req.text();
        let event;
        try {
          event = client.beta.webhooks.unwrap(body, { headers: Object.fromEntries(req.headers) });
        } catch {
          return new Response("signature verification failed", { status: 401 });
        }
        if (event.data.type !== "session.status_run_started") {
          return Response.json({ status: "ignored" });
        }

        for await (const work of client.beta.environments.work.poller({
          environmentId,
          environmentKey,
          blockMs: null,
          reclaimOlderThanMs: 2000,
          drain: true,
          autoStop: false,
          signal: shutdown.signal
        })) {
          await client.beta.environments.work.worker({ workdir: "/workspace" }).handleItem({
            workId: work.id,
            environmentId,
            sessionId: work.data.id,
            environmentKey,
            // セッションごとのシークレットにより、ワーカーはセッションのメモリストアをマウントできます。
            workSecret: work.secret ?? undefined,
            signal: shutdown.signal
          });
        }
        // ポーラーと handleItem はabort時に静かに戻るため、途中で打ち切られたドレインはここに到達します。
        if (shutdown.signal.aborted) {
          return Response.json({ status: "shutting down" }, { status: 503 });
        }
        return Response.json({ status: "ok" });
      }
      ```

      <CodeGroupItem language="C#">
        C# SDKには `EnvironmentWorker` がありません。独自のコードからワークアイテムを処理するには、[Environments Workエンドポイント](https://platform.claude.com/docs/ja/api/beta/environments/work)を呼び出してください。
      </CodeGroupItem>

      ```go Go
      package main

      import (
      	"context"
      	"encoding/json"
      	"errors"
      	"io"
      	"log/slog"
      	"net/http"
      	"os"
      	"os/signal"
      	"syscall"

      	"github.com/anthropics/anthropic-sdk-go"
      	"github.com/anthropics/anthropic-sdk-go/lib/environments"
      	"github.com/anthropics/anthropic-sdk-go/option"
      	"github.com/anthropics/anthropic-sdk-go/packages/param"
      )

      var (
      	environmentKey = os.Getenv("ANTHROPIC_ENVIRONMENT_KEY")
      	environmentID  = os.Getenv("ANTHROPIC_ENVIRONMENT_ID")
      	client         = anthropic.NewClient(
      		option.WithAuthToken(environmentKey),
      		option.WithWebhookKey(os.Getenv("ANTHROPIC_WEBHOOK_SIGNING_KEY")),
      	)
      	worker = environments.NewEnvironmentWorker(client, environments.EnvironmentWorkerOptions{
      		Workdir: "/workspace",
      	})
      	// SIGINT または SIGTERM でキャンセルされます（main で設定）。これにより処理中の作業項目が
      	// 終了前に変更されたメモリファイルをアップロードし、ストアディレクトリを削除できます。
      	shutdown context.Context
      )

      func handle(w http.ResponseWriter, r *http.Request) {
      	body, err := io.ReadAll(r.Body)
      	if err != nil {
      		http.Error(w, "bad request", http.StatusBadRequest)
      		return
      	}
      	event, err := client.Beta.Webhooks.Unwrap(body, r.Header)
      	if err != nil {
      		http.Error(w, "signature verification failed", http.StatusUnauthorized)
      		return
      	}
      	if event.Data.Type != "session.status_run_started" {
      		json.NewEncoder(w).Encode(map[string]string{"status": "ignored"})
      		return
      	}

      	// Go SDK は RunOne の便利関数を提供しません。保留中の項目を
      	// WorkPoller で取り出し、それぞれを HandleItem で実行します。
      	// r.Context() から切り離します。セッションはwebhook配信タイムアウトより長く存続する可能性があります。
      	// プロセス全体のシャットダウンコンテキストにより、SIGTERM 時も項目は正常に終了します。
      	ctx := shutdown
      	poller := environments.NewWorkPoller(ctx, client, environments.WorkPollerOptions{
      		EnvironmentID:      environmentID,
      		EnvironmentKey:     environmentKey,
      		BlockMs:            param.Null[int64](),
      		ReclaimOlderThanMs: param.NewOpt[int64](2000),
      		Drain:              true,
      		AutoStop:           param.NewOpt(false),
      	})
      	defer poller.Close()
      	for poller.Next() {
      		item := poller.Current()
      		if err := worker.HandleItem(ctx, environments.HandleItemOptions{
      			WorkID:         item.ID,
      			EnvironmentID:  item.EnvironmentID,
      			SessionID:      item.Data.ID,
      			EnvironmentKey: environmentKey,
      			// セッションごとのシークレットにより、ワーカーはセッションのメモリストアをマウントできます。
      			WorkSecret: item.Secret,
      		}); err != nil {
      			slog.Error("handle work item", "work_id", item.ID, "err", err)
      			http.Error(w, "internal error", http.StatusInternalServerError)
      			return
      		}
      	}
      	if err := poller.Err(); err != nil {
      		slog.Error("poll work queue", "err", err)
      		http.Error(w, "internal error", http.StatusInternalServerError)
      		return
      	}
      	json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
      }

      func main() {
      	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
      	defer stop()
      	shutdown = ctx

      	server := &http.Server{Addr: ":8080"}
      	http.HandleFunc("POST /webhook", handle)
      	go func() {
      		if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
      			slog.Error("http server", "err", err)
      			os.Exit(1)
      		}
      	}()
      	// シグナル受信時は配信の受け付けを停止し、処理中のハンドラー、
      	// つまりその作業項目のメモリ後処理が完了してから戻ります。
      	<-ctx.Done()
      	if err := server.Shutdown(context.Background()); err != nil {
      		slog.Error("http shutdown", "err", err)
      	}
      }
      ```

      <CodeGroupItem language="Java">
        Java SDKには `EnvironmentWorker` がありません。独自のコードからワークアイテムを処理するには、[Environments Workエンドポイント](https://platform.claude.com/docs/ja/api/beta/environments/work)を呼び出してください。
      </CodeGroupItem>

      <CodeGroupItem language="PHP">
        PHP SDKには `EnvironmentWorker` がありません。独自のコードからワークアイテムを処理するには、[Environments Workエンドポイント](https://platform.claude.com/docs/ja/api/beta/environments/work)を呼び出してください。
      </CodeGroupItem>

      <CodeGroupItem language="Ruby">
        Ruby SDKには `EnvironmentWorker` がありません。独自のコードからワークアイテムを処理するには、[Environments Workエンドポイント](https://platform.claude.com/docs/ja/api/beta/environments/work)を呼び出してください。
      </CodeGroupItem>
    </CodeGroup>

    ハンドラーは自らワークを取得するため、ここでの `work_secret` (typescript: `workSecret`; go: `WorkSecret`) 引数のように、[ワークアイテムのシークレットを転送](https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes-workers#forward-the-work-items-secret)する必要があります。
  </Step>
</Steps>

このハンドラーは、取得したすべてのアイテムを1つのホスト上の1つのプロセスで実行します。セッションが同じメモリストアをアタッチする場合は、[ストアを共有するセッションを分離する](https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes-memory#isolate-sessions-that-share-a-store)を参照してください。

## セッションごとに1つのサンドボックスを実行する

ホスト上のポーラーがワークを取得し、ワークアイテムごとに1回スクリプトを呼び出します。スクリプトはその1つのセッション用のサンドボックスを起動します。

<Steps>
  <Step title="サンドボックスイメージをビルドする">
    `ant` をインストールし、`ant beta:worker run` をエントリポイントとして設定します。サンドボックスが起動すると、環境変数からセッションの詳細を読み取り、そのセッションを処理して終了します。ベースイメージには `/bin/bash` が必要です。`curl` はビルド時にのみ使用されます。

    ```dockerfile
    FROM your-base-image
    ARG ANT_VERSION=1.42.0
    ARG TARGETARCH
    RUN ARCH=$([ "$TARGETARCH" = "arm64" ] && echo arm64 || echo amd64) && \
        curl -fsSL "https://github.com/anthropics/anthropic-cli/releases/download/v${ANT_VERSION}/ant_${ANT_VERSION}_linux_${ARCH}.tar.gz" \
          | tar -xz -C /usr/local/bin ant
    WORKDIR /workspace
    VOLUME /workspace
    ENTRYPOINT ["ant", "beta:worker", "run"]
    ```
  </Step>

  <Step title="スポーンスクリプトを作成する">
    スクリプトはセッションの詳細を新しいサンドボックスに転送します。ポーラーのホストに `jq` が必要です。

    ```bash
    #!/bin/bash
    # spawn.sh: 取得した作業項目ごとに1回呼び出されます
    # 取得した作業項目は stdin から JSON として渡されます。
    ANTHROPIC_WORK_SECRET="$(jq -r '.secret // empty')"
    export ANTHROPIC_WORK_SECRET
    mkdir -p "/host/outputs/$ANTHROPIC_SESSION_ID"
    exec docker run --rm \
      -e ANTHROPIC_SESSION_ID -e ANTHROPIC_ENVIRONMENT_KEY \
      -e ANTHROPIC_WORK_ID -e ANTHROPIC_ENVIRONMENT_ID -e ANTHROPIC_BASE_URL \
      -e ANTHROPIC_WORK_SECRET \
      -v "/host/outputs/$ANTHROPIC_SESSION_ID":/workspace \
      your-image
    ```

    ポーラーは、スクリプトが転送する `ANTHROPIC_*` 変数を設定します（シークレットを除く）。[環境変数](https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes-reference#environment-variables)を参照してください。

    `/host/outputs` は任意に選択するホストディレクトリです。これを `/workspace` にマウントすると、サンドボックスの終了後にセッションの成果物を取得できます。このマウントには、ダウンロードされた `skills/` ツリーや中間ファイルも含まれます。
  </Step>

  <Step title="ポーラーを起動する">
    ```bash
    ant beta:worker poll --on-work ./spawn.sh
    ```
  </Step>
</Steps>

### ワークアイテムのシークレットを転送する

取得した各ワークアイテムには、Anthropicが発行するセッションごとの `secret` (csharp, go: `Secret`) が含まれる場合があります。セッションを実行するワーカーは、[メモリストア](https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes-memory)をマウントするためにこれを必要とします。

セッションの取得と実行を1つのプロセスで行うワーカー（`--on-work` なしの `ant beta:worker poll`、または `run()` (go: `Run()`) を使用する `EnvironmentWorker`）は、シークレットを自ら受け渡します。取得とワーカーの間に独自のコードが入る場合は、自分で転送します：

| ワークの取得方法                                                  | シークレットの受け取り方                                | ワーカーへの渡し方                                                                                                                                                                  |
| --------------------------------------------------------- | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ant beta:worker poll --on-work`                          | スクリプトの標準入力に渡されるワークアイテムのJSONの `secret` フィールド | サンドボックスの環境内の `ANTHROPIC_WORK_SECRET`                                                                                                                                       |
| SDKの `work.poller()` (go: `environments.NewWorkPoller()`) | 取得した各ワークアイテムの `secret` (go: `Secret`) フィールド | サンドボックスの環境内の `ANTHROPIC_WORK_SECRET`、または `handle_item()` (typescript: `handleItem()`; go: `HandleItem()`) への `work_secret` (typescript: `workSecret`; go: `WorkSecret`) 引数 |

シークレットは、そのセッションを処理するサンドボックスにのみ渡し、決してログに記録しないでください。環境キーとの関係については、[セキュリティモデル](https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes-security)を参照してください。

### SDKポーラーからサンドボックスを起動する

`ant beta:worker poll --on-work` の代わりに独自のコードからワークを取得するには、`work.poller()` (go: `environments.NewWorkPoller()`) を使用します。これはキューをポーリングして取得した各セッションを渡すので、お客様がサンドボックスを起動します：

<CodeGroup exclude="shell, csharp, java, php, ruby">
  <CodeGroupItem language="cURL">
    ループでワークを取得し、セッションごとにサンドボックスを起動するには、単一のシェルコマンドよりも多くのロジックが必要です。シェルからは、[セッションごとに1つのサンドボックスを実行する](https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes-workers#run-one-sandbox-per-session)のように、起動スクリプトを指定して `ant beta:worker poll --on-work` を実行してください。
  </CodeGroupItem>

  <CodeGroupItem language="CLI">
    シェルからワークを取得してセッションごとにサンドボックスを起動するには、[セッションごとに1つのサンドボックスを実行する](https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes-workers#run-one-sandbox-per-session)のように、起動スクリプトを指定して `ant beta:worker poll --on-work` を実行してください。
  </CodeGroupItem>

  ```python Python
  import asyncio
  import os

  from anthropic import AsyncAnthropic
  from anthropic.types.beta.environments import BetaSelfHostedWork

  SANDBOX_ENV = (
      "ANTHROPIC_ENVIRONMENT_ID",
      "ANTHROPIC_ENVIRONMENT_KEY",
      "ANTHROPIC_WORK_ID",
      "ANTHROPIC_SESSION_ID",
      "ANTHROPIC_WORK_SECRET",
      "ANTHROPIC_BASE_URL",  # forwarded only when set on this host
  )


  async def launch_container(work: BetaSelfHostedWork) -> None:
      print(f"claimed session {work.data.id}")
      # `docker run` は独自のサンドボックス起動ツールに置き換えてください。環境
      # キー（APIキーは絶対に渡さないでください）と作業項目のセッションごとのシークレットを転送します。内部のワーカーは
      # セッションのメモリストアをマウントするためにこのシークレットを必要とします。
      env = os.environ | {
          "ANTHROPIC_WORK_ID": work.id,
          "ANTHROPIC_SESSION_ID": work.data.id,
          "ANTHROPIC_WORK_SECRET": work.secret or "",
      }
      forward = [arg for name in SANDBOX_ENV for arg in ("-e", name)]
      launcher = await asyncio.create_subprocess_exec(
          "docker", "run", "--rm", "--detach", *forward, "your-image", env=env
      )
      await launcher.wait()


  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:
          async for work in client.beta.environments.work.poller(
              environment_id=environment_id,
              environment_key=environment_key,
              auto_stop=False,  # the launched sandbox owns the stop call
          ):
              await launch_container(work)


  asyncio.run(main())
  ```

  ```typescript TypeScript
  import { spawn } from "node:child_process";
  import { once } from "node:events";
  import Anthropic from "@anthropic-ai/sdk";
  import { WorkPoller } from "@anthropic-ai/sdk/helpers/beta/environments";
  import type { BetaSelfHostedWork } from "@anthropic-ai/sdk/resources/beta/environments";

  const SANDBOX_ENV = [
    "ANTHROPIC_ENVIRONMENT_ID",
    "ANTHROPIC_ENVIRONMENT_KEY",
    "ANTHROPIC_WORK_ID",
    "ANTHROPIC_SESSION_ID",
    "ANTHROPIC_WORK_SECRET",
    "ANTHROPIC_BASE_URL" // forwarded only when set on this host
  ];

  const environmentKey = process.env.ANTHROPIC_ENVIRONMENT_KEY!;
  const environmentId = process.env.ANTHROPIC_ENVIRONMENT_ID!;
  const client = new Anthropic({ authToken: environmentKey });

  async function launchContainer(work: BetaSelfHostedWork): Promise<void> {
    console.log(`claimed session ${work.data.id}`);
    // `docker run` は独自のサンドボックス起動ツールに置き換えてください。environment
    // key（APIキーは決して渡さないでください）と作業項目のセッションごとのシークレットを転送します。内部の worker は
    // セッションのメモリストアをマウントするためにこのシークレットを必要とします。
    const env = {
      ...process.env,
      ANTHROPIC_WORK_ID: work.id,
      ANTHROPIC_SESSION_ID: work.data.id,
      ANTHROPIC_WORK_SECRET: work.secret ?? ""
    };
    const forward = SANDBOX_ENV.flatMap((name) => ["-e", name]);
    const launcher = spawn("docker", ["run", "--rm", "--detach", ...forward, "your-image"], {
      env,
      stdio: "inherit"
    });
    await once(launcher, "close");
  }

  const poller = new WorkPoller({
    client,
    environmentId,
    environmentKey,
    autoStop: false // the launched sandbox owns the stop call
  });

  for await (const work of poller) {
    await launchContainer(work);
  }
  ```

  <CodeGroupItem language="C#">
    C# SDKにはワークをポーリングするヘルパーがありません。独自のコードからワークを取得するには、[Environments Workエンドポイント](https://platform.claude.com/docs/ja/api/beta/environments/work)を呼び出してください。
  </CodeGroupItem>

  ```go Go
  package main

  import (
  	"context"
  	"fmt"
  	"log"
  	"os"
  	"os/exec"

  	"github.com/anthropics/anthropic-sdk-go"
  	"github.com/anthropics/anthropic-sdk-go/lib/environments"
  	"github.com/anthropics/anthropic-sdk-go/option"
  	"github.com/anthropics/anthropic-sdk-go/packages/param"
  )

  var sandboxEnv = []string{
  	"ANTHROPIC_ENVIRONMENT_ID",
  	"ANTHROPIC_ENVIRONMENT_KEY",
  	"ANTHROPIC_WORK_ID",
  	"ANTHROPIC_SESSION_ID",
  	"ANTHROPIC_WORK_SECRET",
  	"ANTHROPIC_BASE_URL", // forwarded only when set on this host
  }

  func launchContainer(ctx context.Context, work *anthropic.BetaSelfHostedWork) error {
  	fmt.Printf("claimed session %s\n", work.Data.ID)
  	// `docker run` は独自のサンドボックス起動ツールに置き換えてください。environment
  	// key（APIキーは決して渡さないでください）とワークアイテムのセッションごとのシークレットを転送します。内部の worker は
  	// セッションのメモリストアをマウントするためにこのシークレットを必要とします。
  	args := []string{"run", "--rm", "--detach"}
  	for _, name := range sandboxEnv {
  		args = append(args, "-e", name)
  	}
  	launcher := exec.CommandContext(ctx, "docker", append(args, "your-image")...)
  	launcher.Env = append(os.Environ(),
  		"ANTHROPIC_WORK_ID="+work.ID,
  		"ANTHROPIC_SESSION_ID="+work.Data.ID,
  		"ANTHROPIC_WORK_SECRET="+work.Secret,
  	)
  	launcher.Stdout, launcher.Stderr = os.Stdout, os.Stderr
  	return launcher.Run()
  }

  func main() {
  	environmentID := os.Getenv("ANTHROPIC_ENVIRONMENT_ID")
  	environmentKey := os.Getenv("ANTHROPIC_ENVIRONMENT_KEY")

  	client := anthropic.NewClient(option.WithAuthToken(environmentKey))

  	ctx := context.Background()

  	poller := environments.NewWorkPoller(ctx, client, environments.WorkPollerOptions{
  		EnvironmentID:  environmentID,
  		EnvironmentKey: environmentKey,
  		AutoStop:       param.NewOpt(false), // the launched sandbox owns the stop call
  	})
  	defer poller.Close()

  	for work, err := range poller.All() {
  		if err != nil {
  			log.Fatal(err)
  		}
  		if err := launchContainer(ctx, work); err != nil {
  			log.Fatal(err)
  		}
  	}
  }
  ```

  <CodeGroupItem language="Java">
    Java SDKにはワークをポーリングするヘルパーがありません。独自のコードからワークを取得するには、[Environments Workエンドポイント](https://platform.claude.com/docs/ja/api/beta/environments/work)を呼び出してください。
  </CodeGroupItem>

  <CodeGroupItem language="PHP">
    PHP SDKにはワークをポーリングするヘルパーがありません。独自のコードからワークを取得するには、[Environments Workエンドポイント](https://platform.claude.com/docs/ja/api/beta/environments/work)を呼び出してください。
  </CodeGroupItem>

  <CodeGroupItem language="Ruby">
    Ruby SDKにはワークをポーリングするヘルパーがありません。独自のコードからワークを取得するには、[Environments Workエンドポイント](https://platform.claude.com/docs/ja/api/beta/environments/work)を呼び出してください。
  </CodeGroupItem>
</CodeGroup>

### サンドボックス内でSDKワーカーを実行する

サンドボックスで[カスタムツールを提供](https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes-custom-tools)する必要がある場合や、[デフォルト以外のメモリ同期設定](https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes-memory#configure-sync)を使用する必要がある場合は、`ant beta:worker run` エントリポイントをSDKエントリポイントに置き換えます。エントリポイントは `EnvironmentWorker` を構築して `handle_item()` (typescript: `handleItem()`; go: `HandleItem()`) を呼び出します。これはスポーンスクリプトが転送するのと同じ `ANTHROPIC_*` 変数を読み取ります。

<CodeGroup exclude="shell, csharp, java, php, ruby">
  ```python Python
  import asyncio
  import contextlib
  import os
  import signal
  from anthropic import AsyncAnthropic
  from anthropic.lib.environments import EnvironmentWorker


  async def main() -> None:
      async with AsyncAnthropic(
          auth_token=os.environ["ANTHROPIC_ENVIRONMENT_KEY"]
      ) as client:
          worker = EnvironmentWorker(client, workdir="/workspace")
          # 引数なしの場合、handle_item() は spawn スクリプトが転送した ANTHROPIC_* 変数を読み取ります。
          # これには ANTHROPIC_WORK_SECRET も含まれます。
          task = asyncio.create_task(worker.handle_item())
          # コンテナ停止時にタスクをキャンセルすることで、ワーカーは終了前に
          # 変更されたメモリファイルをアップロードし、ストアディレクトリを削除できます。
          loop = asyncio.get_running_loop()
          for signum in (signal.SIGINT, signal.SIGTERM):
              loop.add_signal_handler(signum, task.cancel)
          with contextlib.suppress(asyncio.CancelledError):
              await task


  asyncio.run(main())
  ```

  ```typescript TypeScript
  import Anthropic from "@anthropic-ai/sdk";
  import { EnvironmentWorker } from "@anthropic-ai/sdk/helpers/beta/environments";

  const client = new Anthropic({ authToken: process.env.ANTHROPIC_ENVIRONMENT_KEY });
  const controller = new AbortController();
  // コンテナ停止時に中断することで、ワーカーは変更されたメモリファイルをアップロードし、
  // 終了前にストアディレクトリを削除できます。
  process.once("SIGTERM", () => controller.abort());
  process.once("SIGINT", () => controller.abort());

  // 引数なしの場合、handleItem() は spawn スクリプトが転送した ANTHROPIC_* 変数を読み取ります。
  // これには ANTHROPIC_WORK_SECRET も含まれます。
  await new EnvironmentWorker({
    client,
    workdir: "/workspace",
    signal: controller.signal
  }).handleItem();
  ```

  <CodeGroupItem language="C#">
    C# SDKには `EnvironmentWorker` がありません。
  </CodeGroupItem>

  ```go Go
  package main

  import (
  	"context"
  	"log"
  	"os"
  	"os/signal"
  	"syscall"

  	"github.com/anthropics/anthropic-sdk-go"
  	"github.com/anthropics/anthropic-sdk-go/lib/environments"
  	"github.com/anthropics/anthropic-sdk-go/option"
  )

  func main() {
  	// コンテナ停止時にコンテキストをキャンセルすることで、ワーカーは終了前に
  	// 変更されたメモリファイルをアップロードし、ストアディレクトリを削除できます。
  	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
  	defer stop()

  	client := anthropic.NewClient(option.WithAuthToken(os.Getenv("ANTHROPIC_ENVIRONMENT_KEY")))
  	worker := environments.NewEnvironmentWorker(client, environments.EnvironmentWorkerOptions{
  		Workdir: "/workspace",
  	})
  	// ゼロ値のオプションでは、HandleItem は spawn スクリプトが転送した
  	// ANTHROPIC_* 変数（ANTHROPIC_WORK_SECRET を含む）を読み取ります。
  	if err := worker.HandleItem(ctx, environments.HandleItemOptions{}); err != nil {
  		log.Fatalf("worker: %v", err)
  	}
  }
  ```

  <CodeGroupItem language="Java">
    Java SDKには `EnvironmentWorker` がありません。
  </CodeGroupItem>

  <CodeGroupItem language="PHP">
    PHP SDKには `EnvironmentWorker` がありません。
  </CodeGroupItem>

  <CodeGroupItem language="Ruby">
    Ruby SDKには `EnvironmentWorker` がありません。
  </CodeGroupItem>
</CodeGroup>

## セッション用のファイルをステージングする

Anthropicは、セルフホスト型サンドボックスにファイルやGitHubリポジトリをマウントしません。セッション固有のファイルを利用可能にするには：

1. S3パスやコミットSHAなどのファイル参照を、セッションの `metadata` フィールドで渡します。
2. スポーンスクリプトまたは `--on-work` ハンドラーで、セッションを取得（`GET /v1/sessions/{session_id}`）して `metadata` を読み取ります。取得したワークアイテムにはセッションIDは含まれますが、メタデータは含まれません。
3. ツールの実行が始まる前に、ファイルを作業ディレクトリにステージングします。

<CodeGroup>
  ```bash cURL
  curl -sS --fail-with-body https://api.anthropic.com/v1/sessions \
    -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 '{
      "agent": "'"$AGENT_ID"'",
      "environment_id": "'"$ANTHROPIC_ENVIRONMENT_ID"'",
      "metadata": {"input_file": "s3://my-bucket/data.csv"}
    }'
  ```

  ```bash CLI
  ant beta:sessions create \
    --agent "$AGENT_ID" \
    --environment-id "$ANTHROPIC_ENVIRONMENT_ID" \
    --metadata '{"input_file": "s3://my-bucket/data.csv"}'
  ```

  ```python Python
  session = client.beta.sessions.create(
      agent=agent.id,
      environment_id=environment.id,
      metadata={"input_file": "s3://my-bucket/data.csv"},
  )
  ```

  ```typescript TypeScript
  const session = await client.beta.sessions.create({
    agent: agent.id,
    environment_id: environment.id,
    metadata: { input_file: "s3://my-bucket/data.csv" }
  });
  ```

  ```csharp C#
  var session = await client.Beta.Sessions.Create(new()
  {
      Agent = agent.ID,
      EnvironmentID = environment.ID,
      Metadata = new Dictionary<string, string> { ["input_file"] = "s3://my-bucket/data.csv" },
  });
  ```

  ```go Go
  session, err := client.Beta.Sessions.New(ctx, anthropic.BetaSessionNewParams{
  	Agent:         anthropic.BetaSessionNewParamsAgentUnion{OfString: anthropic.String(agent.ID)},
  	EnvironmentID: environment.ID,
  	Metadata: map[string]string{
  		"input_file": "s3://my-bucket/data.csv",
  	},
  })
  if err != nil {
  	panic(err)
  }
  ```

  ```java Java
  var session = client.beta().sessions().create(SessionCreateParams.builder()
      .agent(agent.id())
      .environmentId(environment.id())
      .metadata(SessionCreateParams.Metadata.builder()
          .putAdditionalProperty("input_file", JsonValue.from("s3://my-bucket/data.csv"))
          .build())
      .build());
  ```

  ```php PHP
  $session = $client->beta->sessions->create(
      agent: $agent->id,
      environmentID: $environment->id,
      metadata: ['input_file' => 's3://my-bucket/data.csv'],
  );
  ```

  ```ruby Ruby
  session = client.beta.sessions.create(
    agent: agent.id,
    environment_id: environment.id,
    metadata: {input_file: "s3://my-bucket/data.csv"}
  )
  ```
</CodeGroup>

## 次のステップ

<CardGroup cols={2}>
  <Card title="監視とトラブルシューティング" icon="lightning" href="https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes-operations">
    キューの深さを確認し、セッションとワーカーを正常に停止し、一般的な障害を修正します。
  </Card>

  <Card title="セキュリティモデル" icon="lock" href="https://platform.claude.com/docs/ja/managed-agents/self-hosted-sandboxes-security">
    セルフホスト型サンドボックス環境における責任共有モデル。
  </Card>
</CardGroup>
