sim-use について
sim-useは、sim-useコマンドラインでモバイルシミュレーターを操作するエージェントスキルです。物理iOSデバイスにも限定的に対応し、観察・操作・確認の手順とデバイスごとの制約を重視します。
主な機能
- 01UIアウトラインによる画面の確認
- 02セレクターを使った要素のタップ
- 03テキスト入力、貼り付け、ジェスチャー、スクロール
- 04UIまたはスクリーンショットで操作を確認
- 05既知のiOS操作手順を一括実行
活用シーン
- 01モバイルシミュレーターでスクリプト操作を実行
- 02アプリの画面状態を確認・テスト
- 03入力欄にUnicodeや複数行テキストを入力
- 04シミュレーター操作の視覚的な記録を取得
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ lycorp-jp/ sim-use --skill sim-useインストール後、Claude Code で/sim-useを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/batch-reference.mdcheatsheet.mdcrash-awareness.mdpitfalls.mdscripts/preflight.py詳細
0. 事前チェック
デバイスを初めて操作する前に、事前チェックを実行してください。
python3 scripts/preflight.py --device <UDID>
このチェックでは、sim-use がインストールされておりスキルと互換性があること、デバイスに接続できること、デーモンが正常に動作していることを確認します。スクリプトがない場合は、手動で確認してください。
sim-use --version— sim-use が PATH 上にあり、スキルで説明されているコマンドに対応していることを確認します。sim-use devices— 対象のデバイスが一覧にあり、起動済み/接続済みであることを確認します。sim-use ui --device <UDID>— 画面を読み取れることを確認します。
WARN UI content の行が表示されても、事前チェックは成功です。読み取りは機能していますが、アウトラインにアプリのコントロールが表示されない場合があります。落とし穴の索引を参照してください。
起動中のシミュレーターが1台のみの場合、または実行中のデーモンが1つのみの場合、--device は省略できます。Android では、ブリッジ APK をインストールするために、sim-use android init --device <serial> を一度実行してください。接続した実機の iPhone/iPad は、sim-use devices に種類 physical として表示され、最上位の動詞経由でも操作できます。ただし、利用できるのは ui、セレクターを使った tap、screenshot のみです。それ以外の動詞は、そのデバイスを対象にすると拒否されます。実機を操作する前に、以下の物理 iOS デバイスを参照してください。sim-use の Linux ビルドで操作できるのは Android のみです。sim-use ios …、record-video/stream-video、viewer、init は利用できず、すべての動詞で --device <serial> が必要です。また、sim-use devices には Android デバイスのみが表示されます。
1. 観察と操作のループ
すべての操作は同じサイクルに従います。観察 → 操作 → 確認。
観察
sim-use ui --device <UDID>
アウトラインを読み取ります。各要素には @N エイリアスがあり、場合によっては #<id> 識別子もあります。リストのセルには、#N(優先リスト)または #N@M(スコープ指定)が付与されます。
JSON 出力(--json:entries[].frame、screen)のフレームは、プラットフォーム固有の単位で示されます。iOS はポイント、Android はピクセルです。プラットフォーム間で座標を計算する前に、必ずエンベロープの platform フィールドを確認してください。必ず --json と --no-raw を組み合わせてください。以下の出力を小さく保つを参照してください。
操作
次の優先順位でセレクターを選びます。
| セレクター | 使用する状況 |
|---|---|
tap @N | ui の実行直後に使用します。最速で、キャッシュを利用します。 |
tap #<id> | 軽微なレイアウト変更があっても安定します。アウトラインから貼り付けてください。 |
tap --label 'X' | スクリプト化されたフローに使用します。画面遷移には --wait-timeout を組み合わせます。 |
tap --label-regex '...' | カウンターやタイムスタンプを含む動的なラベルに使用します。^...$ でアンカーを指定します。 |
tap --label-contains 'X' | 正確なラベルがわからない場合に、部分文字列で一致させます。 |
tap -x N -y N / tap --point x,y | AX データのない要素に対する最後の手段です。アウトラインに表示される数値を、向きやディスプレイを問わず使用できます。--coordinate-space native は、デバイスネイティブの縦向きポイントを指定する場合に使用します。 |
候補が重複する場合は、--element-type または --frame minY=0.7r で区別してください(references/cheatsheet.md を参照)。
確認
コマンドは実行結果を待たずに返るため、操作の後は必ず確認してください。
sim-use ui --device <UDID> # read the new screen state
sim-use screenshot --device <UDID> --output after.png
出力を小さく保つ
読み取るコマンド出力のすべてのバイトが、コンテキストを消費します。ループのコストを抑えるためのデフォルト設定:
--jsonよりもデフォルトのテキスト概要を優先してください。この概要には、タップに必要な情報がすべて含まれています(@N/#<id>エイリアス、ロール、フレーム、状態)。座標計算用の構造化フィールド(entries[].frame、screen)や、省略されていない全文(概要ではラベルは60書記素、value=は30文字で切り詰められます)が必要な場合に--jsonを使ってください。--jsonを使う場合は、--no-rawを追加してください。data.rawは生のアクセシビリティツリーで、通常は出力全体のバイト数の大部分を占めます。sim-use 自体のデバッグ以外にはほとんど役立ちません。- 各アクションにつき
uiは1回だけ実行してください。手順Nの確認読み取りは、手順N+1の観察読み取りとして使えます。その間に2回目のuiを実行しないでください。 - スクリーンショットではなく、テキスト概要で確認してください。スクリーンショットの読み取りには、一般的な概要より数倍多くのコストがかかります。色、画像、レイアウトなど、視覚的な確認が本当に必要な場合にのみ撮影してください。
- iOS で画面遷移が終わるのを待つには、
uiをループで再実行するより、tap --label 'X' --wait-timeout 3(要素が表示されるまでポーリング)を優先してください。Android のtapには--wait-timeoutがありません。代わりに、コマンド間にsleepを使ってください。 - iOS で既知の複数手順のシーケンスを実行する場合は、
sim-use ios batchを使ってください(references/batch-reference.mdを参照)。1回の呼び出しで、出力も1回です。
よく使う操作
| タスク | コマンド |
|---|---|
| 下にスクロール | sim-use gesture scroll-up --device <UDID>(scroll-up = コンテンツが上に移動 = ページを下にスクロール) |
| テキストを入力 | sim-use type 'hello' --device <UDID> |
| Unicode を貼り付け | フィールドにフォーカスしてから、sim-use paste 'こんにちは 🎉' --device <UDID> を実行します。iOS では、キーボードモードを問わず Simulator.app または Device Hub で動作します |
| ハードウェアボタン | sim-use button home --device <UDID> |
| Android の戻る操作 | sim-use button back --device <UDID> |
| アニメーションを待つ | コマンド間に sleep 0.4 を実行するか、--pre-delay 0.5 を指定します |
| トグル/スイッチ | sim-use tap @N --duration 0.05 --device <UDID>(UISwitch には短い押下が必要です) |
| スワイプ | sim-use swipe --from 50,500 --to 350,500 --device <UDID> |
| ピンチして拡大 | sim-use gesture pinch-out --device <UDID>(2本の指を広げます) |
| 回転(2本指ジェスチャー) | sim-use gesture rotate-cw --angle 90 --device <UDID> |
| デバイスを回転(iOS) | sim-use ios rotate landscape-left --device <UDID> — インターフェース名は App: ヘッダーに表示されるとおりです。実行後に ui を再実行してください |
| 折りたたむ/開く(iPhone Duo) | sim-use ios fold closed|open --device <UDID>。sim-use ios fold --device <UDID> は、どちらのディスプレイがアクティブかを報告します。実行後に ui を再実行してください |
| 証跡 GIF を記録 | sim-use record-video --output demo.gif --device <UDID> — SIGINT/SIGTERM で停止してください(SIGKILL は絶対に使わないでください)。停止後にトランスコードされ、PR でインライン再生されます。ループの開始/終了を示すカードを追加するには --gif-markers を指定します |
iOS シミュレーターへの貼り付け
Unicode と IME に安全なテキストには、paste を使用してください。デフォルトでは、フォーカス中のフィールドのキャレットと選択範囲が保持されます。--replace を指定すると、先にすべて選択します。ターゲットを明示的にフォーカスするには、--via-menu --target-id <id> または --target-x/--target-y を使用してください。どちらの方法もネイティブの「ペースト」アクションを使用するため、ハードウェアキーボードや同期設定を変更する必要はありません。
複数行のテキストやシェルで特別な扱いが必要なテキストには、printf '%s' "$TEXT" | sim-use paste --stdin --device <UDID> または paste --file <path> を使用してください。1 行への正規化やスマートペーストによるスペース挿入など、コントロールのネイティブなルールは引き続き適用されます。「すべてを選択」が利用できず、アクセシビリティを通じてフィールドが空であることも確認できない場合、--replace は「ペースト」の前に失敗します。この拒否を置換成功として扱わないでください。メニューの出所が不明または曖昧な場合も拒否されます。同じラベルのアプリボタンをタップして、その拒否を回避しないでください。必ず実際のフィールドを確認してください。コマンドから「ペーストが送信された可能性がある」と報告された場合は、再試行する前にフィールドを確認してください。「ペースト」が自動的に再送信されることはありません。
共有クリップボードの同期によって、Mac やほかのデバイスのクリップボードが上書きされることもあります。クリップボードを書き込むプロセスは 1 つだけにしてください。sim-use は独自のペースト操作を直列化し、予期しない読み戻しを確認しますが、外部からの書き込みは防げません。無関係なクリップボードデータを出力したり、新しい外部コンテンツの上に古いバックアップを復元したりしないでください。
バッチ貼り付けでは、デフォルト、置換、ファイル、明示的なメニューターゲットを使用できます。paste --stdin は標準入力をバッチが使用するため、バッチのステップにはできません。一時的な起動準備エラーが発生しても、失敗したバッチが自動的に再実行されることはありません。--continue-on-error を使用した場合も含め、再試行する前に UI と完了済みのステップを確認してください。
物理 iOS デバイス(実験的)
トップレベルの動詞は物理デバイスの UDID を自動的にルーティングしますが、対象は ui、tap(#<id>/--id/--label/--label-contains/--element-type 形式)、screenshot の 3 つだけです。シミュレーターと同等の機能があると決して想定しないでください。その他の動詞や形式(座標、@N/#N エイリアス、スワイプ/ジェスチャー/マルチタッチ、入力/貼り付け、録画、--value/--label-regex/--frame/--duration/--wait-timeout)はすべて、理由と最も近い代替手段を hint に示して拒否されます。再試行するのではなく、hint を確認してください。sim-use ios-device 名前空間は、ios/android に対応する物理デバイス専用の機能で、同じ動詞に加えて ECID による指定とツリー調整用フラグを使用できます。
**ui/tap の厳格な要件:**デバイスがペアリング済みで、信頼され、ロック解除され、デベロッパモードになっている必要があります。また、フォアグラウンドの対象アプリは get-task-allow=true で開発用署名されている必要があります。Development プロファイルでインストールされた Release 構成のバイナリはサポートされています。Distribution/Ad Hoc、TestFlight、App Store、システムアプリはサポート対象外です。これらを再試行したり、成功したと主張したりしないでください。sim-use 自体はランナーをインストールも署名もしません。また、Developer Disk Image も必要ありません。screenshot は署名要件の対象外です。CoreDevice 経由で実行されるため、システムアプリを含むあらゆる画面をキャプチャできます。
# Physical-device preflight — physical rows carry kind `physical`
sim-use devices
# Observe → act → verify, same loop and verbs as the simulator
sim-use ui --device <UDID>
sim-use tap --label "Friends" --element-type Button --device <UDID>
sim-use ui --device <UDID>
# For dynamic labels
sim-use tap --label-contains "Reply" --element-type Button --device <UDID>
# By stable identifier (the #id shown in ui) — positional or --id
sim-use tap '#BackButton' --device <UDID>
# Screenshot — any screen, not limited to development-signed apps
sim-use screenshot --output shot.png --device <UDID>
この実験的な機能を使用する際のルール:
- **階層エラーは機能上の制約として扱います。**コマンドで階層を利用できないと表示された場合は、画面のロックが解除されていることを確認し、インストール済みアプリの最終的な
get-task-allowエンタイトルメントを確認してください。座標やフォーカス移動に切り替えないでください。 - **
@Nではなく、#idまたはラベルでタップします。**要素ハンドルは DTX 接続が切れると無効になるため、@Nエイリアスはありません(座標もありません。ジオメトリがないためです)。アウトラインに表示された#id(位置指定の#<id>または--id)を使用してください。この ID は安定しており、ラベルが動的な場合に最適です。または、--element-typeで対象を絞り込みながら、--label/--label-containsを使用してください。ナビゲーションバーの戻るボタンは、通常のButton "<previous screen title>" #BackButtonとして表示されます。他の要素と同じように#BackButton(または表示されたラベル)をタップして戻ってください。特別な「戻る」動詞はありません。 - **必ず検証します。**Activate は実行後の完了を待たずに返ります。続行する前に
sim-use uiを再実行し、期待した状態になっていることを確認してください。 - 機能上の制約による拒否に従います。
not supported on physical iOS devicesエラーは、一時的な失敗ではなく、その経路がサポート対象外であることを示します。再試行したり、似た形式に置き換えたりするのではなく、ヒント(通常はuiとtap '#<id>' / --label)に従ってください。--jsonはすべての動詞で標準の{ok, data}エンベロープとともに使用できます。物理デバイスの結果には"kind":"physical"が含まれ、ジオメトリフィールド(screen、x/y)は省略されます。 - **ミリ秒ではなく秒単位で見積もります。**ツリー全体の取得には数秒かかります。
sim-use ios-device ui --fastはより高速ですが、ネストされた要素は省略されます。短い間隔でポーリングしないでください。
ui が要素数 0 で成功した場合や、存在しない/曖昧なラベルに対して tap が成功を表示した場合は、sim-use のバグとして扱ってください。コマンドは明確にエラーを返すことが期待されています。
2. 落とし穴
症状のクイックインデックス — 詳しい手順は references/pitfalls.md を参照してください。
| 症状 | 原因 | 対処方法 |
|---|---|---|
tap --label で別の要素がタップされる | ラベルの衝突(例:ヘッダーとタブバーで同じテキストを使用) | --frame minY=0.7r または --element-type を追加して絞り込みます |
画面遷移後に tap @N が失敗する | エイリアスキャッシュが古くなっています | タップする前に ui を再実行します |
App: 行に誤ったアプリが表示される | システムレイヤー(アラート、共有シート)が前面にあります | まず閉じてから、ui を再実行します |
multipleMatches エラー | 複数の要素がセレクターに一致しています | --frame、--element-type、またはより具体的なセレクターを使用します |
| タップはできるが何も起きない | アニメーション中、または要素がまだ操作可能ではありません | --pre-delay 0.3 または --wait-timeout 3 を追加します |
iOS:paste が失敗する、またはテキストが入力されない | フィールドにフォーカスがない、カスタム編集メニュー、貼り付けプロンプト、または外部クリップボードライターが原因です | フィールドにフォーカスするか、paste --via-menu --target-id <id> を使用します。プロンプトを確認し、実際のフィールドを検証してください。Unicode の代替手段として type に切り替えないでください |
Android:paste が拒否される | バックグラウンドからのクリップボードアクセスがブロックされています | 代わりに type を使用します |
アウトラインのラベルに U+FFFC が表示される | iOS のアイコンプレースホルダー文字です | 接頭辞を除外する --label-regex で一致させます |
[i] … covers ~N% of the screen 警告(テキスト出力、または --json のトップレベル advisory キー) | セレクターがほぼ全画面を覆うラッパー(Flutter/キャンバス UI でよく見られます)に解決され、タップがその中央に当たったため、意図したコントロールを外した可能性があります | ui を再実行し、@N/#<id> でコントロールを指定するか、明示的な -x/-y/--point を渡します |
[i] Screen orientation could not be confirmed…/…coordinates may be stale… アドバイザリー | デバイス/アプリが回転していて(App: ヘッダーに (landscape-right) のようなタグが表示されます)、向きの自動キャリブレーションで座標の対応関係を検証できなかったか、@N のスナップショットが回転前のものです | ui を再実行して、もう一度タップします。キャリブレーションが成功すれば、セレクターは回転に自動対応します。明示的な -x/-y/--point はアウトライン(視覚空間)の座標を受け取り、同じキャリブレーションを使用します。--coordinate-space native はデバイスネイティブの縦向き座標用です |
アウトラインが空、または表示中のアプリコントロールが含まれていない。または [i] … recovered from other processes … アドバイザリー(--json:advisory.kind: remote_content_recovery) | アプリが空のアクセシビリティツリーを公開しました。システムピッカーでは正常です。それ以外の場合、iOS シミュレーターでは、アプリの起動時にアプリのアクセシビリティがオフだったことが原因として考えられます | アウトラインと画面を比較します。コントロールが欠けている場合は、アプリコントロールが見つからない場合を参照してください |
iOS:すべての画面で ui が No translation object returned for simulator <UDID> for the frontmost application を出して失敗するが、screenshot と ui --point は動作する | シミュレーターのアクセシビリティブリッジ(CoreSimulatorBridge)が古くなっています | エラーのヒントに従って、xcrun simctl spawn <UDID> launchctl stop com.apple.CoreSimulator.bridge を実行します(launchd がすぐに再起動します)。その後、ui を再試行します。起動直後の場合は、まず数秒待ってから再試行してください |
iOS:ui ヘッダーが inner display、cover display(古いビルドでは内側画面に display LCD-1)、または display Resizable 560x874 で終わる | アプリが名前の示す Duo 画面、または Xcode 27 Resize Mode のディスプレイ上にあります。内側画面がアクティブでも、ヒンジが完全に開いているとは限りません。--json は未加工の名前を保持します。メイン画面/カバー画面では data.display はありません。Touch、ui、ui --point、screenshot、record-video/stream-video(h264、bgra)は自動的にルーティングされます | 通常どおり操作してください。セレクターと @N はそのディスプレイ上で操作します。iOS 27.1 SDK アプリの縦型バー(戻るボタン、タブ)は末尾に [Trailing …]/[Leading …] として表示されます。明示的な -x/-y には ui が表示する数値を使用します。--coordinate-space native はそのディスプレイのネイティブ座標を意味します。iPhone Duo と Resize Mode を参照してください |
3. クラッシュの検知
プロトコルの詳細については、references/crash-awareness.mdを参照してください。概要:
sim-useは、コマンドの実行中に対象プロセスが終了していないか監視します。クラッシュを検知した場合:
================ PROCESS DISAPPEARED ================
com.example.app (pid 12345) was alive at the previous command and is GONE now.
Androidでは、uiがアクセシビリティツリーからAOSPのシステムクラッシュダイアログも直接検知します。
必須の対応:
- 停止します。 気付かれないまま再起動したり、処理を続けたりしないでください。
- バナーのテキストを添えて、クラッシュをユーザーに報告します。
- 続行する前に、指示を待ちます。
意図的に再起動した後は、sim-use app-state --resetを呼び出してシグナルをクリアします。
4. エスカレーション
次の場合は停止してユーザーに確認してください。
- 利用可能な識別情報ではセレクターの衝突を解決できない。
- プリフライトに失敗し、自動修復でも復旧しない。
- タスクで破壊的な操作(データの削除、アプリのアンインストール)が必要となる。
- 同じ操作を3回再試行しても進展がない。
5. 終了チェックリスト
タスクの完了を報告する前に:
sim-use ui(またはscreenshot)を実行して、最終状態を取得します。- 画面が意図した結果と一致していることを確認します。
- 結果が曖昧な場合は、最終的な
uiの出力またはスクリーンショットをユーザーに提示します。