一台 Mac,一个终端,一只 AI。模拟器从此不用你戳。
写在前面:让我愣了三秒的一幕
上周我让 Claude 帮我测一段地图 App 的行为,本来想自己截图喂给它。结果它问了我一句:
"你这边 baguette 装了吗?我自己跑就行。"
我愣了三秒。然后它真的把模拟器启动、截图、找坐标、点搜索框、粘贴中文、定位"新庄地铁站"全跑完了,从头到尾我没碰过模拟器。
这篇就是给当时和我一样懵的同学:cmux 是什么,baguette 是什么,怎么把它俩凑一起让 Agent 自己动手。
一、先认识两个工具
baguette:模拟器的命令行遥控器
baguette 是 iOS 模拟器的命令行控制工具。
平时玩模拟器,要打开 Xcode → Open Developer Tool → Simulator,弹出一个 iPhone 窗口,再用鼠标戳。
baguette 把这一整套塞进了 CLI:
bash
baguette list # 列出所有模拟器
baguette boot --udid <UDID> # 启动模拟器,不弹 GUI
baguette screenshot --udid <UDID> # 拍一张屏幕
baguette tap --x 72 --y 455 ... # 在指定坐标戳一下
baguette describe-ui # 把当前页面变成 JSON 树
baguette type "hello" # 往焦点输入框打字(仅 ASCII)
最有意思的是这条:
bash
baguette serve
# → http://localhost:8421/farm

打开浏览器你能看到所有运行中的模拟器实时推流,也能在网页上戳屏幕。
在 farm 里点对应设备就能进入单机视图,地址格式:
bash
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:
bash
brew install --cask cmux
cmux 只支持 macOS(基于 libghostty 私有 API),Windows 用不了。
Step 2:装 baguette
baguette 用 Swift Package Manager 编译,需要 Xcode 26 + Apple Silicon(arm64e-apple-macos26.0):
bash
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,也可以直接:
bash
brew install tddworks/tap/baguette
Step 3:启一个模拟器
bash
# 列设备
baguette list
# 选一个 UDID 启起来(不会弹 GUI)
baguette boot --udid 3AC22B97-2407-4282-BC03-9F0335FA4387
# 看一眼
baguette screenshot --udid <UDID> -o /tmp/now.jpg && open /tmp/now.jpg
或者直接 baguette serve,浏览器开 http://localhost:8421/farm。
在 farm 里点对应设备就能进入单机视图,地址格式:
bash
http://localhost:8421/simulators/3AC22B97-2407-4282-BC03-9F0335FA4387
四、实战:让 Claude 自己打开地图 App 搜"新庄地铁站"
下面是我真实跑过的命令序列,照样输到 cmux 里你也能复现。
1. 找地图 App 图标坐标
bash
baguette describe-ui --udid <UDID> | jq '.. | objects | select(.label == "地图")'
返回(节选):
json
{
"role": "AXButton",
"identifier": "地图",
"frame": { "x": 38, "y": 410, "width": 68, "height": 90.67 }
}
中心点 (72, 455)。
2. 戳开它
bash
baguette tap --udid <UDID> --x 72 --y 455 --width 440 --height 956
第一坑:tap 必须传 --width --height。这俩不是手势宽高,是整个屏幕的逻辑宽高。iPhone 16 Pro Max 是 440 × 956,从 describe-ui 顶层 AXApplication.frame 拿。
3. 点搜索框
bash
baguette describe-ui --udid <UDID> | jq '.. | objects | select(.identifier == "MapsSearchTextField")'
# → frame: { x: 16, y: 869, width: 362, height: 36 }
baguette tap --udid <UDID> --x 197 --y 887 --width 440 --height 956
4. 输入中文(关键技巧)
baguette type 文档明写 only US-ASCII,中文打不进去。绕法是走系统粘贴板:
bash
# 1) 把中文塞到 Mac 剪贴板
printf '新庄地铁站' | pbcopy
# 2) 同步到模拟器剪贴板
xcrun simctl pbsync host <UDID>
# 3) 长按搜索框唤出"粘贴"菜单(duration 至少 1 秒)
baguette tap --udid <UDID> --x 197 --y 107 --width 440 --height 956 --duration 1.2
# 4) 点"粘贴"按钮(坐标从 describe-ui 拿)
baguette tap --udid <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 跑回归:
text
帮我测试地图 App 的搜索功能:
1. 启动地图 App
2. 在搜索框输入"新庄地铁站"
3. 截图保存到 /tmp/test_新庄地铁站.jpg
4. 如果搜索结果首条命中"新庄",标记 PASS,否则 FAIL
要批量回归,第 2 步换成关键字数组循环跑就是了,同一套脚手架。
跑完 Claude 会把每次的截图和 PASS/FAIL 列给你,比你自己手点稳得多。
多设备 farm 并行
bash
baguette boot --udid <iPhone-16-UDID>
baguette boot --udid <iPad-Pro-UDID>
baguette boot --udid <iPhone-Air-UDID>
/farm 看板一次显示三台,Agent 可以并发对每台跑同一套用例。适配测试一次过。
cmux notify 闭环
在 Claude Code 的 Stop Hook 里加:
bash
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 里点了啥。
参考资料: