serve-sim について
serve-sim は、serve-sim CLI で Apple Simulator を操作するエージェント向けスキルです。シミュレーター制御、映像配信、カメラ入力、権限管理、アクセシビリティの手順を扱います。
主な機能
- 01シミュレーターのタップ、スワイプ、ドラッグ、回転
- 02ブラウザーへのシミュレーター映像配信
- 03ファイルやカメラ映像の注入
- 04アプリ権限とデバッグオーバーレイの管理
- 05アクセシビリティツリーの取得とメモリ警告の再現
活用シーン
- 01起動中のシミュレーターアプリの操作自動化
- 02レビュー用シミュレーター映像の共有
- 03カメラを使うアプリ動作のテスト
- 04アクセシブルなUI要素と権限の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ expo/ serve-sim --skill serve-simインストール後、Claude Code で/serve-simを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.mdevals/evals.jsonreferences/buttons-rotation.mdca-debug.mdcamera.mdendpoints.mdgestures.mdpermissions.mdworkflows.mdscripts/check-prereqs.shensure-running.sh詳細
serve-sim
serve-sim CLI を使用して、エージェントから Apple Simulator(iOS、iPad、Apple Watch)を操作します。serve-sim は、プロセス内ネイティブアドオンを通じてシミュレーターの IOSurfaces をキャプチャし、HTTP または WebRTC による動画と WebSocket による入力を提供するとともに、React プレビュー UI を配信します。このスキルでは、エージェント向けに正確な CLI の仕様、ジェスチャー JSON の形式、注意点、推奨ワークフローを説明します。
使用する場面
- ユーザーが、実行中の Apple Simulator でエージェントにタップ、スワイプ、ドラッグ、ピンチ、またはハードウェアボタンの送信をさせたい場合。
- ユーザーが、レビューやリモート操作のために、シミュレーターをブラウザーにストリーミングしたい場合(ローカル、LAN、またはトンネル経由)。
- ユーザーが、特定のシミュレーターアプリに合成カメラフィード(ファイル、ウェブカメラ、またはアニメーションするプレースホルダー)を注入したい場合。
- ユーザーが、パフォーマンス関連の作業で CoreAnimation のデバッグオーバーレイ(オフスクリーンレンダリング、ブレンドされたレイヤー、スロウアニメーション)を切り替えたい場合。
- ユーザーが、プログラムからメモリ警告をシミュレートしたり、デバイスを回転させたりしたい場合。
- ユーザーが、ピクセルを探し回らずに UI 要素を見つけるため、シミュレーターのアクセシビリティツリーを読み取りたい場合。
- ユーザーが、アプリのプライバシー権限(カメラ、写真、位置情報、連絡先、またはプッシュ通知)を許可、取り消し、またはリセットしたい場合。
使用しない場面
- Android エミュレーター →
adb shellツールを使用してください。 - iOS アプリのビルドまたはインストール →
xcodebuildまたはxcrun simctl installを使用してください。 - React Native アプリ内ランタイムのデバッグ(Redux の状態、ネットワークの調査、コンポーネントツリー) → rn-debugger ツールを使用してください。
- 実機の iOS デバイス →
xcrun devicectlまたは Xcode を使用してください。
前提条件
ほかの操作を行う前に、ホストがこれらの要件を満たしていることを確認してください。不足しているものがあれば、インストールするものをユーザーに正確に伝え、先へ進まないでください。
| 要件 | 確認コマンド | 理由 |
|---|---|---|
| macOS ホスト | uname -s が Darwin を返す | serve-sim は macOS でのみ実行できます |
| Apple シリコン | uname -m が arm64 を返す | 同梱されているネイティブコンポーネントは arm64 のみを対象としています |
| Xcode CLI ツール | xcrun --version が終了コード 0 を返す | simctl はシミュレーターを制御する基盤です |
| Node.js ≥20 | node --version が ≥20 | serve-sim はメンテナンス対象の Node.js LTS リリースをサポートしています |
| macOS 14 以降(任意) | sw_vers -productVersion が ≥14 | camera サブコマンドでのみ必要です |
同梱のヘルパースクリプトを利用できます:scripts/check-prereqs.sh。実行し、終了コードが 0 以外の場合は、表示されたメッセージをユーザーに伝えてください。
ほとんどのサブコマンドでは、起動済みのシミュレーターが必要です。xcrun simctl list devices booted で確認してください。起動済みのものがない場合は、Xcode → Simulator を開くか、xcrun simctl boot <UDID> を実行するようユーザーに伝えてください。
基本的な仕組み
┌───────────────┐ IOSurface ┌────────────────────┐ HTTP/WebRTC ┌─────────┐
│ iOS Simulator │ ──────────► │ serve-sim process │ ────────────► │ Browser │
└───────────────┘ │ + native N-API │ WebSocket └─────────┘
└────────────────────┘
▲
state files in
$TMPDIR/serve-sim/
エージェントが守るべき重要な不変条件:
- すべての座標は 0..1 に正規化されており、ディスプレイの左上が
(0, 0)、右下が(1, 1)です。ピクセル座標は絶対に渡さないでください。 - デバイスごとに登録できるサーバーは 1 つです。サーバープロセスは複数のシミュレーターをキャプチャできます。また、キャプチャ API 自体は排他的ではありません。
- 状態は
$TMPDIR/serve-sim/server-{udid}.jsonに保存されます。状態の確認にはserve-sim --listを使用してください。直接 JSON を読み取るのは、内容を理解している場合に限ります。 rotateで設定した向きはヘルパーに記憶され、その後のジェスチャーではクライアント側で回転処理が行われます。回転後に生の座標を送信するエージェントが、手動で補正する必要はありません。
一般的な操作
| 目的 | コマンド | メモ |
|---|---|---|
| プレビューサーバーを起動する | npx @expo/serve-sim [device] | デフォルトのプレビューは http://localhost:3200 です。ヘルパールートは同一オリジンです。フォアグラウンドプロセスです。 |
| WebRTC プレビューを起動する | npx @expo/serve-sim --transport webrtc [device] | WebRTC メディアと、入力用の順序付きヘルパー WebSocket を使用します。 |
| ヘッドレス/デーモンとして起動する | npx @expo/serve-sim --detach [device] | pid、port、url を含む JSON を返します。エージェントのループで使用します。 |
| ホストのプレビューにストリームを表示する | npx @expo/serve-sim --detach -q → url をホストのプレビューツールに渡す | 「エージェントのプレビューにストリームを表示する」セクションを参照してください。 |
| 実行中のストリームを一覧表示する | npx @expo/serve-sim --list | JSON のみを出力するには -q を追加します。 |
| すべてのヘルパーを停止する | npx @expo/serve-sim --kill | 特定のものを停止するには [device] を渡します。 |
| シングルタップ | npx @expo/serve-sim tap <x> <y> | <x> <y> は 0..1 の範囲です。通常のタップには gesture ではなく、こちらを使用してください。 下記の「重要な注意点」を参照してください。 |
| 複数ステップのジェスチャー | npx @expo/serve-sim gesture '<json>' | references/gestures.md を参照してください。 |
| ハードウェアボタン | npx @expo/serve-sim button <name> | 名前:home、swipe_home、app_switcher、lock、siri、side_button。references/buttons-rotation.md を参照してください。 |
| デバイスを回転する | npx @expo/serve-sim rotate <orientation> | portrait、portrait_upside_down、landscape_left、landscape_right。 |
| メモリ警告をシミュレートする | npx @expo/serve-sim memory-warning | 「デバッグ」→「メモリ警告をシミュレート」と同等です。 |
| CoreAnimation のデバッグ | npx @expo/serve-sim ca-debug <option> <on|off> | オプション:blended、copies、misaligned、offscreen、slow-animations。references/ca-debug.md を参照してください。 |
| カメラ映像を注入する | npx @expo/serve-sim camera <bundle-id> [--file <path>|--webcam [name]] | カメラの dylib をアタッチして、アプリを(再)起動します。macOS 14 以降のみ対応です。references/camera.md を参照してください。 |
| カメラソースをホットスワップする | npx @expo/serve-sim camera switch <placeholder|webcam|file> [arg] | アプリの再起動は不要です。 |
| アプリの権限を管理する | npx @expo/serve-sim permissions <grant|revoke|reset|list> <permission> <bundle-id> | カメラ、写真、位置情報、プッシュ通知、連絡先など。references/permissions.md を参照してください。 |
| アクセシビリティツリーを読み取る | streamUrl のヘルパーベース URL から /ax を導出する | axe 形式の JSON を返します。references/endpoints.md を参照してください。 |
複数のデバイスが起動している場合、ほとんどのサブコマンドでは特定のデバイスを対象にするための -d <udid|name> を指定できます。
重要な注意点:タップには gesture より tap を優先してください
serve-sim gesture を呼び出すたびに、専用の WebSocket が開かれます。{"type":"begin",...} を指定した gesture 呼び出しと、{"type":"end",...} を指定した呼び出しを連続して 2 回実行すると、その間に十分な遅延が生じてシミュレーターではタッチがタップではなく長押しとして解釈されます。これはプロトコル上の意図的な制約であり、回避すべきバグではありません。
ルール:単発のタップには、必ず serve-sim tap <x> <y> を使用してください。gesture は、ドラッグ、スワイプ、または begin → move × N → end の間で同じソケットを維持する必要がある複数ステップの操作にのみ使用してください。
特定のデバイスを対象にする
複数のシミュレーターが起動している場合、すべてのサブコマンドで -d <udid|name> を指定できます。名前の照合では、大文字と小文字を区別せず、xcrun simctl list devices booted が返すデバイス名と比較します。例:
npx @expo/serve-sim tap 0.5 0.5 -d "iPhone 16 Pro"
npx @expo/serve-sim button home -d ABC12345-...
npx @expo/serve-sim --list # show all running streams
起動中のシミュレーターが 1 台だけの場合は、-d を省略してください。このスキルでは、デバイス名を固定値にするよりも自動検出を優先してください。
出力モード
デフォルトでは、serve-sim は人が読みやすいステータスを stdout に出力します。エージェントのループでは、JSON 出力を優先してください。
npx @expo/serve-sim --list -q # JSON object; one stream is top-level, many are under .streams
npx @expo/serve-sim --detach -q # JSON with pid/port/url after spawn
npx @expo/serve-sim camera status -q # JSON with {alive, source, mirror, ...}
-q の出力はプログラムで解析してください。-q を付けていない、人向けの出力は解析しないでください。バージョンによって変更される場合があります。
エージェントのプレビューにストリームを表示する
ユーザーが「ここでシミュレーターを見せて」「プレビューで表示して」「このツールで開いて」などと依頼した場合、シミュレーターをユーザーがチャットしているのと同じ画面にストリーミングすることが目的です。serve-sim は通常の HTTP URL を返します。エージェントはその URL を提示し、ホストにプレビューツールがある場合は、そのツールに渡します。
手順:
-
serve-sim を起動して URL を取得します:
npx @expo/serve-sim --detach -q{"pid":..., "port":3100, "url":"http://localhost:3100", "streamUrl":"http://localhost:3100/helper/<udid>/stream.mjpeg", ...}のような JSON が返されます。urlフィールドは人間が表示するプレビュー UI、streamUrlは生の MJPEG エンドポイントです。 -
ユーザーがどのブラウザーからでも手動で開けるように、応答では必ず URL をそのまま表示します。
-
ホストのプレビューツールを確認し、利用可能なものがあれば URL を渡します。ツールセットで見つかる可能性のあるツール名の例:
preview_start(Claude Code)—{ url: "<url>" }を渡して呼び出します。mcp__Claude_Preview__preview_start(一部の MCP セットアップ)。browser_open、open_urlなどの URL を開くツール — URL を渡します。- Cursor/Codex CLI などでは、エージェントが使えるプレビューツールがない場合があります。その場合は URL を表示し、ユーザーに開き方(ブラウザー、IDE の組み込みブラウザーペインなど)を案内します。
-
特定のプレビューツールがあると決めつけないでください。 現在のセッションで利用可能なツールを確認します。上記の説明に当てはまるツールがあれば使用します。なければ手順 2 に従い、URL を目立つように表示します。
ストリームは npx @expo/serve-sim --kill を実行するまで動作し続けます。複数のクライアント(ホストのプレビュー、ユーザーのブラウザー、トンネル)は同じ URL を同時に読み込めます。
完全な手順については、references/workflows.md のワークフロー「ホストのプレビューにシミュレーターストリームを表示する」を参照してください。
ワークフロー
UI 自動化、カメラテスト、アクセシビリティを利用したタップ、ディープリンクのフロー、プレビューへの引き継ぎなど、エンドツーエンドの手順については references/workflows.md を参照してください。このリファレンスでは、serve-sim 自身の AGENTS.md に記載されているパターンを説明しています。
クリーンアップ
ユーザーが明示的に起動し続けることを希望している場合を除き、完了したら必ずヘルパーを停止してください:
npx @expo/serve-sim --kill # stop all
npx @expo/serve-sim --kill "iPhone 16 Pro" # stop one
孤立したサーバーは記録済みのポートを占有し、新たな起動を妨げます。
避けるべきパターン
- ピクセル座標を渡さないでください。 座標はすべて
0..1に正規化されています。ユーザーからピクセル値を指定された場合は、GET /configで報告された画面サイズで割ってください。 - 単純なタップに
gestureを使わないでください。tapを使用してください。上記の「重要な注意点」を参照してください。 npx @expo/serve-simがすでに実行中だと決めつけないでください。--listを使うか、$TMPDIR/serve-sim/server-{udid}.jsonを確認してください。見つからない場合は、明示的に起動してください。- セッション中の初回実行時に、前提条件の確認を省略しないでください。 macOS のバージョン違い、Xcode CLI ツールの不足、または Node <20 は、後続でわかりにくいエラーの原因になります。
- ボタン名を作り出さないでください。 有効な名前は次の 6 つだけです:
home、swipe_home、app_switcher、lock、siri、side_button。正確な一覧については references/buttons-rotation.md を参照してください。 - quiet ではない人間向けの出力を解析しないでください。 JSON には
-qを使用してください。 - 無関係なタスクの間、カメラヘルパーを起動したままにしないでください。 完了したら
npx @expo/serve-sim camera --stop-webcamで停止してください。 - アクセシビリティ検索で一致する結果が返されなかった場合、座標を推測しないでください。 対象要素を見つけるために AX ツリー(例:
GET /ax)を取得し、クエリで結果が返されなかった場合は、明確にエラーを報告してください。位置を推測してタップするより、ユーザーに「対象が見つかりません」と報告するほうが、ほとんどの場合適切です。ガードパターンについては references/workflows.md のワークフロー 1 を参照してください。
リファレンス一覧
- references/gestures.md — 正確なジェスチャー JSON の形式、境界値、マルチタッチ、ドラッグ/スワイプの手順。
- references/buttons-rotation.md — 有効な 6 つのボタンと 4 つの向き、および動作に関する注意事項。
- references/camera.md — 合成カメラ入力:プレースホルダー、ファイル、ウェブカメラ、ミラーモード、ホットスワップ。
- references/permissions.md — プッシュ通知を含む、アプリのプライバシー権限の付与/取り消し。
- references/ca-debug.md — 5 つの CoreAnimation デバッグフラグと、それぞれが役立つ場面。
- references/endpoints.md — CLI を介さないエージェント向けの HTTP および WebSocket エンドポイント。
- references/workflows.md — UI オートメーション、カメラテスト、ディープリンクのワークフローに関する一連の手順。