Claude Media
Agent SDKのsandbox設定をコードから制御する — TypeScript/Python実装ガイド

Agent SDKのsandbox設定をコードから制御する — TypeScript/Python実装ガイド

Agent SDKのSandboxSettingsをTypeScript/Pythonで設定し、コマンド・ネットワークを制限する方法。両言語の設定差とdangerouslyDisableSandboxのフォールバックを解説。

Agent SDKのsandbox設定でできること

Agent SDKのsandboxオプションは、Claudeが実行するBashコマンドをOSレベルで隔離する機能を、設定ファイルではなくコードから直接制御する仕組みです。SandboxSettingsquery()ClaudeAgentOptionsに渡すだけで、コマンド実行・ネットワーク到達先・ファイル書き込み範囲をプログラム的に絞り込めます。

TypeScript版とPython版は同じsandboxオプションを共有していますが、既定の挙動と設定項目の粒度が言語間で食い違います。両方でSDKを使い分けるチームほど、この差分を知らずに本番へ出すと片方だけ想定外の動作になります。本記事はその差分を実装コードで示します。SDK自体の基本的な始め方はClaude Agent SDK入門で扱っているので、はじめてSDKを触る場合は先にそちらで最小構成を動かしてください。

TypeScriptでSandboxSettingsを有効にする

TypeScript版のSandboxSettingsは次の形をとります。

type SandboxSettings = {
  enabled?: boolean;
  failIfUnavailable?: boolean;
  autoAllowBashIfSandboxed?: boolean;
  excludedCommands?: string[];
  allowUnsandboxedCommands?: boolean;
  network?: SandboxNetworkConfig;
  filesystem?: SandboxFilesystemConfig;
  ignoreViolations?: Record<string, string[]>;
  enableWeakerNestedSandbox?: boolean;
  ripgrep?: { command: string; args?: string[] };
};

enabled: trueにするとBashコマンドの実行がサンドボックス内に隔離されます。実際に有効化するコードは次の通りです。

import { query } from "@anthropic-ai/claude-agent-sdk";
 
try {
  for await (const message of query({
    prompt: "Build and test my project",
    options: {
      sandbox: {
        enabled: true,
        autoAllowBashIfSandboxed: true,
        network: {
          allowLocalBinding: true
        }
      }
    }
  })) {
    if ("result" in message) console.log(message.result);
  }
} catch (error) {
  // サンドボックスが起動できない場合など、
  // 単発のquery()はエラー結果をyieldした後にthrowする
  console.log(`Session ended with an error: ${error}`);
}

autoAllowBashIfSandboxedは既定でtrueで、サンドボックス化されたBashコマンドを自動承認します。サンドボックス自体がOSレベルで隔離するため、この既定値は妥当な設計です。

重要なのはfailIfUnavailableです。TypeScript版はこれが既定でtrueになっています。サンドボックスが起動できない環境でenabled: trueを渡すと、そこで処理を止めます。あえて隔離なしで走らせたいときはfailIfUnavailable: falseを明示してフォールバックさせます。

サンドボックスが動くのはmacOS・Linux・WSL2で、ネイティブのWindowsには対応していません。Windows環境で使うにはWSL2ディストリビューション内でClaude Codeを動かす必要があります。macOSは組み込みのSeatbeltフレームワークを使うため追加インストールは不要ですが、LinuxとWSL2ではbubblewrapsocatが必要です。起動できないとquery()の結果メッセージがsubtype: "error_during_execution"になり、単発のquery()呼び出しではそのままthrowされるため、必ずtry/catchで囲みます。

Pythonでは何が違うのか — failIfUnavailableの既定値

Python版のSandboxSettingsTypedDictで定義されています。

class SandboxSettings(TypedDict, total=False):
    enabled: bool
    autoAllowBashIfSandboxed: bool
    excludedCommands: list[str]
    allowUnsandboxedCommands: bool
    network: SandboxNetworkConfig
    ignoreViolations: SandboxIgnoreViolations
    enableWeakerNestedSandbox: bool

見比べると、Python版にはfailIfUnavailablefilesystemripgrepが型として宣言されていません。ここが両言語で最も踏み外しやすい差です。

Python版はenabled: Trueかつサンドボックスが起動できない場合、既定では隔離なしのまま実行を続け、stderrに警告を出すだけです。TypeScript版の「既定で起動を止める」とは正反対の挙動になります。厳格に止めたいなら、型に無いキーを辞書へ直接足します。

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions
 
