写在前面:让我愣了三秒的一幕
上周让Claude帮我测试一款地图App的操作流程,原本打算手动截图喂给AI分析。没想到它反问了一句:"能不能让我自己操作模拟器?"
愣了三秒。接着它真的独立完成了模拟器启动、截图、坐标定位、搜索框点击、中文粘贴、导航至"新庄地铁站"的完整流程,全程无需人工干预模拟器。
这篇文章就是给当初同样困惑的读者准备的:cmux是什么,baguette是什么,以及如何将两者结合让AI Agent自主操作iOS模拟器。
一、先认识两个工具
baguette:模拟器的命令行遥控器
baguette是一款专为iOS模拟器设计的命令行控制工具。
以往操作模拟器,标准流程是打开Xcode → Open Developer Tool → Simulator,弹出一个iPhone窗口,再用鼠标点击。baguette将整套操作封装进CLI环境:
baguette list # 列出所有可用模拟器
baguette boot --udid # 启动指定模拟器,不显示GUI界面
baguette screenshot --udid # 截取当前屏幕
baguette tap --x 72 --y 455 ... # 在指定坐标位置执行点击
baguette describe-ui # 将当前页面导出为JSON格式的无障碍树
baguette type "hello" # 向焦点输入框键入文本(仅支持ASCII)
最值得关注的是这条命令:
baguette serve
# → https://localhost:8421/farm
打开浏览器即可查看所有运行中模拟器的实时推流,也能在网页上直接操作屏幕。在farm界面点击对应设备即可进入单机视图,地址格式如下:
https://localhost:8421/simulators/3AC22B97-2407-4282-BC03-9F0335FA4387
cmux:为AI Agent量身打造的终端环境
iTerm2、Warp、Ghostty是为人类用户设计的终端。cmux则是专门为AI Agent打造的终端工具。
它基于libghostty(Ghostty内核)构建,额外提供了多项实用功能:
- 垂直标签页加分屏:左边Claude Code写代码,中间跑测试,右边监控模拟器,互不干扰
- 监听OSC 9/99/777转义序列实现通知机制,Agent任务完成后能主动提醒你
- 内置可脚本化浏览器,Agent能自主打开网页、点击按钮、填写表单,无需额外安装Playwright
- 自带cmux notify命令,可无缝接入Claude Code的Hook机制
简而言之,cmux就是为AI Agent准备的专属工作台。
二、为什么这俩搭配使用?
将两者拆开对比分析:
| 痛点 | 单独使用 | cmux + baguette |
|---|---|---|
| AI无法看到屏幕内容 | 需要你手动截图喂给AI | screenshot直接输出JPEG图像 |
| AI不知道点击位置 | 需要你手动描述坐标 | describe-ui提供完整的无障碍树 |
| AI操作后无法获取反馈 | 需要你再截一张图确认 | 自动通知 + 自动截图回传 |
| 多任务切换效率低下 | 需要开一堆Terminal窗口 | 垂直标签 + 分屏布局 |
| 中文输入无法使用type | 直接卡死无法继续 | pbcopy + simctl pbsync走系统粘贴板 |
baguette解决的是"视觉感知与操作执行"问题,cmux解决的是"工作环境与任务编排"问题。两者结合就能真正实现自动化操作。
三、3步完成安装配置
Step 1:安装cmux
前往cmux.com下载dmg文件双击安装,也可通过brew快速部署:
brew install --cask cmux
cmux仅支持macOS系统(基于libghostty私有API),Windows环境暂无法使用。
Step 2:安装baguette
baguette使用Swift Package Manager编译,需要Xcode 26 + Apple Silicon芯片(arm64e-apple-macos26.0):
git clone https://github.com/tddworks/baguette
cd baguette
swift build -c release
sudo cp .build/release/baguette /usr/local/bin
baguette --version # 验证安装是否成功
如果仓库README提供了Homebrew tap,也可以直接执行:
brew install tddworks/tap/baguette
Step 3:启动一个模拟器
# 列出所有可用设备
baguette list
# 选择指定UDID启动模拟器(不会弹出GUI窗口)
baguette boot --udid 3AC22B97-2407-4282-BC03-9F0335FA4387
# 验证模拟器运行状态
baguette screenshot --udid -o /tmp/now.jpg && open /tmp/now.jpg
或者直接执行baguette serve,在浏览器中打开https://localhost:8421/farm。在farm界面点击对应设备即可进入单机视图,地址格式如下:
https://localhost:8421/simulators/3AC22B97-2407-4282-BC03-9F0335FA4387
四、实战演示:让Claude自主打开地图App搜索"新庄地铁站"
以下是我真实运行过的命令序列,照搬到cmux中你也能复现完整流程。
1. 获取地图App图标坐标
baguette describe-ui --udid | jq '.. | objects | select(.label == "地图")'
返回结果(节选):
{
"role": "AXButton",
"identifier": "地图",
"frame": { "x": 38, "y": 410, "width": 68, "height": 90.67 }
}
中心点坐标为(72, 455)。
2. 点击打开地图App
baguette tap --udid --x 72 --y 455 --width 440 --height 956
第一个关键点:tap命令必须传入--width和--height参数。这两个参数并非手势宽高,而是整个屏幕的逻辑分辨率。iPhone 16 Pro Max为440 × 956,该数据可从describe-ui输出的顶层AXApplication.frame中获取。
3. 点击搜索框
baguette describe-ui --udid | jq '.. | objects | select(.identifier == "MapsSearchTextField")'
# → frame: { x: 16, y: 869, width: 362, height: 36 }
baguette tap --udid --x 197 --y 887 --width 440 --height 956
4. 输入中文(核心技巧)
baguette type文档明确标注仅支持US-ASCII编码,无法直接输入中文。绕行方案是借助系统粘贴板:
# 1) 将中文字符串写入Mac剪贴板
printf '新庄地铁站' | pbcopy
# 2) 同步到模拟器剪贴板
xcrun simctl pbsync host
# 3) 长按搜索框唤出"粘贴"菜单(duration至少1秒)
baguette tap --udid --x 197 --y 107 --width 440 --height 956 --duration 1.2
# 4) 点击"粘贴"按钮(坐标从describe-ui获取)
baguette tap --udid --x 51 --y 148 --width 440 --height 956
执行完毕后,搜索框中会显示"新庄地铁站",地图自动定位到目标位置。
苹果地图(iOS 18数据源为高德)按关键词进行模糊匹配,南京"新庄"的实际官方站名为"南京林业大学·新庄",是1号线和3号线的交汇站,因此首条命中结果即为目标。整个过程由AI Agent自主完成,无需任何人工干预。
5. 在cmux中实时观察执行过程
打开cmux,垂直分屏布局:
- 左侧面板:Claude Code执行命令
- 右侧面板:浏览器打开
https://localhost:8421/simulators/3AC22B97-2407-4282-BC03-9F0335FA4387,实时观察模拟器画面
长串ID为iPhone 16 Pro Max的UDID,替换为你自己的设备标识即可。Agent每执行一次点击操作,你都能亲眼看到iPhone屏幕上的实时响应。
五、几个进阶玩法
自动化UI测试
将上述步骤封装成一个prompt,让Claude执行回归测试:
帮我测试地图App的搜索功能:
1. 启动地图App
2. 在搜索框输入"新庄地铁站"
3. 截图保存到 /tmp/test_新庄地铁站.jpg
4. 如果搜索结果首条命中"新庄",标记PASS,否则FAIL
需要批量回归时,将第2步替换为关键字数组循环执行即可,复用同一套脚手架。跑完测试后Claude会自动整理每次的截图和PASS/FAIL结果列表,比手动操作稳定得多。
多设备farm并行测试
baguette boot --udid
baguette boot --udid
baguette boot --udid
/farm看板界面同时显示三台设备,AI Agent可以并发对每台设备执行同一套测试用例。适配测试一次性完成,效率大幅提升。
cmux notify闭环通知
在Claude Code的Stop Hook中添加:
cmux notify "模拟器测试跑完啦,赶紧来看"
晚上让Agent自主运行一整晚,第二天早上直接查看通知结果即可。
六、新手会踩的坑
以下都是实际踩过的坑:
baguette tap报"Missing argument --x"错误。参数顺序没有要求,但--width和--height必须传入,查看--help时一眼扫过很容易遗漏。- 中文输入卡死问题。
baguette type不支持中文输入,必须走pbcopy + pbsync + 长按粘贴的绕行方案。 - 长按操作变成了普通点击。
--duration参数至少设为1.0,0.5秒不足以触发iOS的long-press阈值。 - describe-ui抓不到列表项。iOS的UICollectionView有时会懒加载无障碍节点,导致无法获取具体行数据。此时只能根据图像估算坐标(屏幕逻辑大小 / 显示像素 = 比例尺)。
- Xcode版本不匹配。baguette当前要求Xcode 26 + macOS 26 + Apple Silicon芯片,老款Intel Mac无法使用。
写在最后
cmux为AI Agent提供了专属工作台,baguette为AI Agent赋予了操作能力,剩下的"该让它做什么"则是我们自己的职责。
跑完那次"新庄地铁站"的自动化流程后,我的第一反应不是"AI真厉害",而是"我下班是不是更难了"。但换个角度想,重复性的屏幕点击操作本来就不该由人来完成,既然AI Agent能自主执行,何必要自己加班。
成功跑通的读者欢迎在评论区分享你的截图,看看你的Claude在iPhone里探索了哪些功能。
参考资料:
- tddworks/baguette · GitHub
- cmux官网
