.mobster/test-results/<suite-id>/, that stands on its own: upload it as a CI artifact and every link in it works. Reports stay in your project folder unless you share them with your team.
Find the files a run writes
A safety stop is a JUnit error even when its check is quarantined. A stopped or other nonzero suite with no failing check gets a
Suite verdict error, so CI doesn’t report it as passed.
--junit FILE and --html DIR also write the JUnit file and the HTML report (with runs/ and videos/) where your CI expects them. --json prints results.json on stdout.
Read the HTML report
Openindex.html in the folder that mobster test prints. It starts with the checks that didn’t pass, then lists every check’s file, tags and verdict on each device. --spread groups the checks by device.
Open a failed check to see its expectations, what was found instead, the verdict frame, and its Logs and Crash pane. The report links to each run’s report, log and video, then lists flaky checks. Every link stays inside the folder except Mobster in the footer, which opens mobster.dev.
Read JUnit results
junit.xml has one <testsuite> per device and one <testcase classname="checks.<file>"> per check:
<failure>has typeassertion,app_crashedorneeds_review.<error type="couldnt_run">marks a check that couldn’t run.<skipped>marks quarantine.- Each check has the properties
status,attempts,flaky,passRateandreport. When measured, it also hasperf.launchMs,perf.memoryMbandperf.hangs. - Each suite has
git.branchandgit.headwhen you run in a git checkout. - A crash’s top frames appear in
<failure>. The app’s log around the failure appears in<system-out>.
Read results.json
Read logs, crashes and video
For every run on a simulator or a USB iPhone, Mobster keeps the app’s log and, when the app crashed, its crash report. With--video it also records the screen.
- A crash fails the check as
failed, classapp_crashed, even when the expectations held. Mobster knows the app crashed the moment SpringBoard logs that its process ended on a signal (SIGSEGV,SIGABRT,SIGTRAP), the watchdog (0x8badf00d) or jetsam. Relaunches that Mobster starts don’t count. - The log is the app’s unified log (
os_log,Logger,NSLog) from before the launch to the verdict. On a simulator Mobster reads it withxcrun simctl spawn <udid> log stream, at the info level and above. On an iPhone it reads the syslog withidevicesyslog. Each line carries the run clock, in seconds since the run started. What your app prints to stdout withprintisn’t in it. - The log around a failure in
results.jsonmarks each lineapp: truewhen it’s the app’s own (its process, not an Apple framework). Mobster for Mac shows those lines first and folds the rest behind Show system log. - The video is a simulator’s screen through
xcrun simctl io recordVideo, or an iPhone’s through WebDriverAgent’s video stream, encoded on the Mac to an H.264 MP4 590 pixels wide. Nothing on the phone changes. Mobster doesn’t store a frame that repeats the one before, so a still screen costs nothing. - The crash report comes from
~/Library/Logs/DiagnosticReportsfor a simulator, and from the iPhone withidevicecrashreport --keep, which copies it and leaves it on the phone. Mobster names your app’s frames withatosand the dSYM beside the check’s.appor in.mobster/build/Build/Products. A Debug build already carries its names.
index.html shows the same pane under the expectations and links to the full log and the .ips, and junit.xml carries the crash in <failure type="app_crashed"> and the log window in <system-out>. In Mobster for Mac, each project’s page shows its runs by branch and the same pane beside each failed check’s steps, with Run checks to run them all again and Run again under the failed checks to run only those that didn’t pass.
results.json gives each result that didn’t pass an evidence object. Proof for every step adds the slices for each step.
macOS writes a simulator’s crash report some time after the crash, so
mobster test waits up to 60 seconds once, at the end of the suite, for the reports it’s missing. A report that comes later stays in ~/Library/Logs/DiagnosticReports, and the check still says it crashed and on which signal.
Each log line and every string in a crash report goes through the secret filter before it’s written: passwords, one-time codes, card numbers and API keys become ••••. They stay in the run folder on this Mac, and Mobster sends them nowhere. Over MCP, the result your coding agent reads (verify_finish, run_tests) carries evidence as data. The log stops at 1 MB, then keeps its last 2,000 lines and says how many it dropped.
On an iPhone over Wi-Fi, the log and crash reports need libimobiledevice to reach the phone on the network. When it can’t, the result’s note says there’s no log. A check on a WebDriverAgent address gets no log or crash report, because Mobster can’t tell which phone it is.
Export a suite
From the project folder, name the finished suite:show prints the suite verdict and evidence count. --json gives opaque check and device IDs, statuses and evidence hashes, with no check names, device names, paths, app text or pixels. export writes that descriptor to a new local folder and uploads nothing. Both need the suite’s evidence-inventory.json and an unchanged results.json, and refuse a suite without them.
To copy raw evidence, pick each kind:
--output names a new folder. If a selected file is missing or changed, export refuses before it creates the folder. Logs, crash reports and videos stay in the suite folder and are never copied into a capsule.
Compare two suites
observedTransition apart from verifiedFix. It needs each suite’s inventory and an unchanged results.json. verifiedFix is true only when clean, single-attempt simulator runs show an app-state field (Fixtures) fail on one build and pass on another, while the check, fixture, environment and policy stay the same. An input Mobster couldn’t pin (What a suite pins) never counts toward a verified fix.
Shrink a failing check
When a comparison verified a fix,mobster test minimize looks for the fewest steps that still fail on the bad build and pass on the good one. Keep both simulator .app builds in the project, then run:
--isolated says you isolated any outside state for every trial: Mobster resets the app as the check requires, but it can’t reset your backend. It first reruns the original pair. It keeps a step’s removal only when the bad build fails the same assertion twice and the control build passes once between them. An unknown outcome stops without a retry. It runs at most 8 suites, the original pair included (--max-attempts N takes 5 to 8).
.mobster/drafts/repro/<pair-and-refs>/result.json, with candidate.yaml only when a smaller check is confirmed. Mobster never edits your check or its approved path. It exits 0 when it finished, even with no smaller check, 3 on bad input or an unknown outcome, and 130 when you stop it.