sandbox_settings = {
    "enabled": True,
    "autoAllowBashIfSandboxed": True,
    "failIfUnavailable": True,
    "network": {"allowLocalBinding": True},
}
 
 
async def main():
    try:
        async for message in query(
            prompt="Build and test my project",
            options=ClaudeAgentOptions(sandbox=sandbox_settings),
        ):
            print(message)
    except Exception as error:
        print(f"Session ended with an error: {error}")
 
 
asyncio.run(main())

failIfUnavailableキーはSandboxSettingsの型定義には無いものの、SDKはこの値をそのままClaude Codeへ転送し、Claude Code側がその値を尊重します。型チェッカーには警告されますが、動作上は機能します。

TypeScript(隔離できないなら止める)とPython(隔離できないなら続ける)で、フェイルセーフの方向は真逆です。この違いは、CI環境でサンドボックスの可用性が不安定なチームほど重要になります。Pythonで厳格な隔離を前提にしたワークフローを組むなら、failIfUnavailable: Trueを省略しないことが必須になります。

ネットワークとファイルシステムを絞り込む

SandboxNetworkConfigはサンドボックス化されたBashコマンドのネットワーク到達先を制御します。WebFetchツールはこの設定の対象外で、権限ルール側で別途制御される点に注意してください。

allowedDomainsで許可するドメインを指定するのに対し、deniedDomainsは同じワイルドカード構文で明示的に拒否するドメインを指定でき、両方に一致した場合は拒否が優先されます。Unixソケットを個別パスで許可するallowUnixSocketsとは別に、allowAllUnixSocketstrueにするとすべてのUnixソケットへの接続を許可できます。LinuxとWSL2ではseccompフィルタがUnixソケットへの接続をまとめてブロックするため、個別パスの許可ではなくソケット全体を開けたい場合はこちらを使います。httpProxyPort/socksProxyPortを指定すると、Claude Codeが内蔵するプロキシの代わりに自前のプロキシへ通信を経由させられます。

ファイルシステムの読み書き制限は、TypeScript版だけがSandboxFilesystemConfigとして持っています。

type SandboxFilesystemConfig = {
  allowWrite?: string[];
  denyWrite?: string[];
  denyRead?: string[];
};

allowWriteで書き込みを許可するパスパターンを、denyWritedenyReadでそれぞれ拒否パターンを指定します。Python版のSandboxSettingsにはこれに相当するフィールドが公式リファレンスに存在しません。ファイル読み書きの範囲を細かく絞りたい場合、TypeScript版の方が制御粒度は高いということです。コンテナ単位でファイルシステムごと隔離したい場合は、DevContainerでの安全な実装のようにOSレベルの隔離と組み合わせる選択肢もあります。

モデルにサンドボックスの外を頼ませるときの許可設計

allowUnsandboxedCommandsは既定でtrueです。何も設定しなくても、モデルはツール入力にdangerouslyDisableSandbox: trueを付けてサンドボックス外での実行をすでに要求できる状態にあります。この要求は既存の権限システムにフォールバックし、TypeScriptならcanUseTool、Pythonならcan_use_toolハンドラーが呼ばれます。サンドボックス外の実行を一切認めない前提で運用したいなら、allowUnsandboxedCommands: falseを明示する必要があります。

import { query } from "@anthropic-ai/claude-agent-sdk";
 
for await (const message of query({
  prompt: "Deploy my application",
  options: {
    sandbox: {
      enabled: true,
      allowUnsandboxedCommands: true
    },
    permissionMode: "default",
    canUseTool: async (tool, input) => {
      if (tool === "Bash" && input.dangerouslyDisableSandbox) {
        if (isCommandAuthorized(input.command)) {
          return { behavior: "allow" as const, updatedInput: input };
        }
        return {
          behavior: "deny" as const,
          message: "Command not authorized for unsandboxed execution"
        };
      }
      return { behavior: "allow" as const, updatedInput: input };
    }
  }
})) {
  if ("result" in message) console.log(message.result);
}

excludedCommandsに列挙したコマンド(dockerなど)は、この権限フローを経由せずモデルの関与なしに自動でサンドボックスをバイパスします。認証チェックを挟みたいコマンドはexcludedCommandsではなくallowUnsandboxedCommands側に寄せます。

