pilotty について
pilottyは、エージェントによるターミナルTUI操作のためのコマンドラインツールです。独立したセッション、画面スナップショット、変化検知を使ってアプリを確認・操作できます。
主な機能
- 01PTYセッションでアプリを起動
- 02独立したセッションの管理
- 03テキストと構造化スナップショットの取得
- 04キー、テキスト、クリックの送信
- 05画面の変化や安定を待機
- 06保持されたターミナル出力の読み取り
活用シーン
- 01ターミナルエディターの自動操作
- 02ターミナルのフォームやダイアログ入力
- 03htopなどの画面の確認
- 04ストリーミングAI TUIとの対話
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ msmps/ pilotty --skill pilottyインストール後、Claude Code で/pilottyを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/key-input.mdsession-management.mdtemplates/dialog-interaction.shmulti-session.shvim-workflow.sh詳細
pilotty によるターミナル自動化
重要:引数の順序
すべてのフラグ(--name、-s、--format など)は、位置引数より前に指定する必要があります。
# CORRECT - flags before command/arguments
pilotty spawn --name myapp vim file.txt
pilotty key -s myapp Enter
pilotty snapshot -s myapp --format text
# WRONG - flags after command (they get passed to the app, not pilotty!)
pilotty spawn vim file.txt --name myapp # FAILS: --name goes to vim
pilotty key Enter -s myapp # FAILS: -s goes nowhere useful
エージェントの失敗の原因で最も多いのはこれです。迷った場合は、フラグを先に、その後にコマンド/引数を指定してください。
クイックスタート
pilotty spawn vim file.txt # Start TUI app in managed session
pilotty wait-for "file.txt" # Wait for app to be ready
pilotty snapshot # Get screen text, cursor, and dimensions
pilotty key i # Enter insert mode
pilotty type "Hello, World!" # Type text
pilotty key Escape # Exit insert mode
pilotty kill # End session
基本的なワークフロー
- 起動:
pilotty spawn <command>でアプリをバックグラウンドの PTY で起動します - 待機:
pilotty wait-for <text>でアプリの準備完了を確認します - スナップショット:
pilotty snapshotで現在の画面状態を取得します - 把握:画面のテキストとカーソル位置を確認します
- 操作:キーボードコマンド(
key、type)または座標クリックを使います - 再スナップショット:
content_hashを確認して、画面の変化を把握します
コマンド
セッション管理
pilotty spawn <command> # Start TUI app (e.g., pilotty spawn htop)
pilotty spawn --name myapp <cmd> # Start with custom session name (--name before command)
pilotty kill # Kill default session
pilotty kill -s myapp # Kill specific session
pilotty list-sessions # List all active sessions
pilotty daemon # Manually start daemon (usually auto-starts)
pilotty stop # Stop daemon and all sessions
pilotty examples # Show end-to-end workflow example
画面キャプチャ
pilotty snapshot # Full JSON with text content and hash
pilotty snapshot --format compact # JSON without text field
pilotty snapshot --format text # Plain text with cursor indicator
pilotty snapshot -s myapp # Snapshot specific session
# Wait for screen to change (eliminates need for sleep!)
HASH=$(pilotty snapshot | jq '.content_hash')
pilotty key Enter
pilotty snapshot --await-change $HASH # Block until screen changes
pilotty snapshot --await-change $HASH --settle 50 # Wait for 50ms stability
pilotty snapshot --settle 50 --strict # Exit nonzero on deadline/exit
保持された出力
pilotty output # Readable rendered output history
pilotty output -s myapp # Readable history for a named session
pilotty output -s myapp --ansi # Exact retained ANSI/VT bytes
表示範囲から外れたコンテンツを確認するには、読みやすい形式の出力を使用してください。再生や診断で正確なターミナルバイト列が必要な場合にのみ、--ansi を使用してください。
入力
pilotty type "hello" # Type text at cursor
pilotty type -s myapp "text" # Type in specific session
pilotty key Enter # Press Enter
pilotty key Ctrl+C # Send interrupt
pilotty key Escape # Send Escape
pilotty key Tab # Send Tab
pilotty key F1 # Function key
pilotty key Alt+F # Alt combination
pilotty key Up # Arrow key
pilotty key -s myapp Ctrl+S # Key in specific session
# Key sequences (space-separated, sent in order)
pilotty key "Ctrl+X m" # Emacs chord: Ctrl+X then m
pilotty key "Escape : w q Enter" # vim :wq sequence
pilotty key "a b c" --delay 50 # Send a, b, c with 50ms delay
pilotty key -s myapp "Tab Tab Enter" # Sequence in specific session
操作
pilotty click 5 10 # Click at row 5, col 10
pilotty click -s myapp 10 20 # Click in specific session
pilotty scroll up # Scroll up 1 line
pilotty scroll down 5 # Scroll down 5 lines
pilotty scroll up 10 -s myapp # Scroll in specific session
ターミナル制御
pilotty resize 120 40 # Resize terminal to 120 cols x 40 rows
pilotty resize 80 24 -s myapp # Resize specific session
pilotty wait-for "Ready" # Wait for text to appear (30s default)
pilotty wait-for "Error" -r # Wait for regex pattern
pilotty wait-for "Done" -t 5000 # Wait with 5s timeout
pilotty wait-for "~" -s editor # Wait in specific session
グローバルオプション
| オプション | 説明 |
|---|---|
-s, --session <name> | 対象のセッションを指定します(デフォルト:"default") |
--format <fmt> | スナップショット形式:full、compact、text |
-t, --timeout <ms> | wait-for と await-change のタイムアウト(デフォルト:30000) |
-r, --regex | wait-for のパターンを正規表現として扱います |
--name <name> | spawn コマンドのセッション名 |
--delay <ms> | シーケンス内のキー入力間の遅延(デフォルト:0、最大:10000) |
--await-change <hash> | content_hash が変わるまでスナップショットを待機します |
--settle <ms> | 画面が安定するまで、このミリ秒数だけ待機します(デフォルト:0) |
--strict | キャプチャ期限に達した場合は 3、セッションが終了した場合は 4 で終了します |
--ansi | output から保持された ANSI/VT バイト列を正確に書き出します |
環境変数
PILOTTY_SESSION="mysession" # Default session name
PILOTTY_SOCKET_DIR="/tmp/pilotty" # Override socket directory
RUST_LOG="debug" # Enable debug logging
スナップショット出力
snapshot コマンドは、現在の画面を説明する構造化 JSON を返します。
{
"outcome": "immediate",
"size": { "cols": 80, "rows": 24 },
"cursor": { "row": 5, "col": 10, "visible": true },
"text": "Settings:\n [x] Notifications [ ] Dark mode\n [Save] [Cancel]",
"content_hash": 12345678901234567890
}
カーソル位置を示すプレーンテキスト表示には、--format text を使用してください。
--- Terminal 80x24 | Cursor: (5, 10) ---
bash-3.2$ [_]
[_] はカーソル位置を示します。テキストの内容から画面の状態を把握し、キーボードコマンドで操作してください。
画面の変化を待機する(推奨)
待機時間を推測するのはやめましょう! --await-change を使用して、画面が実際に更新されるまで待機してください。
# Capture baseline hash
HASH=$(pilotty snapshot | jq '.content_hash')
# Perform action
pilotty key Enter
# Wait for screen to change (blocks until hash differs)
pilotty snapshot --await-change $HASH
# Or wait for screen to stabilize (for apps that render progressively)
pilotty snapshot --await-change $HASH --settle 100
フラグ:
| フラグ | 説明 |
|---|---|
--await-change <HASH> | content_hash がこの値と異なるまで待機します |
--settle <MS> | 変化を検出した後、画面が MS ミリ秒間安定するまで待機します |
-t, --timeout <MS> | 最大待機時間(デフォルト:30000) |
--strict | 証拠を保持したまま、deadline または exited の場合はゼロ以外の終了コードで終了します |
各スナップショットには、返された理由が報告されます。
| 結果 | 意味 | エージェントの動作 |
|---|---|---|
immediate | 待機は要求されていません | 現在の画面を確認します |
changed | --await-change の条件が満たされました | 新しい画面を確認します |
settled | 要求された安定時間が経過しました | 画面が安定したものとして扱います |
deadline | 時間切れです。最新の証拠が含まれています | 証拠を確認し、有用であれば待機時間を延ばして再試行します |
exited | セッションが終了しました。最終的な証拠が含まれています | これ以上入力を送らず、終了メタデータまたは出力を確認します |
期限切れと終了の結果でも、デフォルトでは終了コード 0 で終了します。シェルの制御フローでこれらの結果を失敗として扱う場合にのみ、--strict を追加してください。
sleep より優れている理由:
sleep 1は推測です。短すぎると競合状態が発生し、長すぎると自動化が遅くなります--await-changeは必要な時間だけ正確に待機します。長すぎることも短すぎることもありません--settleは段階的に描画されるアプリ(一部を表示してから全体を表示するアプリ)に対応します
ストリーミング AI 応答を待つ
応答をストリーミングする AI 搭載 TUI(opencode など)とやり取りする場合、トークンが届くたびに画面が更新されるため、より長い --settle 時間が必要です。
# 1. Capture hash before sending prompt
HASH=$(pilotty snapshot -s myapp | jq -r '.content_hash')
# 2. Type prompt and submit
pilotty type -s myapp "write me a poem about ai agents"
pilotty key -s myapp Enter
# 3. Wait for streaming response to complete
# - Use longer settle (2-3s) since AI apps pause between chunks
# - Extend timeout for long responses (60s+)
pilotty snapshot -s myapp --await-change "$HASH" --settle 3000 -t 60000
# 4. Response may be scrolled - scroll up if needed to see full output
pilotty scroll -s myapp up 10
pilotty snapshot -s myapp --format text
ストリーミングで重要なパラメーター:
--settle 2000-3000:AI の応答ではチャンク間に間が空くため、2〜3 秒に設定するとストリーミングが確実に完了します-t 60000:生成に時間がかかる場合に備えて、デフォルトの 30 秒より長くタイムアウトを設定します--settleタイマーは画面が更新されるたびにリセットされるため、ストリーミングが止まるまで自然に待機します
手動で変更を検出する
手動でポーリングする場合(推奨されません)は、content_hash を直接使用します。
# Get initial state
SNAP1=$(pilotty snapshot)
HASH1=$(echo "$SNAP1" | jq -r '.content_hash')
# Perform action
pilotty key Tab
# Check if screen changed
SNAP2=$(pilotty snapshot)
HASH2=$(echo "$SNAP2" | jq -r '.content_hash')
if [ "$HASH1" != "$HASH2" ]; then
echo "Screen changed - inspect the new text"
fi
ナビゲーション方法
pilotty は、人間と同じようにキーボード優先でナビゲーションします。
# 1. Take snapshot to see the screen
pilotty snapshot --format text
# 2. Navigate using keyboard
pilotty key Tab # Move to the next control
pilotty key Enter # Activate/select
pilotty key Escape # Cancel/back
pilotty key Up # Move up in list/menu
pilotty key Space # Toggle checkbox
# 3. Type text when needed
pilotty type "search term"
pilotty key Enter
# 4. Click at coordinates for mouse-enabled TUIs
pilotty click 5 10 # Click at row 5, col 10
重要なポイント:スナップショットのテキストを読んで画面の内容を把握してから、キーボードコマンドで操作します。
例:vim でファイルを編集する
# 1. Spawn vim
pilotty spawn --name editor vim /tmp/hello.txt
# 2. Wait for vim to load and capture baseline hash
pilotty wait-for -s editor "hello.txt"
HASH=$(pilotty snapshot -s editor | jq '.content_hash')
# 3. Enter insert mode
pilotty key -s editor i
# 4. Type content
pilotty type -s editor "Hello from pilotty!"
# 5. Wait for screen to update, then exit (no sleep needed!)
pilotty snapshot -s editor --await-change $HASH --settle 50
pilotty key -s editor "Escape : w q Enter"
# 6. Verify session ended
pilotty list-sessions
個別のキーを使用する別の方法:
pilotty key -s editor Escape
pilotty type -s editor ":wq"
pilotty key -s editor Enter
例:ダイアログのチェックリストを操作する
# 1. Spawn dialog checklist (--name before command)
pilotty spawn --name opts dialog --checklist "Select features:" 12 50 4 \
"notifications" "Push notifications" on \
"darkmode" "Dark mode theme" off \
"autosave" "Auto-save documents" on \
"telemetry" "Usage analytics" off
# 2. Wait for dialog to render (use await-change, not sleep!)
pilotty snapshot -s opts --settle 200 # Wait for initial render to stabilize
# 3. Inspect the screen and capture its hash
SNAP=$(pilotty snapshot -s opts)
echo "$SNAP" | jq -r '.text'
HASH=$(echo "$SNAP" | jq '.content_hash')
# 4. Navigate to "darkmode" and toggle it
pilotty key -s opts Down # Move to second option
pilotty key -s opts Space # Toggle it on
# 5. Wait for change and inspect the updated screen
pilotty snapshot -s opts --await-change $HASH | jq -r '.text'
# 6. Confirm selection
pilotty key -s opts Enter
# 7. Clean up
pilotty kill -s opts
例:フォームに入力する
# 1. Spawn a form application
pilotty spawn --name form my-form-app
# 2. Get snapshot to understand the visible form
pilotty snapshot -s form --format text
# 3. Tab to first input (likely already focused)
pilotty type -s form "myusername"
# 4. Tab to password field
pilotty key -s form Tab
pilotty type -s form "mypassword"
# 5. Tab to remember me and toggle
pilotty key -s form Tab
pilotty key -s form Space
# 6. Tab to Login and activate
pilotty key -s form Tab
pilotty key -s form Enter
# 7. Check result
pilotty snapshot -s form --format text
例:htop を監視する
# 1. Spawn htop
pilotty spawn --name monitor htop
# 2. Wait for display
pilotty wait-for -s monitor "CPU"
# 3. Take snapshot to see current state
pilotty snapshot -s monitor --format text
# 4. Send commands
pilotty key -s monitor F9 # Kill menu
pilotty key -s monitor q # Quit
# 5. Kill session
pilotty kill -s monitor
例:AI TUI(opencode など)を操作する
AI 搭載 TUI は応答をストリーミングするため、特別な対応が必要です。
# 1. Spawn the AI app
pilotty spawn --name ai opencode
# 2. Wait for the prompt to be ready
pilotty wait-for -s ai "Ask anything" -t 15000
# 3. Capture baseline hash
HASH=$(pilotty snapshot -s ai | jq -r '.content_hash')
# 4. Type prompt and submit
pilotty type -s ai "explain the architecture of this codebase"
pilotty key -s ai Enter
# 5. Wait for streaming response to complete
# - settle=3000: Wait 3s of no changes to ensure streaming is done
# - timeout=60000: Allow up to 60s for long responses
pilotty snapshot -s ai --await-change "$HASH" --settle 3000 -t 60000 --format text
# 6. If response is long and scrolled, scroll up to see full output
pilotty scroll -s ai up 20
pilotty snapshot -s ai --format text
# 7. Clean up
pilotty kill -s ai
AI アプリを使用する際の注意点:
- AI の応答ではチャンク間に間が空くため、
--settle 2000-3000を使用します - 複雑なプロンプトには、
-t 60000でタイムアウトを延長します - 長い応答では端末がスクロールする場合があります。冒頭を確認するには
scroll upを使用します --settleタイマーは画面が更新されるたびにリセットされるため、実際に完了するまで待機します
セッション
各セッションは、以下を備えた独立した環境です。
- PTY(擬似端末)
- 画面バッファー
- 子プロセス
# Run multiple apps (--name must come before the command)
pilotty spawn --name monitoring htop
pilotty spawn --name editor vim file.txt
# Target specific session
pilotty snapshot -s monitoring
pilotty key -s editor Ctrl+S
# List all
pilotty list-sessions
# Kill specific
pilotty kill -s editor
--name を指定せずに最初に起動したセッションには、自動的に default という名前が付けられます。
重要:
--nameフラグはコマンドの前に指定する必要があります。コマンドの後に続くものは、すべてそのコマンドの引数として渡されます。
デーモンアーキテクチャ
pilotty はセッション管理にバックグラウンドデーモンを使用します。
- 自動起動:最初のコマンドでデーモンが起動します
- 自動停止:セッションがない状態が 5 分続くと終了します
- 終了後の記録:終了したセッションのステータス、最終画面、上限付きの出力は、最大 10 分間保持されます
- 状態の共有:複数の CLI 呼び出しでセッションを共有します
デーモンを手動で管理する必要はほとんどありません。
エラー処理
エラーには、実行可能な提案が含まれます。
| 終了コード | カテゴリー | エージェントの対応 |
|---|---|---|
0 | コマンド完了 | スナップショットの outcome を確認します。--strict を指定していない場合、deadline または exited の可能性があります |
1 | 一般/API エラー | エラーコード、メッセージ、提案を確認します |
2 | 使用方法のエラー | コマンドの構文を修正します |
3 | 厳密なキャプチャの期限超過 | 出力された記録を確認し、適切であれば時間を延長して再試行します |
4 | セッションのライフサイクル終了 | そのセッションへの入力を再試行せず、status、snapshot、または output を使用します |
{
"code": "SESSION_NOT_FOUND",
"message": "Session 'abc123' not found",
"suggestion": "Run 'pilotty list-sessions' to see available sessions"
}
{
"code": "SPAWN_FAILED",
"message": "Failed to spawn process: command not found",
"suggestion": "Check that the command exists and is in PATH"
}
よくあるパターン
信頼性の高い操作と待機(推奨)
# The pattern: capture hash, act, await change
HASH=$(pilotty snapshot | jq '.content_hash')
pilotty key Enter
pilotty snapshot --await-change $HASH --settle 50
# This replaces fragile patterns like:
# pilotty key Enter && sleep 1 && pilotty snapshot # BAD: guessing
待ってから操作する
pilotty spawn my-app
pilotty wait-for "Ready" # Ensure app is ready
pilotty snapshot # Then snapshot
操作前に状態を確認する
pilotty snapshot --format text | grep "Error" # Check for errors
pilotty key Enter # Then proceed
タイムアウト時に再試行する
pilotty wait-for "Ready" -t 5000 || {
pilotty snapshot --format text # Check what's on screen
# Adjust approach based on actual state
}
詳細ドキュメント
詳しいパターンやエッジケースについては、以下を参照してください。
| リファレンス | 説明 |
|---|---|
| references/session-management.md | 複数セッションのパターン、分離、クリーンアップ |
| references/key-input.md | キーの組み合わせに関する完全なリファレンス |
すぐに使えるテンプレート
実行可能なワークフロースクリプト:
| テンプレート | 説明 |
|---|---|
| templates/vim-workflow.sh | vim でファイルを編集し、保存して終了する |
| templates/dialog-interaction.sh | ダイアログ/whiptail のプロンプトを処理する |
| templates/multi-session.sh | TUI を並行してオーケストレーションする |
使用方法:
./templates/vim-workflow.sh /tmp/myfile.txt "File content here"
./templates/dialog-interaction.sh
./templates/multi-session.sh