Claude模拟器自动化iOS:cmux+baguette实战评测
写在前面:让我愣了三秒的一幕
上周让Claude帮我测一段地图App的行为,本来想自己截图喂给它。结果它反问了一句:"能不能让我自己操作模拟器?"
愣了三秒。然后它真的把模拟器启动、截图、找坐标、点搜索框、粘贴中文、定位"新庄地铁站"全跑完了,从头到尾没碰过模拟器。
这篇就是给当时一样懵的同学准备的:cmux是什么,baguette是什么,怎么把它俩凑一起让Agent自己动手。
一、先认识两个工具
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
# → http://localhost:8421/farm
打开浏览器你能看到所有运行中的模拟器实时推流,也能在网页上戳屏幕。在farm里点对应设备就能进入单机视图,地址格式:
http://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跑完任务能ping你
- 内置可脚本化浏览器,Agent能自己开网页、点按钮、填表单,不用再装Playwright
- 自带cmux notify命令,可以接到Claude Code的Hook里
简单说,cmux是为Agent准备的工位。
二、为什么这俩配?
把它们拆开看:
| 痛点 | 单独使用 | cmux + baguette |
|---|---|---|
| AI看不到屏幕 | 你截图喂给它 | screenshot直出JPEG |
| AI不知道点哪 | 你描述坐标 | describe-ui给完整a11y树 |
| 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,浏览器开http://localhost:8421/farm。在farm里点对应设备就能进入单机视图,地址格式:
http://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. 戳开它
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文档明写only 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号线交汇站,所以首条命中的就是它。整个过程Agent自己跑完,没动过任何东西。
5. cmux里怎么"看戏"
打开cmux,竖着分两屏:
- 左边:Claude Code执行命令
- 右边:浏览器开
http://localhost:8421/simulators/3AC22B97-2407-4282-BC03-9F0335FA4387,实时看模拟器
那个长串是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看板一次显示三台,Agent可以并发对每台跑同一套用例。适配测试一次过。
cmux notify闭环
在Claude Code的Stop Hook里加:
cmux notify "模拟器测试跑完啦,赶紧来看"
晚上让它自己跑一晚,第二天起来直接看通知。
六、新手会踩的坑
这些坑都踩过:
baguette tap报"Missing argument --x"。参数顺序无所谓,但--width--height必传,看--help一眼漏掉是常事。- 中文输入卡死。
baguette type不支持中文,老老实实走pbcopy + pbsync + 长按粘贴。 - 长按变成普通点击。
--duration至少给1.0,0.5不够触发iOS的long-press阈值。 - describe-ui抓不到列表项。iOS的UICollectionView有时懒加载a11y节点,看不到具体行。这种情况只能根据图像估算坐标(屏幕逻辑大小 / 显示像素 = 比例尺)。
- Xcode版本不匹配。baguette当前要求Xcode 26 + macOS 26 + Apple Silicon,老Intel Mac用不了。
写在最后
cmux给Agent一张工位,baguette给Agent一双手,剩下"该让它干嘛"是我们自己的活。
跑完那次"新庄地铁站",第一反应不是"AI真厉害",而是"我下班是不是更难了"。话又说回来,重复点屏幕的活本来就不该人来干,能让Agent自己跑,何必自己加班。
跑通了的同学欢迎评论区贴你的截图,看看你的Claude在iPhone里点了啥。
参考资料:
- tddworks/baguette · GitHub
- cmux官网