mobster test pr runs the checks a branch needs, not the whole suite, and writes the pull request comment. CI posts it on every pull request.
Test the checks a branch needs
- It reads
git difffrom where the branch leftorigin/main(--basepicks another), uncommitted work included. - Each changed Swift view becomes a screen: its name (
PaywallViewispaywall), and the accessibility identifiers, strings and deep links on the changed lines. Storyboards,.stringsand.xcstringsfiles count too. - It picks every saved check that names a changed id or string, mentions a changed string in a step, carries the screen as a tag or file name, or was itself changed. When it picks none, the kind of each changed file decides (below).
- It builds the app with
xcodebuildinto.mobster/build, for the simulator, or for the iPhone with--device, and points the picked checks at the new build.--schemeand--projectchoose what to build, and--no-buildskips it. - For each changed screen that no check covers, it writes a draft to
.mobster/drafts/pr/<screen>.yamlfrom the screen’s new ids and strings, at most 3. A draft runs beside the checks and never fails the pull request. Move a good one into.mobster/checks/to keep it.
mobster test’s, counted without the drafts. A build that fails exits 3, and the comment quotes its first errors. Mobster builds one project at a time: while another Mobster build writes .mobster/build, such as your coding agent’s in another session, the build stops at once with Another Mobster build is writing (next release) and exits 3.
Know which files change the app
When no check names what changed, app and unknown files run every check, each with the reason “an app file changed and no check names it”. A diff over 400 files does too. Tests, config and docs on their own run the checks taggedsmoke.
Mobster asks your Xcode project first:
- A file or folder that an app, extension or framework target builds is app code, even when a test target builds it too.
- A file or folder that only test targets build is a test.
- A path in a target’s
DEVELOPMENT_ASSET_PATHS, such asPreview Content, is a test, unless a target builds that path itself. - So a feature folder named
LabTestsis app code, and aFirefoxTeststarget is a test. - Mobster reads every
project.pbxprojin the repository, including one git ignores, as XcodeGen and Tuist write them, for at most 5 seconds. A project it couldn’t read in time adds nothing.
- Config: a file in a
.github,.vscode,.cursor,.claude,.codex,.gemini,.zed,.agents,.windsurf,.amp,.omp,.mobster,.changesetor.huskyfolder, at any depth. The files.gitignore,.gitattributes,.editorconfig,.mcp.jsonandopencode.jsonare config too. Any other hidden folder, such as.yarn, is unknown. - Test, in a SwiftPM package: a file in the
Testsfolder beside itsPackage.swift. The rest of a package is unknown. - Test, outside a package: a file in a
Tests,UITests,TestorPreview Contentfolder, or a file whose name ends inTests, such asCheckoutTests.swift. - Docs: a README, CHANGELOG, CONTRIBUTING, CODE_OF_CONDUCT, LICENSE or COPYING file, anywhere. A Markdown, text or reStructuredText file at the top level. A file in a
docsorDocumentationfolder that isn’t code. - Unknown: anything else, such as a Podfile, an
Info.plistor a package’s sources.
pr.json lists each changed file’s kind under changes.kinds. Of the new files git doesn’t track yet, only screens, strings files and checks in .mobster/checks/ count.
Read the comment and its files
The suite folder gets the usual reports, plus:
For a repeated check, the repro steps, deep link and GIF come from the attempt that decided its verdict. The comment ends without a credit line.
mobster test pr --tested-with ends it with “Tested with Mobster”, linked to mobster.dev.
To post the comment when a pull request or merge request opens or changes, run mobster ci on your own Mac (CI). In GitHub Actions, mobster ci comment also posts the verdict as the check Mobster (next release), with the job’s token. When you run mobster test pr yourself, Mobster Checks posts the same check.
Test on your iPhone
mobster test pr --device "Test iPhone" builds for the phone and installs that build. With --testflight com.example.yourapp it skips the build and tests the TestFlight build already on the phone.
With two or more devices, --spread runs each picked check once, on whichever device is free (Spread checks across phones). With fewer than two, or with --repeat, it stops before the build.
Test every pull request on this Mac
You get this in the next release, not in Mobster for Mac 0.4.0 or Mobster CLI 0.4.3.
mobster test pr --watch tests each pull request in your clone when someone opens it or pushes to it. You need no workflow file, no runner and no CI minutes:
- The watcher runs
git ls-remote originevery 30 seconds with the credential you already use to fetch.--intervalsets 10 to 3,600 seconds. It needs no token: only Mobster Checks, when you install it, calls GitHub’s API to post. - It tests a pull request by itself when its head is also the head of a branch in the repository: someone who can push there pushed it. That includes branches bots such as Dependabot push, and their builds run third-party install scripts.
- It waits before it tests a head from a fork, because its build scripts would run on your Mac. Read the changes at that head, then restart the watcher with
mobster test pr --watch --allow N. It tests the head that was waiting when it started, and a later push waits again. - It gives each pull request its own worktree in
~/Library/Caches/Mobster/watch/<id>/<number>, where<id>is 12 hex digits from your clone’s git folder (MOBSTER_CACHE_DIRmoves~/Library/Caches/Mobster). One watcher at a time watches a repository. - A worktree holds only the files your repository tracks, and the watcher installs nothing. An Expo or React Native app without committed
node_modules, or a project with aPodfileand no committedPods, is skipped with one line. Native projects with Swift packages run. Unless you pass--base, it uses the basemobster test prpicks:origin/main, thenorigin/master,mainandmaster. - Each worktree keeps its own replay recordings and history, so a check with steps runs with a model on its first run there. You can’t use
--comment,--jsonor--sharewith--watch, and the project’s Slack rule doesn’t run for watched pull requests. - On its first pass, it records the heads it finds and tests none. It tests 1 pull request at a time, and prints 1 line for each: the pull request, its verdict, the seconds from the listing that showed its head to the result, and the suite folder. With Mobster Checks installed, the verdict goes on the pull request as the check
Mobster, and--github commentadds the comment. - Press
ctrl+cto stop it. When you restart it, it tests only the heads that changed since.
mobster serve run this watcher by themselves for your own open pull requests, in each of your projects that has saved checks and whose origin is a GitHub repository with Mobster Checks installed. Their watcher tests only pull requests opened by the GitHub account you connected, and anyone else’s waits as a fork’s does. While Mobster watches a repository, mobster test pr --watch in that clone says another watcher holds it. To turn that watcher off for a project, send {"on": false} to POST /api/projects/{id}/pull-watch.