Grandream
Sandboxを1つにした判断|Docker Sandboxes
連載「Docker Sandboxesでコーディングエージェントを隔離する」第6回/検証日: 2026年8月23日/
sbx0.39.0・Node.js 22.12.0・Codex CLI 0.146.0
第1回から第5回まで、「clone modeの永続Sandboxを1つ立て、CodexとClaude Codeを同居させる」形で書いてきました。今回はその手前の判断です。
先に結論を書きます。この構成を選ぶかどうかは、性能でもセキュリティでもなく、自分の作業パターンで決まりました。 独立した2タスクを並走させたいならエージェントごとにSandboxを分けるのが素直です。ところが実際に多いのは、同じタスクをCodexとClaudeで途中交代することでした。設計をCodexに詰めさせ、実装をClaudeに書かせ、詰まったら逆に読ませる。この頻度だと、分離のコストが利益を上回ります。
ホストには隔離を強く、エージェント同士は共有する
決めるべきことは2つあり、混ぜると議論が進みませんでした。
軸 | 選択肢 | 決めたこと |
|---|---|---|
ホストとの境界 | working tree共有mount / clone mode | clone mode(隔離を強く取る) |
エージェント同士の境界 | agent別Sandbox / 単一Sandboxで共有 | 単一Sandbox(共有を取る) |
非対称になったのは、守る価値のある資産が片側にしか無かったからです。ホスト側にはコミット済みの履歴があり、ホストの認証情報があり、macOS用のビルド生成物があります。一方でCodexとClaudeの間には、守るべきものがほとんどありません。同じリポジトリの同じブランチを、交互に触っているだけです。
ホストworking treeの共有は、性能ではなく「動かない」で消えた
最初に試したのは、ホストとSandboxが同じworking treeを直接読み書きする方式です。ホストのIDEでそのままファイルを開けて、複数Sandboxから同じ変更を参照できる。分かりやすさは明らかにこちらが上でした。
消えた理由は遅さではありません。動かなかったからです。macOSのVirtioFS上でLinuxのnpmを走らせると、node_modulesの大量の小さいファイル操作と相性が悪く、npmの並列ディレクトリ作成でENOTDIRが出ました。VirtioFSのcacheを無効化すれば改善しましたが、標準運用に追加設定が要る時点で他のメンバーへ渡せません。
仮に動いたとしても、生成物が衝突します。macOS用とLinux用の成果物が同じworking treeへ同居するからです。node_modulesの所有者が食い違い、ネイティブbinaryが入れ替わり、file watchingと.nextのcacheが噛み合わなくなる。第1回で「Linux用のnode_modulesがmacOS用を踏み潰す事故が起きない」と書けるのは、この方式を捨てた結果です。
隔離も薄くなります。Sandboxからホストのworking treeへ直接書けるので、エージェントに事前承認をほとんど求めない運用(第1回)と組み合わせるには心細い。
そして決め手は、共有mountが要件ではなかったことです。ホストからソースを見たいだけなら、Codex App・Claude Desktop・IDE・ターミナルからsampleapp.sbxへSSH接続すればprivate cloneをそのまま開けます(第5回)。「ホストのエディタで開きたい」はmount以外でも満たせました。
agent別に分けるのが既定、外れた理由は交代コスト
先に押さえておくことがあります。Docker Sandboxesの既定は1 Sandbox 1 agentです。 ドキュメントに推奨として書かれているわけではありません。CLIの形に現れています。
sbx create [flags] AGENT PATH [PATH...] # agent は位置引数(作成時に固定)
sbx run [flags] [AGENT] [PATH...]
# → the agent positional is optional when the named sandbox already exists
# and is read from its spec
sandboxのspecがagentを1つ保持し、再アタッチ時はそこから読む。sbx secret setの組み込みserviceもanthropic・openaiのようにprovider単位で、agentの認証はホスト側に置く設計です。一方で公式ドキュメントは、1つのSandboxへ複数agentを同居させる話を扱っていません。禁じられているのではなく、想定されていないという状態です。
つまり我々がしたのは、既定から外れるという選択でした。「agent別分離という選択肢を捨てた」のとは違います。
初期案どおり専用Sandboxを2つ持たせれば、agentごとの公式templateがそのまま使え、認証もfilesystemもprocessも分離されます。設計としてはそちらが素直です。
それでも外れました。重かったのはnpm ciの二重実行やポートの二重管理より、交代のたびに、渡すためのcommitが必要になることでした。
Codexに設計を詰めさせ、途中からClaudeへ実装を渡す。このとき別Sandboxだと、未コミットの変更をそのまま渡せません。commitしてpushしてfetchする、あるいはpatchを作る。動いている開発サーバーは引き継げず、.nextのビルドキャッシュも作り直しになり、Gitに載らない.env.localは別途配る必要があります。1日に何度も交代する使い方では、この数十秒の儀式が判断のリズムを削りました。
「試しにClaudeにも読ませてみる」がGit操作3回のコストなら、人は試さなくなります。エージェントを2つ用意した意味が薄れる。だから既定から外れて、分離より作業状態の継続性を取りました。
採ったのは、Claude agent typeの単一Sandbox
最終形です。Claude agent typeで永続Sandboxを1つ作り、KitでCodex CLIを足す(第2回)。Codex App・Claude Desktop・CLI・開発サーバーが、同じmicroVMと同じprivate cloneを使います。
macOS host
├─ repository ──→ /run/sandbox/source(virtiofs · read-only)
├─ sbx daemon / credential store
├─ Codex App ────── SSH ─┐
└─ Claude Desktop ─ SSH ─┤
v
sampleapp microVM
├─ private clone(ext4)
├─ Claude Code
├─ Codex CLI
├─ node_modules / .next
└─ app :3000 → host 127.0.0.1:3000
この形で効くのは3点です。private cloneがmicroVM内のext4にあるので、npmのfile I/OがVirtioFSを通りません。node_modulesと.nextはSandbox内に閉じ、停止しても残るので毎回npm ciしなくて済みます。そしてCodexとClaudeが同じbranch・未コミット変更・開発サーバー・buildキャッシュを共有するので、交代に引き継ぎが要りません。
第1回でfindmntの確認を入れたのは、この形になっているかを1コマンドで判定するためです。プロジェクトルートがext4、/run/sandbox/sourceがvirtiofsのread-only。逆になっていたら狙った構成ではありません。
運用で決めておくのは3つ
エージェントの交代。 同じprivate cloneなので引き継ぎcommitは不要です。差分を確認してから切り替えます。
./scripts/sandbox codex
./scripts/sandbox claude
並列作業。 同じworking treeでbranchを切り替えると全セッションに影響します。並列が必要ならmicroVM内にタスク別のGit worktreeとbranchを作り、必要なら各worktreeでnpm ciします。重複が気になるほど並列が増えたら、npm cacheの共有を考える段です。
ホストとの受け渡し。 private cloneとホストのworking treeは自動同期しません。Sandbox作成時にホストへ追加されるsandbox-sampleapp remoteから引きます。
git fetch sandbox-sampleapp
git log --oneline sandbox-sampleapp/<branch> -5
git cherry-pick <commit>
未コミット変更はfetchできず、Sandbox削除で失われます。削除前のgit statusは人が見ます(第5回)。
弱くしたのはエージェント同士の境界
構成を選ぶことは、弱くする場所を選ぶことでもあります。この構成でいちばんはっきりした代償は、後付けCodex CLIのトークンがSandbox内に保存されることです(第2回)。
これは偶然の不便ではありません。sbxはagentの認証をsandbox specに紐づくものとして扱います。specに載っていないagentは、ホスト側の認証経路に乗れない。 既定から外れた分だけ分離保証が落ちる、という因果です。
同じ理由で、CodexとClaudeのfilesystem・process・credentialは互いに分離されていません。片方が壊した状態は、もう片方から見えます。これは交代を速くした代わりに引き受けたもので、Sandbox内にagent credentialを置けない要件が出たらagent別へ戻します。
残りの弱点は、連載の他の回で触れた性質と同じです。ホストのworking treeとは自動同期しません(第1回)。outboundを全許可しているので、エージェントが到達できる外部の範囲は広いままです(第1回)。credential proxyはHTTP header以外の形式の秘密を隠しません(第4回)。並列させるならworktreeを自分で切る手間も残ります。
戻す条件を書いておく
決定を固定するつもりはありません。次のどれかが主要要件になったら、比較をやり直します。
- CodexとClaudeに完全に独立したcredential/filesystem境界が必要になった
- 独立タスクの恒常的な並列実行が中心になり、単一VM内のworktree管理で足りなくなった
- Docker Sandboxesが複数agentの同居を正式に扱い、host-side OAuthも安全に共有できるようになった
- VirtioFSのnpm互換性が改善し、ホストworking treeの即時共有が隔離より重要になった
書き残す価値があるのは、条件そのものより「どの観測で気が変わるか」を先に決めておける点です。ENOTDIRが出なくなったら1案目を再検討する、交代より並列が増えたら2案目へ戻す。そう決めておけば、次に迷ったときに同じ議論を最初からやり直さずに済みます。
まとめ
第6回の要点です。
- 構成を決めたのは性能でもセキュリティでもなく、交代が多いか並列が多いかという自分の作業パターンだった
- ホストworking treeの共有は、VirtioFS上のnpmが
ENOTDIRで落ちた時点で消えた。SSHでprivate cloneを開ければ共有mountは要件にならない - agent別Sandboxで重かったのは
npm ciの重複より、交代1回ごとに引き継ぎcommitが要ること - 採用形はClaude agent typeの単一永続Sandbox+KitでCodex CLI追加。
ext4のprivate cloneとvirtiofsread-onlyのホストソースで境界を作る - 代償は構造的なもの。specに載らないagentはホスト側の認証経路に乗れず、トークンがSandbox内に残る。要件が変われば既定へ戻す
次回は最終回です。この単一Sandbox構成をOrca ADEの実行ホストとして登録するときに踏んだ、性質の違う3つのエラーを扱います。
連載の構成
- clone modeで作る初期設定
- 1つのSandboxにCodexとClaudeを同居させる
GH_TOKENで権限を絞る- sentinelが見えても注入は成功していない
- Codex AppとClaude Desktopから入る
- Sandboxを1つにした判断(本記事)
- Orca ADEをSandboxへ繋ぐ
参考資料
- Docker Sandboxes overview(Docker公式ドキュメント)
- Docker Sandboxes Kit reference(Docker公式ドキュメント)
- Connect Claude Desktop to Docker Sandboxes(Docker公式ドキュメント)
- Connect ChatGPT to Docker Sandboxes(Docker公式ドキュメント)
本記事はsbx 0.39.0・Node.js 22.12.0・Codex CLI 0.146.0で2026年8月23日に検証した構成の判断記録です。CLIの仕様やagent typeの扱いは更新される可能性があるため、同じ比較をするときは手元のバージョンで再確認してください。
関連記事
Grandream
株式会社グランドリーム
AI・システム開発のプロフェッショナルチームです。AIエージェント・業務自動化・Webシステム開発などを手がけています。



