关于 pilotty
pilotty 是用于 Agent 自动化终端 TUI 的命令行工具。它通过独立会话、屏幕快照和等待界面变化来检查并操作终端应用。
主要功能
- 01在 PTY 会话中启动应用
- 02管理多个隔离会话
- 03获取文本及结构化屏幕快照
- 04发送按键、文本和点击
- 05等待屏幕变化或稳定
- 06读取保留的终端输出
适用场景
- 01自动操作终端编辑器
- 02填写终端表单或对话框
- 03检查 htop 等终端界面
- 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
这是导致 Agent 失败的头号原因。如有疑问,请记住:先写标志,再写命令/参数。
快速开始
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 时以非零状态退出 |
每个快照都会报告返回原因:
| 结果 | 含义 | Agent 操作 |
|---|---|---|
immediate | 未请求等待 | 读取当前屏幕 |
changed | 已满足 --await-change 条件 | 继续查看新屏幕 |
settled | 已满足请求的稳定时间窗口 | 将屏幕视为稳定 |
deadline | 时间已到;已包含最新证据 | 检查证据;如有需要,可增加等待时间后重试 |
exited | 会话已结束;已包含最终证据 | 不要再发送输入;检查退出元数据或输出 |
默认情况下,deadline 和 exited 结果仍以退出码 0 结束。只有当 shell 控制流需要因这些结果而失败时,才添加 --strict。
为什么这比 sleep 更好:
sleep 1只是猜测:时间太短会导致竞态,太长则会拖慢自动化--await-change会按需精确等待,不多也不少--settle适用于渐进式渲染的应用(先显示部分内容,再显示完整内容)
等待流式 AI 响应
与会流式输出响应的 AI 驱动型 TUI(如 opencode 等)交互时,需要设置更长的 --settle 时间,因为屏幕会随着 token 到达而持续更新:
# 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:将超时时间延长到默认的 30s 以上,以适应更长的生成过程- 每次屏幕变化都会重置等待计时器,因此它会自然地等待流式输出停止
手动检测变化
如需手动轮询(不推荐),请直接使用 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 应用的注意事项:
- 使用
--settle 2000-3000,因为 AI 响应的各个片段之间会有停顿 - 对于复杂提示词,使用
-t 60000延长超时时间 - 较长的响应可能会滚动终端内容;使用
scroll up查看开头 - 每次屏幕更新都会重置等待计时器,因此它会等待响应真正完成
会话
每个会话都彼此隔离,并拥有自己的:
- 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 调用共享会话
你很少需要手动管理守护进程。
错误处理
错误信息会包含可执行的建议:
| 退出码 | 类别 | Agent 操作 |
|---|---|---|
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 | 处理 dialog/whiptail 提示 |
| templates/multi-session.sh | 并行编排 TUI |
用法:
./templates/vim-workflow.sh /tmp/myfile.txt "File content here"
./templates/dialog-interaction.sh
./templates/multi-session.sh