基于 SimSlim(精简模拟器)和 MobAI 自动化的 iOS 模拟器快速 QA 循环,用于冒烟测试、应用构建和智能体驱动的点击测试。适用于功能后的快速 iOS QA,而非完整回归或大规模多模拟器测试。
安装
npx skillscat add munyon-canyon/monaco/ios-simslim-fast-qa 通过 SkillsCat registry 安装。
基于 SimSlim(精简模拟器)和 MobAI 自动化的 iOS 模拟器快速 QA 循环,用于冒烟测试、应用构建和智能体驱动的点击测试。适用于功能后的快速 iOS QA,而非完整回归或大规模多模拟器测试。
iOS SimSlim Fast QA
Repo-agnostic fast smoke loop: one slim simulator, one MobAI claim, tight iterate cycle.
| Layer | Job | Not its job |
|---|---|---|
| SimSlim | Disable unused sim daemons; verify/doctor | Tap UI, build, screenshot |
| MobAI + mobai-mcp | claim, start_bridge, execute_dsl, install_app | Compile Swift; slim RAM |
| xcodebuild / MobileBuildMCP | Build, install, optional snapshot-ui | Cut sim RAM or manage fleet |
| Agent | discover → profile → build → drive → fix | Stock sim forever; drive another lane's sim |
Default: 1 sim (~0.9 GB slim vs ~4 GB stock). Rare: 2–3 sims (clone gold after slim-once). No 12-sim farm.
When to use
- User asks for fast iOS QA, sim smoke, agent tap-through, SimSlim, or MobAI.
- Day-1 smoke after a feature: launch, primary nav, one critical path — not full regression.
- Unit tests first (no sim). Expand tiers only after smoke is green.
Skip this skill for web automation (not available on iOS sim). Parallel agents in separate worktrees each run this loop on their own lane simulator: scripted taps go through the XCUITest journeys (scripts/qa/journey.py), ad-hoc taps through an MCP that takes a simulator id per call, with the lane UDID from scripts/gold-sim-udid.sh.
Machine setup (once)
SimSlim
brew install mobai-app/tap/simslimMobAI desktop
Run MobAI desktop app. API at 127.0.0.1:8686.
MCP (user or repo .cursor/mcp.json)
{
"mcpServers": {
"mobai": {
"command": "npx",
"args": ["-y", "mobai-mcp"]
}
}
}Add MobileBuildMCP only if the repo already wires it — optional, not required.
Gold simulator (once per machine, slow)
Pick one iOS 18.5+ runtime (slim persist minimum). Boot it, note UDID:
xcrun simctl list devices availableSlim it once with base profile:
simslim on <GOLD_UDID> --profile ci/profiles/base-slim.json --jsonKeep gold booted between agent sessions when possible. For 2–3 sims: clone gold after slim-once (clone inherits slim + apps).
Monaco: UDID is per machine. Never copy a UUID from this repo or another laptop. After slim-once, export SIMSLIM_UDID=<udid> (shell rc and/or plain .env). In the primary checkout scripts/gold-sim-udid.sh prints it or exits 1. In a linked worktree it prints the worktree's own lane simulator, Monaco <lane>, created on first use (docs/how-to/local-simulator.md#parallel-agents-one-simulator-per-worktree). just build mobile / just reset mobile / ./scripts/ios-sim use scripts/resolve-ios-sim.sh (stock fallback in primary). scripts/stop-mobile.sh uninstalls com.monaco.app on the lane's sims in a worktree, and on every sim except live lanes' in the primary checkout. MobileBuildMCP: --simulator-id "$(scripts/gold-sim-udid.sh)". Stock Simulator without slim: README Without slim sim.
Every session before driving UI:
simslim verify <UDID> --profile ci/profiles/<profile>.json \
|| simslim on <UDID> --profile ci/profiles/<profile>.json
simslim doctor --requires ci/profiles/<profile>.jsonexcept in profile = KEEP that daemon category ON (less slim, more capability).
Repo discovery
Run before first build. Works on any Swift/UIKit/SwiftUI app.
| Target | How | Why |
|---|---|---|
| Scheme | xcodebuild -list -json — pick app scheme, not test-only |
Build target |
| Bundle ID | xcodebuild -showBuildSettings -scheme <SCHEME> | grep PRODUCT_BUNDLE_IDENTIFIER or Info.plist |
open_app / install_app |
| Deploy target | IPHONEOS_DEPLOYMENT_TARGET in pbxproj or build settings |
Must fit sim runtime; slim persist needs iOS 18.5+ |
| Entitlements | *.entitlements, Signing & Capabilities in pbxproj |
Profile except/keep map |
| Info.plist | *UsageDescription*, URL schemes, SKAdNetwork |
Photos, camera, location, tracking |
| Backends | README, .env.example, localhost URLs in code |
Start sidecar before UI tier |
xcodebuild -list -json
xcodebuild -scheme <SCHEME> -showBuildSettings 2>/dev/null | grep -E 'PRODUCT_BUNDLE_IDENTIFIER|IPHONEOS_DEPLOYMENT_TARGET'Capability → profile map
Start from base-slim (maximum cut). Add except / keep only for QA paths that touch that subsystem.
Rule: except: ["photos"] means keep the photos category ON.
| Signal in repo | Profile tweak | Category |
|---|---|---|
| SwiftUI tabs only, no system pickers | except: [] |
Full slim |
| PHPicker / Photos / camera | except: ["photos"] |
photos |
| Push notifications QA | keep: ["apsd"] or except: ["push"] |
push |
| StoreKit / IAP | keep: ["storekitd"] |
storekit |
| Universal links / handoff | keep: ["swcd"] |
links |
| HealthKit | except: ["health"] |
health |
| Location / maps | except: ["location"] |
location |
| iCloud / CloudKit | except: ["icloud"] |
icloud |
Example ci/profiles/base-slim.json (keeps siri: slimmed away, the keyboard's dictation handler spins the app's main thread):
{
"except": ["siri"]
}Example ci/profiles/photos-qa.json:
{
"except": ["photos"]
}Re-pick profile when entitlements or smoke scope changes.
Inner loop
discover → profile → verify||on → build → install → claim → start_bridge → drive → report → (fix) → loopChecklist (copy per iteration)
- [ ] Discover scheme, bundle ID, entitlements, deploy target
- [ ] Pick slim profile; verify || on; doctor
- [ ] Build .app
- [ ] Install on claimed sim UDID
- [ ] MobAI: claim → start_bridge → open_app → execute_dsl
- [ ] On fail: save_screenshot + ui_tree; fix code; loop
- [ ] release_device when doneBuild + install (xcodebuild — always available)
xcodebuild -scheme <SCHEME> \
-destination 'platform=iOS Simulator,id=<UDID>' \
-derivedDataPath /tmp/dd-<SCHEME> \
build
xcrun simctl install <UDID> \
/tmp/dd-<SCHEME>/Build/Products/Debug-iphonesimulator/<App>.appBuild + install (MobileBuildMCP — if present)
Use same UDID MobAI will claim. build-and-run, snapshot-ui, screenshot — optional shortcuts, not assumed.
MobAI protocol
Read first: fetch MCP resource mobai://reference/device-automation (and testing docs if driving flows).
| Step | Action |
|---|---|
| Reserve | list_devices → claim_device(holder=<task-id>) |
| Bridge | start_bridge — iOS cold start ~60s; wait for ready |
| Fresh launch | open_app with bundleId, fresh=true |
| Drive | execute_dsl batch or replay mobai/flows/*.mob if repo has them |
| Fail | save_screenshot + ui_tree; debug_attach if crash |
| Done | release_device |
Concurrency: MobAI Free = 1 concurrent device — enough for one agent's loop. Parallel agents in separate worktrees do not share MobAI: each drives its own lane simulator with the XCUITest journeys or an MCP that takes a simulator id per call.
Example DSL sketch (adapt to actual MobAI schema):
{
"steps": [
{ "action": "tap", "label": "Home" },
{ "action": "wait", "ms": 500 },
{ "action": "assert_visible", "label": "Settings" }
]
}Day-1 smoke (not full suite)
Three checks on the one slim sim:
| Check | Pass |
|---|---|
| Launch | App opens, splash dismisses, no crash |
| Primary nav | Tabs / sidebar / root flows reachable |
| One critical path | Single highest-risk user flow end-to-end |
Write or replay flows under mobai/flows/*.mob only when the repo already uses them — do not require per-repo artifacts to run this skill.
Per-repo artifacts (optional)
| Path | Purpose |
|---|---|
ci/profiles/*.json |
Capability-specific slim profiles |
.cursor/mcp.json |
mobai-mcp (+ optional MobileBuildMCP) |
mobai/flows/*.mob |
Replayable smokes for this app |
.cursor/skills/<app>-qa/SKILL.md |
App-specific scheme, bundle, backends, smoke tiers |
Skill is global. Per-repo files speed repeat runs; absence is fine — discover each time.
Gotchas
| Issue | Mitigation |
|---|---|
simslim erase / recreate sim |
Wipes slim; re-run simslim on on gold |
| Runtime below iOS 18.5 | Slim does not persist across reboot |
start_bridge cold |
Budget ~60s before first tap |
| No launch args for test state | Seed data via backend or debug menu; document blocker |
| Missing accessibility ids | Add ids or use label/text taps; fragile |
| PHPicker / system pickers | Use except: ["photos"]; PhotosPicker hard to automate |
| Backend not running | Start sidecar before UI smoke |
| Web automation on iOS sim | Not supported — native MobAI DSL only |
Agent output format
After a smoke pass, report:
## iOS fast QA — <scheme>
- Sim: <name> (<UDID>), profile: <profile>.json
- Build: pass | fail
- Smoke: launch / nav / critical path — pass | fail | blocked
- Blockers: [list or none]
- Screenshot: [MobAI save path or upload if user needs link]On fail: screenshot + ui_tree summary, one concrete fix, then re-loop — do not claim a second sim on Free tier.