本文へスキップ

iOS アプリ開発で AI エージェントをチーム展開するための隔離と配布の設計

📋 目次

背景

Claude Code のようなエージェントに Xcode のビルドやシミュレータ操作、git のコミットまで任せられるようになりました。 手元の1台で使う分には便利ですが、任せる作業が増えるほど誤った操作やプロンプトインジェクションでホスト環境そのものを壊すリスクも大きくなります。 チーム全員のマシンでこれを個別に対策するのは現実的ではありません。 そこで、仕事で使える現実的な内容として ios-dev-sandbox という仕組みを考えてみました。 iOS 開発用のエージェント環境を隔離し、チーム全員に同じ設定を配布します。 中身は kusumotoa/ios-dev-sandbox-sample で公開しています。

この記事では、その仕組みの大枠を解説します。

Xcode に依存する以上、閉じ込めきれない

エージェントの隔離には Docker Sandboxes(sbx)という microVM 基盤を使い、ファイルシステムとネットワークを絞っています。

ただし Xcode は macOS 専用の GUI アプリケーションで、iOS シミュレータも macOS 上でしか動きません。 Linux の microVM に閉じ込めるほど、ビルドもシミュレータの起動もできなくなります。 そこで ios-dev-sandbox は隔離自体を sbx に任せます。 引き受けるのは、Linux VM の中に存在し得ないもの(Xcode や macOS 専用の CLI)への橋渡しと、チーム標準の設定・スキルの配布だけです。

ホストへの橋を1本の口に絞る

橋渡しの実体は host-bridge という HTTP サーバーで、ホストの 127.0.0.1 で待ち受けます。 サンドボックス内のエージェントは host.docker.internal:19721 という決まったポートにリクエストを送るだけです。

http://host.docker.internal:19721/mcp/xcode   → mcpbridge → Xcode
http://host.docker.internal:19721/mcp/<名前>  → Figma・npx などの他の MCP サーバー
http://host.docker.internal:19721/exec        → macOS 専用 CLI を実行

橋が1本なので、何を通すかも1箇所で決められます。 エージェントがホストのコマンドを呼んでから実際に動くまでに、3 つの関門があります。

サンドボックスからホストの CLI が実行されるまでに通る 3 つの関門

3 つ目が引数の先頭しか見ないのには理由があります。 tool --api-url status logs と書けば、許可した status を装って logs を実行させられるからです。

GitHub の書き込みと読み取りを PAT 2 本で分ける

git push や gh にも同じ発想の境界が要ります。 Fine-grained PAT の権限は選んだリポジトリ全体に一律なので、1本では「このリポジトリは書ける、あのリポジトリは読むだけ」を作業対象ごとに使い分けられません。 そこで書き込み用と読み取り専用の2本を用意し、gh のラッパーが対象リポジトリを見てどちらを送るか決めます。

作成時に PAT のスコープを引いて gh を振り分ける図

チームに配るための3層構造

チーム全員に同じ設定を配ろうとすると、個人のマシン固有の設定とチーム全体で揃えるべき設定を混ぜるわけにはいきません。 ios-dev-sandbox では設定を3層に分けています。

share・local・secrets の3層構造

local/ は gitignore されていても、git add -f や誤ったバックアップで漏れる余地が残ります。 トークン類だけリポジトリの外に置いているのはそのためです。

share/ にある設定はサンドボックスの境界そのものなので、レビューなしに変わってはいけません。 org のリポジトリとして配るなら、管理者にも例外を認めない設定で main へのブランチ保護を掛けておくことを勧めています。

state: サンドボックスは使い捨て、状態は外に逃がす

サンドボックスは設定を変えるたびに作り直します。 作り直しても消えてはいけないものが会話履歴・インストール済みのプラグイン・成果物です。

サンドボックスは使い捨て、状態はホスト側の外部ディレクトリに残る図

会話履歴を bind しておけば前回の続きから話せますし、プラグインの再ダウンロードも起きません。

エージェントの種類を選べるようにする

チームのメンバーが全員同じエージェントを使うとは限りません。 IOS_DEV_SANDBOX_AGENT という環境変数で Claude Code、Codex、Copilot CLI を切り替えられます。

cd ~/projects/my-ios-app
ios-dev-sandbox                                  # claude
IOS_DEV_SANDBOX_AGENT=codex ios-dev-sandbox      # codex
IOS_DEV_SANDBOX_AGENT=copilot ios-dev-sandbox    # copilot

同じプロジェクトでもエージェントごとに別のサンドボックスが立ち、設定や会話履歴も分かれます。 host-bridge を1本に絞ってあるおかげで、隔離や allowlist の仕組みは重複させずに済みます。 エージェントごとに書き分けるのは、MCP の登録先と指示ファイルの置き場所だけです。

まとめ

隔離自体は Docker Sandboxes に任せ、ios-dev-sandbox は4つに絞りました。 Xcode への橋渡し、GitHub の PAT 分離、share・local・secrets の3層による設定配布、会話履歴と成果物の永続化です。 同じ課題に直面している方は参考にしてもらえればと思います。

参考リンク

この記事をシェア