よくあるつまずき

  • ignoreViolationsで緩めたつもりが緩んでいない: TypeScript版はRecord<string, string[]>(コマンド部分文字列、または全コマンド対象の*をキーに、無視したい違反テキストの部分文字列を値にする形。例{ "*": ["/etc/hosts"] })。Python版はSandboxIgnoreViolationsという別型で、file: list[str]network: list[str]をそれぞれ持つ形です。移植時にそのままキーをコピーすると型が合いません。加えて、この設定はブロック自体を解除するものではなく、違反レポートを黙らせるだけです。アクセスは引き続き拒否されるため、「無視リストに入れたのにコマンドが動かない」ときは設計どおりの挙動です。
  • Python版にfilesystem設定が無い: TypeScript版のコードをPythonへ移植するとき、allowWrite/denyWrite/denyReadを渡そうとしても受け皿がありません。ファイル書き込み範囲の制御が必要なワークフローは、この制約を先に確認しておきます。
  • strictAllowlistは設定源を選ぶ: ユーザー設定・managed設定・CLIの--settingsからは効きますが、プロジェクト設定は無視されます。
  • allowManagedDomainsOnlyはmanaged設定でのみ有効: SDKオプション経由で設定しても効果がありません。どちらも設定を書いたのに反映されないときは、設定の入力元(ユーザー設定/managed設定/プロジェクト設定/SDKオプション)を疑います。
  • プラットフォーム非対応での無言のフォールバック(Python): failIfUnavailableを明示しないままPython版でenabled: trueだけ渡すと、サンドボックスが使えない環境でも隔離なしで実行が進みます。CI環境をまたいでポリシーを揃えたいなら、両言語ともfailIfUnavailableを明示するのが安全です。
  • excludedCommandsallowUnsandboxedCommandsを混同する: 前者はモデルの関与なしに自動でサンドボックスをバイパスする、いわば無条件の除外リストです。後者はモデルが要求しcanUseTool/can_use_toolが判断する、承認フロー付きの抜け道です。認証チェックを挟みたいコマンドを誤ってexcludedCommandsに入れると、チェックが一切走らずに実行されてしまいます。
  • enableWeakerNestedSandboxを通常運用で有効にする: 公式リファレンスはこのフラグを「互換性のための弱いネストサンドボックスを有効化する」設定とだけ説明しています。両言語とも既定はfalseで、コンテナの中でさらにサンドボックスを動かすような入れ子構成での互換性維持が目的です。通常の単層構成で有効化する理由はありません。

sandbox設定オプションの使い分け早見表

設定項目TypeScriptPython備考
failIfUnavailableの型宣言TypeScriptあり(既定true)Pythonなし(既定で隔離なし続行)備考Pythonは辞書に直接キーを足せば動作する
filesystem(読み書き制限)TypeScriptSandboxFilesystemConfigありPython相当フィールドなし備考書き込み範囲を絞るならTypeScript側が有利
network.strictAllowlistTypeScriptあり(v2.1.219以降)Python相当フィールドなし備考managed/ユーザー/CLI設定からのみ有効
network.allowMachLookupTypeScript相当フィールドなしPythonあり(macOS専用)備考XPC/Machサービス名の許可リスト
ignoreViolationsの形TypeScriptRecord<string, string[]>PythonSandboxIgnoreViolations(file/network)備考移植時にキー形式がそのまま流用できない
ripgrepカスタムバイナリ指定TypeScriptありPython相当フィールドなし備考サンドボックス環境向けのripgrepパス指定

まとめ

Agent SDKのsandbox設定は、TypeScript版とPython版で同じ目的の機能を提供しつつ、既定値と項目の粒度が細部で食い違います。特にfailIfUnavailableの既定挙動が言語間で逆という点は、CI/CDや複数言語のマルチエージェント構成を組むチームが最初に踏みやすい落とし穴です。設計の全体像(コンテナ・gVisor・VMによる多層防御)を先に押さえたいなら、Agent SDKの安全なデプロイ設計を土台にし、本記事はその上でSDKのコード側から何を制御できるかのリファレンスとして使ってください。サンドボックスが承認疲れをどう減らす設計になっているかはClaude Codeのサンドボックス設計、セッション・ハーネスとの分離思想はManaged Agentsの設計思想で扱っています。

よくある質問

Claude Code本体の設定ファイルでのサンドボックス設定と何が違いますか

設定ファイル側のsandbox設定はCLI利用者向けの静的な設定です。Agent SDKのSandboxSettingsは同じ機能をコードから動的に組み立てる手段で、query()呼び出しごとに条件分岐させたい場合に向いています。

この記事を共有:XはてブLinkedIn